diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/AUTHORS ns-3.40/AUTHORS
--- ns-3.39/AUTHORS	2023-07-05 14:23:47.577426400 -0700
+++ ns-3.40/AUTHORS	2023-09-27 13:30:37.522838800 -0700
@@ -164,6 +164,7 @@
 Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca)
 Harsh Lara (harshapplefan@gmail.com)
 Mattia Lecci (mattia.lecci@gmail.com)
+Ben Lee (limjcst@163.com)
 Robin Lee (xinyashuai1987@163.com)
 Juan Leon (juanvleonr@gmail.com)
 Kristijan Lenković (k.lenkovic@me.com)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/build-support/custom-modules/ns3-cmake-package.cmake ns-3.40/build-support/custom-modules/ns3-cmake-package.cmake
--- ns-3.39/build-support/custom-modules/ns3-cmake-package.cmake	2023-07-05 14:23:47.585426600 -0700
+++ ns-3.40/build-support/custom-modules/ns3-cmake-package.cmake	2023-09-27 13:30:37.530838700 -0700
@@ -29,7 +29,7 @@
       )
       set(lib_real_name "-l${lib_real_name}")
     else()
-      if(IS_ABSOLUTE ${lib})
+      if((IS_ABSOLUTE "${lib}") OR ("${lib}" MATCHES "^-l"))
         set(lib_real_name ${lib})
       else()
         set(lib_real_name "-l${lib}")
@@ -88,6 +88,9 @@
     string(REPLACE ";-I" " -I" pkgconfig_interface_include_directories
                    "${pkgconfig_interface_include_directories}"
     )
+    string(REPLACE ";" "" pkgconfig_interface_include_directories
+                   "${pkgconfig_interface_include_directories}"
+    )
   endif()
 
   # Configure pkgconfig file for the module using pkgconfig variables
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/build-support/custom-modules/ns3-configtable.cmake ns-3.40/build-support/custom-modules/ns3-configtable.cmake
--- ns-3.39/build-support/custom-modules/ns3-configtable.cmake	2023-07-05 14:23:47.585426600 -0700
+++ ns-3.40/build-support/custom-modules/ns3-configtable.cmake	2023-09-27 13:30:37.530838700 -0700
@@ -54,12 +54,20 @@
 
 # Now the CMake part
 
+set(ON ON)
 macro(check_on_or_off user_config_switch confirmation_flag)
-  if(${user_config_switch})
-    if(${confirmation_flag})
+  # Argument parsing
+  if(${${user_config_switch}})
+    if(${${confirmation_flag}})
       string(APPEND out "${Green}ON${ColourReset}\n")
     else()
-      string(APPEND out "${Red}OFF (missing dependency)${ColourReset}\n")
+      if(${confirmation_flag}_REASON)
+        string(APPEND out
+               "${Red}OFF (${${confirmation_flag}_REASON})${ColourReset}\n"
+        )
+      else()
+        string(APPEND out "${Red}OFF (missing dependency)${ColourReset}\n")
+      endif()
     endif()
   else()
     string(APPEND out "OFF (not requested)\n")
@@ -120,73 +128,73 @@
   )
 
   string(APPEND out "Build with runtime asserts    : ")
-  check_on_or_off("${NS3_ASSERT}" "${NS3_ASSERT}")
+  check_on_or_off("NS3_ASSERT" "NS3_ASSERT")
 
   string(APPEND out "Build with runtime logging    : ")
-  check_on_or_off("${NS3_LOG}" "${NS3_LOG}")
+  check_on_or_off("NS3_LOG" "NS3_LOG")
 
   string(APPEND out "Build version embedding       : ")
-  check_on_or_off("${NS3_ENABLE_BUILD_VERSION}" "${ENABLE_BUILD_VERSION}")
+  check_on_or_off("NS3_ENABLE_BUILD_VERSION" "ENABLE_BUILD_VERSION")
 
   string(APPEND out "BRITE Integration             : ")
-  check_on_or_off("ON" "${NS3_BRITE}")
+  check_on_or_off("ON" "NS3_BRITE")
 
   string(APPEND out "DES Metrics event collection  : ")
-  check_on_or_off("${NS3_DES_METRICS}" "${NS3_DES_METRICS}")
+  check_on_or_off("NS3_DES_METRICS" "NS3_DES_METRICS")
 
   string(APPEND out "DPDK NetDevice                : ")
-  check_on_or_off("${NS3_DPDK}" "${ENABLE_DPDKDEVNET}")
+  check_on_or_off("NS3_DPDK" "ENABLE_DPDKDEVNET")
 
   string(APPEND out "Emulation FdNetDevice         : ")
-  check_on_or_off("${ENABLE_EMU}" "${ENABLE_EMUNETDEV}")
+  check_on_or_off("ENABLE_EMU" "ENABLE_EMUNETDEV")
 
   string(APPEND out "Examples                      : ")
-  check_on_or_off("${ENABLE_EXAMPLES}" "${ENABLE_EXAMPLES}")
+  check_on_or_off("ENABLE_EXAMPLES" "ENABLE_EXAMPLES")
 
   string(APPEND out "File descriptor NetDevice     : ")
-  check_on_or_off("ON" "${ENABLE_FDNETDEV}")
+  check_on_or_off("ON" "ENABLE_FDNETDEV")
 
   string(APPEND out "GNU Scientific Library (GSL)  : ")
-  check_on_or_off("${NS3_GSL}" "${GSL_FOUND}")
+  check_on_or_off("NS3_GSL" "GSL_FOUND")
 
   string(APPEND out "GtkConfigStore                : ")
-  check_on_or_off("${NS3_GTK3}" "${GTK3_FOUND}")
+  check_on_or_off("NS3_GTK3" "GTK3_FOUND")
 
   string(APPEND out "LibXml2 support               : ")
-  check_on_or_off("ON" "${LIBXML2_FOUND}")
+  check_on_or_off("ON" "LIBXML2_FOUND")
 
   string(APPEND out "MPI Support                   : ")
-  check_on_or_off("${NS3_MPI}" "${MPI_FOUND}")
+  check_on_or_off("NS3_MPI" "MPI_FOUND")
 
   string(APPEND out "ns-3 Click Integration        : ")
-  check_on_or_off("ON" "${NS3_CLICK}")
+  check_on_or_off("ON" "NS3_CLICK")
 
   string(APPEND out "ns-3 OpenFlow Integration     : ")
-  check_on_or_off("ON" "${NS3_OPENFLOW}")
+  check_on_or_off("ON" "NS3_OPENFLOW")
 
   string(APPEND out "Netmap emulation FdNetDevice  : ")
-  check_on_or_off("${ENABLE_EMU}" "${ENABLE_NETMAP_EMU}")
+  check_on_or_off("ENABLE_EMU" "ENABLE_NETMAP_EMU")
 
   string(APPEND out "PyViz visualizer              : ")
-  check_on_or_off("${NS3_VISUALIZER}" "${ENABLE_VISUALIZER}")
+  check_on_or_off("NS3_VISUALIZER" "ENABLE_VISUALIZER")
 
   string(APPEND out "Python Bindings               : ")
-  check_on_or_off("${NS3_PYTHON_BINDINGS}" "${ENABLE_PYTHON_BINDINGS}")
+  check_on_or_off("NS3_PYTHON_BINDINGS" "ENABLE_PYTHON_BINDINGS")
 
   string(APPEND out "SQLite support                : ")
-  check_on_or_off("${NS3_SQLITE}" "${ENABLE_SQLITE}")
+  check_on_or_off("NS3_SQLITE" "ENABLE_SQLITE")
 
   string(APPEND out "Eigen3 support                : ")
-  check_on_or_off("${NS3_EIGEN}" "${ENABLE_EIGEN}")
+  check_on_or_off("NS3_EIGEN" "ENABLE_EIGEN")
 
   string(APPEND out "Tap Bridge                    : ")
-  check_on_or_off("${ENABLE_TAP}" "${ENABLE_TAP}")
+  check_on_or_off("ENABLE_TAP" "ENABLE_TAP")
 
   string(APPEND out "Tap FdNetDevice               : ")
-  check_on_or_off("${ENABLE_TAP}" "${ENABLE_TAPNETDEV}")
+  check_on_or_off("ENABLE_TAP" "ENABLE_TAPNETDEV")
 
   string(APPEND out "Tests                         : ")
-  check_on_or_off("${ENABLE_TESTS}" "${ENABLE_TESTS}")
+  check_on_or_off("ENABLE_TESTS" "ENABLE_TESTS")
 
   # string(APPEND out "Use sudo to set suid bit      : not enabled (option
   # --enable-sudo not selected) string(APPEND out "XmlIo : enabled
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/build-support/custom-modules/ns3-module-macros.cmake ns-3.40/build-support/custom-modules/ns3-module-macros.cmake
--- ns-3.39/build-support/custom-modules/ns3-module-macros.cmake	2023-07-05 14:23:47.589426500 -0700
+++ ns-3.40/build-support/custom-modules/ns3-module-macros.cmake	2023-09-27 13:30:37.530838700 -0700
@@ -191,9 +191,29 @@
     # include directories, allowing consumers of this module to include and link
     # the 3rd-party code with no additional setup
     get_target_includes(${lib${BLIB_LIBNAME}} exported_include_directories)
+
     string(REPLACE "-I" "" exported_include_directories
                    "${exported_include_directories}"
     )
+
+    # include directories prefixed in the source or binary directory need to be
+    # treated differently
+    set(new_exported_include_directories)
+    foreach(directory ${exported_include_directories})
+      string(FIND "${directory}" "${PROJECT_SOURCE_DIR}" is_prefixed_in_subdir)
+      if(${is_prefixed_in_subdir} GREATER_EQUAL 0)
+        string(SUBSTRING "${directory}" ${is_prefixed_in_subdir} -1
+                         directory_path
+        )
+        list(APPEND new_exported_include_directories
+             $<BUILD_INTERFACE:${directory_path}>
+        )
+      else()
+        list(APPEND new_exported_include_directories ${directory})
+      endif()
+    endforeach()
+    set(exported_include_directories ${new_exported_include_directories})
+
     string(REPLACE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include" ""
                    exported_include_directories
                    "${exported_include_directories}"
@@ -235,6 +255,23 @@
     INTERFACE ${exported_include_directories}
   )
 
+  # Export definitions as interface definitions, propagating local definitions
+  # to other modules and scratches
+  get_target_property(
+    target_definitions ${lib${BLIB_LIBNAME}} COMPILE_DEFINITIONS
+  )
+  if(${target_definitions} STREQUAL "target_definitions-NOTFOUND")
+    set(target_definitions)
+  endif()
+  get_directory_property(dir_definitions COMPILE_DEFINITIONS)
+  set(exported_definitions "${target_definitions};${dir_definitions}")
+  list(REMOVE_DUPLICATES exported_definitions)
+  list(REMOVE_ITEM exported_definitions "")
+  set_target_properties(
+    ${lib${BLIB_LIBNAME}} PROPERTIES INTERFACE_COMPILE_DEFINITIONS
+                                     "${exported_definitions}"
+  )
+
   set(ns3-external-libs "${non_ns_libraries_to_link};${ns3-external-libs}"
       CACHE INTERNAL
             "list of non-ns libraries to link to NS3_STATIC and NS3_MONOLIB"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/build-support/custom-modules/ns3-vcpkg-hunter.cmake ns-3.40/build-support/custom-modules/ns3-vcpkg-hunter.cmake
--- ns-3.39/build-support/custom-modules/ns3-vcpkg-hunter.cmake	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/build-support/custom-modules/ns3-vcpkg-hunter.cmake	2023-09-27 13:30:37.530838700 -0700
@@ -0,0 +1,198 @@
+# Copyright (c) 2017-2023 Universidade de Brasília
+#
+# 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: Gabriel Ferreira <gabrielcarvfer@gmail.com>
+
+# Set default installation directory
+set(VCPKG_DIR "${PROJECT_SOURCE_DIR}/vcpkg")
+
+# Check if there is an existing vcpkg installation in the user directory
+if(WIN32)
+  set(user_dir $ENV{USERPROFILE})
+else()
+  set(user_dir $ENV{HOME})
+endif()
+
+# Override the default vcpkg installation directory in case it does
+if(EXISTS "${user_dir}/vcpkg")
+  set(VCPKG_DIR "${user_dir}/vcpkg")
+endif()
+
+find_package(Git)
+
+if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
+  set(VCPKG_TARGET_ARCH x64)
+else()
+  set(VCPKG_TARGET_ARCH x86)
+endif()
+
+if(WIN32)
+  set(VCPKG_EXEC vcpkg.exe)
+  set(VCPKG_TRIPLET ${VCPKG_TARGET_ARCH}-windows)
+else()
+  set(VCPKG_EXEC vcpkg)
+  if(NOT APPLE) # LINUX
+    set(VCPKG_TRIPLET ${VCPKG_TARGET_ARCH}-linux)
+  else()
+    set(VCPKG_TRIPLET ${VCPKG_TARGET_ARCH}-osx)
+  endif()
+endif()
+
+# https://learn.microsoft.com/en-us/vcpkg/users/buildsystems/cmake-integration
+set(VCPKG_TARGET_TRIPLET ${VCPKG_TRIPLET})
+set(VCPKG_MANIFEST ${PROJECT_SOURCE_DIR}/vcpkg.json)
+
+function(setup_vcpkg)
+  message(STATUS "vcpkg: setting up support in ${VCPKG_DIR}")
+
+  # Check if vcpkg was downloaded previously
+  if(EXISTS "${VCPKG_DIR}")
+    # Vcpkg already downloaded
+    message(STATUS "vcpkg: folder already exists, skipping git download")
+  else()
+    if(NOT ${Git_FOUND})
+      message(FATAL_ERROR "vcpkg: Git is required, but it was not found")
+    endif()
+    get_filename_component(VCPKG_PARENT_DIR ${VCPKG_DIR} DIRECTORY)
+    execute_process(
+      COMMAND ${GIT_EXECUTABLE} clone --depth 1
+              https://github.com/microsoft/vcpkg.git
+      WORKING_DIRECTORY "${VCPKG_PARENT_DIR}/"
+    )
+  endif()
+
+  if(${MSVC})
+    message(FATAL_ERROR "vcpkg: Visual Studio is unsupported")
+  else()
+    # Check if required packages are installed (unzip curl tar)
+    if(WIN32)
+      find_program(ZIP_PRESENT zip.exe)
+      find_program(UNZIP_PRESENT unzip.exe)
+      find_program(CURL_PRESENT curl.exe)
+      find_program(TAR_PRESENT tar.exe)
+    else()
+      find_program(ZIP_PRESENT zip)
+      find_program(UNZIP_PRESENT unzip)
+      find_program(CURL_PRESENT curl)
+      find_program(TAR_PRESENT tar)
+    endif()
+
+    if(${ZIP_PRESENT} STREQUAL ZIP_PRESENT-NOTFOUND)
+      message(FATAL_ERROR "vcpkg: Zip is required, but is not installed")
+    endif()
+
+    if(${UNZIP_PRESENT} STREQUAL UNZIP_PRESENT-NOTFOUND)
+      message(FATAL_ERROR "vcpkg: Unzip is required, but is not installed")
+    endif()
+
+    if(${CURL_PRESENT} STREQUAL CURL_PRESENT-NOTFOUND)
+      message(FATAL_ERROR "vcpkg: Curl is required, but is not installed")
+    endif()
+
+    if(${TAR_PRESENT} STREQUAL TAR_PRESENT-NOTFOUND)
+      message(FATAL_ERROR "vcpkg: Tar is required, but is not installed")
+    endif()
+  endif()
+
+  # message(WARNING "Checking VCPKG bootstrapping") Check if vcpkg was
+  # bootstrapped previously
+  if(EXISTS "${VCPKG_DIR}/${VCPKG_EXEC}")
+    message(STATUS "vcpkg: already bootstrapped")
+  else()
+    # message(WARNING "vcpkg: bootstrapping")
+    set(COMPILER_ENFORCING)
+
+    if(WIN32)
+      set(command bootstrap-vcpkg.bat -disableMetrics)
+    else()
+      # if(NOT APPLE) #linux/bsd
+      set(command bootstrap-vcpkg.sh -disableMetrics)
+      # else() set(command bootstrap-vcpkg.sh)# --allowAppleClang) endif()
+    endif()
+
+    execute_process(
+      COMMAND ${COMPILER_ENFORCING} ${VCPKG_DIR}/${command}
+      WORKING_DIRECTORY ${VCPKG_DIR}
+    )
+    # message(STATUS "vcpkg: bootstrapped") include_directories(${VCPKG_DIR})
+    set(ENV{VCPKG_ROOT} ${VCPKG_DIR})
+  endif()
+
+  if(NOT WIN32)
+    execute_process(COMMAND chmod +x ${VCPKG_DIR}/${VCPKG_EXEC})
+  endif()
+
+  set(CMAKE_PREFIX_PATH
+      "${VCPKG_DIR}/installed/${VCPKG_TRIPLET}/;${CMAKE_PREFIX_PATH}"
+      PARENT_SCOPE
+  )
+
+  # Install packages in manifest mode
+  if(EXISTS ${VCPKG_MANIFEST})
+    message(STATUS "vcpkg: detected a vcpkg manifest file: ${VCPKG_MANIFEST}")
+    execute_process(
+      COMMAND ${VCPKG_DIR}/${VCPKG_EXEC} install --triplet ${VCPKG_TRIPLET}
+              --x-install-root=${VCPKG_DIR}/installed RESULT_VARIABLE res
+    )
+    if(${res} EQUAL 0)
+      message(STATUS "vcpkg: packages defined in the manifest were installed")
+    else()
+      message(
+        FATAL_ERROR
+          "vcpkg: packages defined in the manifest failed to be installed"
+      )
+    endif()
+  endif()
+endfunction()
+
+function(add_package package_name)
+  # Early exit in case vcpkg support is not enabled
+  if(NOT ${NS3_VCPKG})
+    message(${HIGHLIGHTED_STATUS}
+            "vcpkg: support is disabled. Not installing: ${package_name}"
+    )
+    return()
+  endif()
+
+  # Early exit in case a vcpkg.json manifest file is present
+  if(EXISTS ${VCPKG_MANIFEST})
+    file(READ ${VCPKG_MANIFEST} contents)
+    if(${contents} MATCHES ${package_name})
+      message(STATUS "vcpkg: ${package_name} was installed")
+      return()
+    else()
+      message(
+        FATAL_ERROR
+          "vcpkg: manifest mode in use, but ${package_name} is not listed in ${VCPKG_MANIFEST}"
+      )
+    endif()
+  endif()
+
+  # Normal exit
+  message(STATUS "vcpkg: ${package_name} will be installed")
+  execute_process(
+    COMMAND ${VCPKG_DIR}/${VCPKG_EXEC} install ${package_name} --triplet
+            ${VCPKG_TRIPLET} RESULT_VARIABLE res
+  )
+  if(${res} EQUAL 0)
+    message(STATUS "vcpkg: ${package_name} was installed")
+  else()
+    message(FATAL_ERROR "vcpkg: ${package_name} failed to be installed")
+  endif()
+endfunction()
+
+if(${NS3_VCPKG})
+  setup_vcpkg()
+endif()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/build-support/macros-and-definitions.cmake ns-3.40/build-support/macros-and-definitions.cmake
--- ns-3.39/build-support/macros-and-definitions.cmake	2023-07-05 14:23:47.589426500 -0700
+++ ns-3.40/build-support/macros-and-definitions.cmake	2023-09-27 13:30:37.530838700 -0700
@@ -150,6 +150,7 @@
 set(THIRD_PARTY_DIRECTORY ${PROJECT_SOURCE_DIR}/3rd-party)
 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 link_directories(${CMAKE_OUTPUT_DIRECTORY}/lib)
+file(MAKE_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY})
 
 # Get installation folder default values for each platform and include package
 # configuration macro
@@ -664,23 +665,6 @@
     endif()
   endif()
 
-  set(ENABLE_SQLITE False)
-  if(${NS3_SQLITE})
-    # find_package(SQLite3 QUIET) # unsupported in CMake 3.10 We emulate the
-    # behavior of find_package below
-    find_external_library(
-      DEPENDENCY_NAME SQLite3 HEADER_NAME sqlite3.h LIBRARY_NAME sqlite3
-    )
-
-    if(${SQLite3_FOUND})
-      set(ENABLE_SQLITE True)
-      add_definitions(-DHAVE_SQLITE3)
-      include_directories(${SQLite3_INCLUDE_DIRS})
-    else()
-      message(${HIGHLIGHTED_STATUS} "SQLite was not found")
-    endif()
-  endif()
-
   if(${NS3_NATIVE_OPTIMIZATIONS} AND ${GCC})
     add_compile_options(-march=native -mtune=native)
   endif()
@@ -751,6 +735,68 @@
   )
   list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/build-support/3rd-party")
 
+  # Include our package managers
+  # cmake-format: off
+  # Starting with a custom cmake file that provides a Hunter-like interface to vcpkg
+  # Use add_package(package) to install a package
+  # Then find_package(package) to use it
+  # cmake-format: on
+  include(ns3-vcpkg-hunter)
+
+  # Then the beautiful CPM manager (too bad it doesn't work with everything)
+  # https://github.com/cpm-cmake/CPM.cmake
+  if(${NS3_CPM})
+    set(CPM_DOWNLOAD_VERSION 0.38.2)
+    set(CPM_DOWNLOAD_LOCATION
+        "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake"
+    )
+    if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
+      message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
+      file(
+        DOWNLOAD
+        https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
+        ${CPM_DOWNLOAD_LOCATION}
+      )
+    endif()
+    include(${CPM_DOWNLOAD_LOCATION})
+    set(CPM_USE_LOCAL_PACKAGES ON)
+  endif()
+  # Package manager test block
+  if(TEST_PACKAGE_MANAGER)
+    if(${TEST_PACKAGE_MANAGER} STREQUAL "CPM")
+      cpmaddpackage(
+        NAME ARMADILLO GIT_TAG 6cada351248c9a967b137b9fcb3d160dad7c709b
+        GIT_REPOSITORY https://gitlab.com/conradsnicta/armadillo-code.git
+      )
+      find_package(ARMADILLO REQUIRED)
+      message(STATUS "Armadillo was found? ${ARMADILLO_FOUND}")
+    elseif(${TEST_PACKAGE_MANAGER} STREQUAL "VCPKG")
+      add_package(Armadillo)
+      find_package(Armadillo REQUIRED)
+      message(STATUS "Armadillo was found? ${ARMADILLO_FOUND}")
+    else()
+      find_package(Armadillo REQUIRED)
+    endif()
+  endif()
+  # End of package managers
+
+  set(ENABLE_SQLITE False)
+  if(${NS3_SQLITE})
+    # find_package(SQLite3 QUIET) # unsupported in CMake 3.10 We emulate the
+    # behavior of find_package below
+    find_external_library(
+      DEPENDENCY_NAME SQLite3 HEADER_NAME sqlite3.h LIBRARY_NAME sqlite3
+    )
+
+    if(${SQLite3_FOUND})
+      set(ENABLE_SQLITE True)
+      add_definitions(-DHAVE_SQLITE3)
+      include_directories(${SQLite3_INCLUDE_DIRS})
+    else()
+      message(${HIGHLIGHTED_STATUS} "SQLite was not found")
+    endif()
+  endif()
+
   set(ENABLE_EIGEN False)
   if(${NS3_EIGEN})
     find_package(Eigen3 QUIET)
@@ -889,6 +935,7 @@
       message(${HIGHLIGHTED_STATUS}
               "Python: development libraries were not found"
       )
+      set(ENABLE_PYTHON_BINDINGS_REASON "missing Python development libraries")
     endif()
   else()
     if(${NS3_PYTHON_BINDINGS})
@@ -896,6 +943,7 @@
         ${HIGHLIGHTED_STATUS}
         "Python: an incompatible version of Python was found, python bindings will be disabled"
       )
+      set(ENABLE_PYTHON_BINDINGS_REASON "incompatible Python version")
     endif()
   endif()
 
@@ -906,6 +954,15 @@
         ${HIGHLIGHTED_STATUS}
         "Bindings: python bindings require Python, but it could not be found"
       )
+      set(ENABLE_PYTHON_BINDINGS_REASON "missing dependency: python")
+    elseif(APPLE AND "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "arm64")
+      # Warn users that Cppyy on ARM Macs isn't supported yet
+      message(${HIGHLIGHTED_STATUS}
+              "Bindings: macOS silicon detected -- see issue 930"
+      )
+      set(ENABLE_PYTHON_BINDINGS_REASON
+          "macOS silicon detected -- see issue 930"
+      )
     else()
       check_python_packages("cppyy" missing_packages)
       if(missing_packages)
@@ -913,6 +970,9 @@
           ${HIGHLIGHTED_STATUS}
           "Bindings: python bindings disabled due to the following missing dependencies: ${missing_packages}"
         )
+        set(ENABLE_PYTHON_BINDINGS_REASON
+            "missing dependency: ${missing_packages}"
+        )
       else()
         set(ENABLE_PYTHON_BINDINGS ON)
       endif()
@@ -999,10 +1059,21 @@
 
   set(ENABLE_VISUALIZER FALSE)
   if(${NS3_VISUALIZER})
-    if((NOT ${ENABLE_PYTHON_BINDINGS}) OR (NOT ${Python3_FOUND}))
-      message(${HIGHLIGHTED_STATUS} "Visualizer requires Python bindings")
+    # If bindings are enabled, check if visualizer dependencies are met
+    if(${NS3_PYTHON_BINDINGS})
+      if(NOT ${Python3_FOUND})
+        set(ENABLE_VISUALIZER_REASON "missing Python")
+      elseif(NOT ${ENABLE_PYTHON_BINDINGS})
+        set(ENABLE_VISUALIZER_REASON "missing Python Bindings")
+      else()
+        set(ENABLE_VISUALIZER TRUE)
+      endif()
+      # If bindings are disabled, just say python bindings are disabled
     else()
-      set(ENABLE_VISUALIZER TRUE)
+      set(ENABLE_VISUALIZER_REASON "Python Bindings are disabled")
+    endif()
+    if(ENABLE_VISUALIZER_REASON)
+      message(${HIGHLIGHTED_STATUS} "Visualizer: ${ENABLE_VISUALIZER_REASON}")
     endif()
   endif()
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/build-support/test-files/test-package-managers/CMakeLists.txt ns-3.40/build-support/test-files/test-package-managers/CMakeLists.txt
--- ns-3.39/build-support/test-files/test-package-managers/CMakeLists.txt	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/build-support/test-files/test-package-managers/CMakeLists.txt	2023-09-27 13:30:37.530838700 -0700
@@ -0,0 +1,42 @@
+if(NOT
+   TEST_PACKAGE_MANAGER
+)
+  message(
+    STATUS "Skipping test module because TEST_PACKAGE_MANAGER is not set."
+  )
+  return()
+endif()
+
+set(armadillo)
+if(${TEST_PACKAGE_MANAGER}
+   STREQUAL
+   "CPM"
+)
+  set(armadillo
+      armadillo
+  )
+  include_directories(${CMAKE_BINARY_DIR}/_deps/armadillo-src/include)
+elseif(
+  ${TEST_PACKAGE_MANAGER}
+  STREQUAL
+  "VCPKG"
+)
+  set(armadillo
+      ${ARMADILLO_LIBRARIES}
+  )
+  include_directories(${ARMADILLO_INCLUDE_DIRS})
+else()
+  message(FATAL_ERROR "zoincs")
+  message(
+    STATUS
+      "Skipping test module because TEST_PACKAGE_MANAGER is set to an unsupported value."
+  )
+  return()
+endif()
+
+build_lib(
+  LIBNAME test-package-managers
+  SOURCE_FILES src.cc
+  LIBRARIES_TO_LINK ${libcore}
+                    ${armadillo}
+)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/build-support/test-files/test-package-managers/src.cc ns-3.40/build-support/test-files/test-package-managers/src.cc
--- ns-3.39/build-support/test-files/test-package-managers/src.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/build-support/test-files/test-package-managers/src.cc	2023-09-27 13:30:37.530838700 -0700
@@ -0,0 +1,10 @@
+#include <armadillo>
+
+int
+main(int argc, char** argv)
+{
+    arma::arma_rng::set_seed_random();
+    arma::Mat<double> mat = arma::randu(4, 4);
+    std::cout << "mat:\n" << mat << "\n";
+    return 0;
+}
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/CHANGES.md ns-3.40/CHANGES.md
--- ns-3.39/CHANGES.md	2023-07-05 14:23:47.581426600 -0700
+++ ns-3.40/CHANGES.md	2023-09-27 13:30:37.526838800 -0700
@@ -13,6 +13,36 @@
 
 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.39 to ns-3.40
+-------------------------------
+
+### New API
+
+* (energy) Added `GenericBatteryModel` to the energy module with working examples, and support for battery presets and cell packs.
+* (lr-wpan) Added the functions to set or get the capability field via bitmap (a 8 bit int).
+* (lr-wpan) Added the possibility to obtain the LQI from a received `MlmeAssociateIndicationParams`.
+* (wifi) Added new helper methods to SpectrumWifiPhyHelper to allow flexible configuration for the mapping between spectrum PHY interfaces and PHY instances.
+* (wifi) Added new trace sources to `WifiPhy`: **OperatingChannelChange**, which is fired when the operating channel of a PHY is changed.
+* (wifi) The attribute `WifiPhy::Antennas` is extended to support up to 8 antennas.
+
+### Changes to existing API
+
+* (core) Removed private class `EmpiricalRandomVariable::ValueCDF` in favor of `std::map`.
+* (lr-wpan) Removed unnecessary bcst filter from `LrWpanMac::PdDataIndication` which also blocked the correct reception of beacon request commands.
+* (wifi) The attribute `WifiPhy::Antennas` is extended to support up to 8 antennas.
+* (wifi) `StaWifiMac::MacState` enum is now public, and `WifiMacHeader` can be subclassed
+
+### Changes to build system
+
+* Added support for Vcpkg and CPM package managers
+
+### Changed behavior
+
+* (core) `EmpiricalRandomVariable` CDF pairs can now be added in any order.
+* (core) `EmpiricalRandomVariable` no longer requires that a CDF pair with a range value exactly equal to 1.0 be added (see issue #922).
+* (wifi) Upon ML setup, a non-AP MLD updates the IDs of the setup links to match the IDs used by the AP MLD.
+* (wifi) Attribute **TrackSignalsFromInactiveInterfaces** in SpectrumWifiPhy has been defaulted to be enabled.
+
 Changes from ns-3.38 to ns-3.39
 -------------------------------
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/.clang-tidy ns-3.40/.clang-tidy
--- ns-3.39/.clang-tidy	2023-07-05 14:23:47.577426400 -0700
+++ ns-3.40/.clang-tidy	2023-09-27 13:30:37.522838800 -0700
@@ -18,10 +18,14 @@
   modernize-make-shared,
   modernize-make-unique,
   modernize-redundant-void-arg,
+  modernize-type-traits,
+  modernize-use-auto,
+  modernize-use-bool-literals,
   modernize-use-emplace,
   modernize-use-equals-delete,
   modernize-use-nullptr,
   modernize-use-override,
+  modernize-use-transparent-functors,
   performance-faster-string-find,
   performance-for-range-copy,
   performance-implicit-conversion-in-loop,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/CMakeLists.txt ns-3.40/CMakeLists.txt
--- ns-3.39/CMakeLists.txt	2023-07-05 14:23:47.581426600 -0700
+++ ns-3.40/CMakeLists.txt	2023-09-27 13:30:37.526838800 -0700
@@ -55,6 +55,7 @@
 # other options
 option(NS3_ENABLE_BUILD_VERSION "Embed version info into libraries" OFF)
 option(NS3_CCACHE "Use Ccache to speed up recompilation" ON)
+option(NS3_CPM "Enable the CPM C++ library manager support" OFF)
 option(NS3_FAST_LINKERS "Use Mold or LLD to speed up linking if available" ON)
 option(NS3_FETCH_OPTIONAL_COMPONENTS
        "Fetch Brite, Click and Openflow dependencies" OFF
@@ -82,6 +83,7 @@
 option(NS3_STATIC "Build a static ns-3 library and link it against executables"
        OFF
 )
+option(NS3_VCPKG "Enable the Vcpkg C++ library manager support" OFF)
 option(NS3_VERBOSE "Print additional build system messages" OFF)
 option(NS3_VISUALIZER "Build visualizer module" ON)
 option(NS3_WARNINGS "Enable compiler warnings" ON)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/contributing/pickle-to-xml.py ns-3.40/doc/contributing/pickle-to-xml.py
--- ns-3.39/doc/contributing/pickle-to-xml.py	2023-07-05 14:23:47.589426500 -0700
+++ ns-3.40/doc/contributing/pickle-to-xml.py	2023-09-27 13:30:37.534838700 -0700
@@ -12,11 +12,11 @@
 import codecs
 
 def dump_pickles(out, dirname, filename, path):
-    f = open(os.path.join(dirname, filename), 'r')
-    data = pickle.load(f)
-    fragment_file = codecs.open(data['current_page_name'] + '.frag', mode='w', encoding='utf-8')
-    fragment_file.write(data['body'])
-    fragment_file.close()
+    with open(os.path.join(dirname, filename), 'r', encoding='utf-8') as f:
+        data = pickle.load(f)
+    with codecs.open(data['current_page_name'] + '.frag', mode='w', encoding='utf-8') as fragment_file:
+        fragment_file.write(data['body'])
+
     out.write('  <page url="%s">\n' % path)
     out.write('    <fragment>%s.frag</fragment>\n' % data['current_page_name'])
     if data['prev'] is not None:
@@ -28,12 +28,11 @@
                   (os.path.normpath(os.path.join(path, data['next']['link'])),
                    data['next']['title']))
     out.write('  </page>\n')
-    f.close()
+
     if data['next'] is not None:
         next_path = os.path.normpath(os.path.join(path, data['next']['link']))
         next_filename = os.path.basename(next_path) + '.fpickle'
         dump_pickles(out, dirname, next_filename, next_path)
-    return
 
 import sys
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/contributing/source/coding-style.rst ns-3.40/doc/contributing/source/coding-style.rst
--- ns-3.39/doc/contributing/source/coding-style.rst	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/contributing/source/coding-style.rst	2023-09-27 13:30:37.534838700 -0700
@@ -38,9 +38,9 @@
 The following list contains the set of clang-format versions that are verified
 to produce consistent output among themselves.
 
-* clang-format-14
-* clang-format-15
 * clang-format-16
+* clang-format-15
+* clang-format-14
 
 Integration with IDEs
 =====================
@@ -121,13 +121,14 @@
 as a Merge Request.
 
 The script has multiple modes of operation. By default, the script checks if
-source code files are well formatted and text files do not have trailing whitespace
+source code files are well formatted, if there are no #include headers from the same
+module with the "ns3/" prefix, and text files do not have trailing whitespace
 nor tabs. The process returns a zero exit code if all files adhere to these rules.
 If there are files that do not comply with the rules, the process returns a non-zero
 exit code and lists the respective files. This mode is useful for developers editing
 their code and for the GitLab CI/CD pipeline to check if the codebase is well formatted.
 All checks are enabled by default. Users can disable specific checks using the corresponding
-flags: ``--no-formatting``, ``--no-whitespace`` and ``--no-tabs``.
+flags: ``--no-include-prefixes``, ``--no-formatting``, ``--no-whitespace`` and ``--no-tabs``.
 
 Additional information about the formatting issues detected by the script can be enabled
 by adding the ``-v, --verbose`` flag.
@@ -151,17 +152,13 @@
 .. sourcecode:: console
 
   # Entire codebase (using paths relative to the ns-3 main directory)
-  ./utils/check-style-clang-format.py [--fix] [--verbose] [--no-formatting] [--no-whitespace] [--no-tabs] .
+  ./utils/check-style-clang-format.py --fix .
 
   # Entire codebase (using absolute paths)
-  /path/to/utils/check-style-clang-format.py [--fix] [--verbose] [--no-formatting] [--no-whitespace] [--no-tabs] /path/to/ns3
-
-  # Specific directory
-  /path/to/utils/check-style-clang-format.py [--fix] [--verbose] [--no-formatting] [--no-whitespace] [--no-tabs] absolute_or_relative/path/to/directory
-
-  # Individual file
-  /path/to/utils/check-style-clang-format.py [--fix] [--verbose] [--no-formatting] [--no-whitespace] [--no-tabs] absolute_or_relative/path/to/file
+  /path/to/utils/check-style-clang-format.py --fix /path/to/ns3
 
+  # Specific directory or file
+  /path/to/utils/check-style-clang-format.py --fix absolute_or_relative/path/to/directory_or_file
 
 Clang-tidy
 **********
@@ -799,6 +796,29 @@
   // Or as constexpr (in implementation files)
   constexpr uint8_t STATUS_PDU{0};
 
+When declaring variables that are easily deducible from context, prefer to declare them
+with ``auto`` instead of repeating the type name. Not only does this improve code readability,
+by making lines shorter, but it also facilitates future code refactoring.
+When declaring variables, prefer to use direct-initialization, to avoid repeating the type name.
+
+.. sourcecode:: cpp
+
+  // Avoid repeating the type name when declaring iterators or pointers, and casting variables
+  std::map<uint32_t, std::string>::const_iterator it = myMap.find(key);
+  int* ptr = new int[10];
+  uint8_t m = static_cast<uint8_t>(97 + (i % 26));
+
+  // Prefer to declare them with auto
+  auto it = myMap.find(key);
+  auto* ptr = new int[10];
+  auto m = static_cast<uint8_t>(97 + (i % 26));
+
+  // Avoid splitting the declaration and initialization of variables
+  Ipv4Address ipv4Address = Ipv4Address("192.168.0.1")
+
+  // Prefer to use direct-initialization
+  Ipv4Address ipv4Address("192.168.0.1")
+
 Comments
 ========
 
@@ -1200,6 +1220,125 @@
 
   NS_TEST...  (p, nullptr, ...)      NS_TEST...  (p, nullptr, ...)
 
+Code performance tips
+=====================
+
+While developing code, consider the following tips to improve the code's performance.
+Some tips are general recommendations, but are not strictly enforced.
+Other tips are enforced by clang-tidy. Please refer to the clang-tidy section below
+for more details.
+
+- Prefer to use ``.emplace_back()`` over ``.push_back()`` to optimize performance.
+
+- When initializing STL containers (e.g., ``std::vector``) with known size,
+  reserve memory to store all items, before pushing them in a loop.
+
+  .. sourcecode:: cpp
+
+    constexpr int N_ITEMS = 5;
+
+    std::vector<int> myVector;
+    myVector.reserve(N_ITEMS); // Reserve memory to store all items
+
+    for (int i = 0; i < N_ITEMS; i++)
+    {
+        myVector.emplace_back(i);
+    }
+
+- Prefer to initialize STL containers (e.g., ``std::vector``, ``std::map``, etc.)
+  directly through the constructor or with a braced-init-list, instead of pushing
+  elements one-by-one.
+
+  .. sourcecode:: cpp
+
+    // Prefer to initialize containers directly
+    std::vector<int> myVector1{1, 2, 3};
+    std::vector<int> myVector2(myVector1.begin(), myVector1.end());
+    std::vector<bool> myVector3(myVector2.size(), true);
+
+    // Avoid pushing elements one-by-one
+    std::vector<int> myVector1;
+    myVector1.reserve(3);
+    myVector1.emplace_back(1);
+    myVector1.emplace_back(2);
+    myVector1.emplace_back(3);
+
+    std::vector<int> myVector2;
+    myVector2.reserve(myVector1.size());
+    for (const auto& v : myVector1)
+    {
+        myVector2.emplace_back(v);
+    }
+
+    std::vector<bool> myVector3;
+    myVector3.reserve(myVector1.size());
+    for (std::size_t i = 0; i < myVector1.size(); i++)
+    {
+        myVector3.emplace_back(true);
+    }
+
+- When looping through containers, prefer to use const-ref syntax over copying
+  elements.
+
+  .. sourcecode:: cpp
+
+    std::vector<int> myVector{1, 2, 3};
+
+    for (const auto& v : myVector) { ... }  // OK
+    for (auto v : myVector) { ... }         // Avoid
+
+- Prefer to use the ``empty()`` function of STL containers (e.g., ``std::vector``),
+  instead of the condition ``size() > 0``, to avoid unnecessarily calculating the
+  size of the container.
+
+- Avoid unnecessary calls to the functions ``.c_str()`` and ``.data()`` of
+  ``std::string``.
+
+- Avoid unnecessarily dereferencing std smart pointers (``std::shared_ptr``,
+  ``std::unique_ptr``) with calls to their member function ``.get()``.
+  Prefer to use the std smart pointer directly where needed.
+
+  .. sourcecode:: cpp
+
+    auto ptr = std::make_shared<Node>();
+
+    // OK
+    if (ptr) { ... }
+
+    // Avoid
+    if (ptr.get()) { ... }
+
+- Consider caching frequently-used results (especially expensive calculations,
+  such as mathematical functions) in a temporary variable, instead of calculating
+  them in every loop.
+
+  .. sourcecode:: cpp
+
+    // Prefer to cache intermediate results
+    const double sinTheta = std::sin(theta);
+    const double cosTheta = std::cos(theta);
+
+    for (uint8_t i = 0; i < NUM_VALUES; i++)
+    {
+        double power = std::pow(2, i);
+
+        array1[i] = (power * sinTheta) + cosTheta;
+        array2[i] = (power * cosTheta) + sinTheta;
+    }
+
+    // Avoid repeating calculations
+    for (uint8_t i = 0; i < NUM_VALUES; i++)
+    {
+        array1[i] = (std::pow(2, i) * std::sin(theta)) + std::cos(theta);
+        array2[i] = (std::pow(2, i) * std::cos(theta)) + std::sin(theta);
+    }
+
+- Do not include inline implementations in header files; put all
+  implementation in a ``.cc`` file (unless implementation in the header file
+  brings demonstrable and significant performance improvement).
+
+- Avoid declaring trivial destructors, to optimize performance.
+
 C++ standard
 ============
 
@@ -1250,10 +1389,6 @@
     void MySub(const T& t);  // OK
     void MySub(T const& t);  // Not OK
 
-- Do not include inline implementations in header files; put all
-  implementation in a ``.cc`` file (unless implementation in the header file
-  brings demonstrable and significant performance improvement).
-
 - Do not use ``NULL``, ``nil`` or ``0`` constants; use ``nullptr`` (improves portability)
 
 - Consider whether you want the default constructor, copy constructor, or assignment
@@ -1315,12 +1450,13 @@
 Clang-tidy rules
 ================
 
-Please refer to the ``.clang-tidy`` file in the |ns3| root directory for the full list
+Please refer to the ``.clang-tidy`` file in the |ns3| main directory for the full list
 of rules that should be observed while developing code.
 
-- Explicitly mark inherited functions with the ``override`` specifier.
+Some rules are explained in the corresponding sections above. The remaining rules are
+explained here.
 
-- Prefer to use ``.emplace_back()`` over ``.push_back()`` to optimize performance.
+- Explicitly mark inherited functions with the ``override`` specifier.
 
 - When creating STL smart pointers, prefer to use ``std::make_shared`` or
   ``std::make_unique``, instead of creating the smart pointer with ``new``.
@@ -1340,80 +1476,46 @@
     for (const auto& v : myVector) { ... }             // Prefer
     for (int i = 0; i < myVector.size(); i++) { ... }  // Avoid
 
-- When looping through containers, prefer to use const-ref syntax over copying
-  elements.
-
-  .. sourcecode:: cpp
-
-    std::vector<int> myVector{1, 2, 3};
-
-    for (const auto& v : myVector) { ... }  // OK
-    for (auto v : myVector) { ... }         // Avoid
-
-- When initializing ``std::vector`` containers with known size, reserve memory to
-  store all items, before pushing them in a loop.
-
-  .. sourcecode:: cpp
-
-    constexpr int N_ITEMS = 5;
-
-    std::vector<int> myVector;
-    myVector.reserve(N_ITEMS); // Reserve memory to store all items
-
-    for (int i = 0; i < N_ITEMS; i++)
-    {
-        myVector.emplace_back(i);
-    }
-
-- Prefer to initialize STL containers (e.g., ``std::vector``, ``std::map``, etc.)
-  directly with a braced-init-list, instead of pushing elements one-by-one.
+- Avoid accessing class static functions and members through objects.
+  Instead, prefer to access them through the class.
 
   .. sourcecode:: cpp
 
     // OK
-    std::vector<int> myVector{1, 2, 3};
+    MyClass::StaticFunction();
 
     // Avoid
-    std::vector<int> myVector;
-    myVector.reserve(3);
-    myVector.emplace_back(1);
-    myVector.emplace_back(2);
-    myVector.emplace_back(3);
-
-- Prefer to use the ``empty()`` function of STL containers (e.g., ``std::vector``),
-  instead of the condition ``size() > 0``, to avoid unnecessarily calculating the
-  size of the container.
-
-- Avoid unnecessary calls to the functions ``.c_str()`` and ``.data()`` of
-  ``std::string``.
+    MyClass myClass;
+    MyClass.StaticFunction();
 
-- Avoid unnecessarily dereferencing std smart pointers (``std::shared_ptr``,
-  ``std::unique_ptr``) with calls to their member function ``.get()``.
-  Prefer to use the std smart pointer directly where needed.
+- Prefer using type traits in short form ``traits_t<...>`` and ``traits_v<...>``,
+  instead of the long form ``traits<...>::type`` and ``traits<...>::value``, respectively.
 
   .. sourcecode:: cpp
 
-    auto ptr = std::make_shared<Node>();
+    // Prefer using the shorter version of type traits
+    std::is_same_v<int, float>
+    std::is_integral_v<T>
+    std::enable_if_t<std::is_integral_v<T>, Time>
 
-    // OK
-    if (ptr) { ... }
+    // Avoid the longer form of type traits
+    std::is_same<int, float>::value
+    std::is_integral<T>::value
+    std::enable_if<std::is_integral<T>::value, Time>::type
 
-    // Avoid
-    if (ptr.get()) { ... }
+- Avoid using integer values (``1`` or ``0``) to represent boolean variables
+  (``true`` or ``false``), to improve code readability and avoid implicit conversions.
 
-- Avoid declaring trivial destructors, to optimize performance.
+- Prefer to use ``static_assert()`` over ``NS_ASSERT()`` when conditions can be
+  evaluated at compile-time.
 
-- Avoid accessing class static functions and members through objects.
-  Instead, prefer to access them through the class.
+- Prefer using transparent functors to non-transparent ones, to avoid repeating
+  the type name. This improves readability and avoids errors when refactoring code.
 
   .. sourcecode:: cpp
 
-    // OK
-    MyClass::StaticFunction();
+    // Prefer using transparent functors
+    std::map<MyClass, int, std::less<>> myMap;
 
-    // Avoid
-    MyClass myClass;
-    MyClass.StaticFunction();
-
-- Prefer to use ``static_assert()`` over ``NS_ASSERT()`` when conditions can be
-  evaluated at compile-time.
+    // Avoid repeating the type name "MyClass" in std::less<>
+    std::map<MyClass, int, std::less<MyClass>> myMap;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/contributing/source/conf.py ns-3.40/doc/contributing/source/conf.py
--- ns-3.39/doc/contributing/source/conf.py	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/contributing/source/conf.py	2023-09-27 13:30:55.802883400 -0700
@@ -48,9 +48,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = 'ns-3.39'
+version = 'ns-3.40'
 # The full version, including alpha/beta/rc tags.
-release = 'ns-3.39'
+release = 'ns-3.40'
 
 # 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.39/doc/contributing/source/index.rst ns-3.40/doc/contributing/source/index.rst
--- ns-3.39/doc/contributing/source/index.rst	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/contributing/source/index.rst	2023-09-27 13:30:37.534838700 -0700
@@ -24,6 +24,7 @@
 
 .. toctree::
    :maxdepth: 2
+   :numbered:
 
    introduction
    general
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/doxygen.warnings.report.sh ns-3.40/doc/doxygen.warnings.report.sh
--- ns-3.39/doc/doxygen.warnings.report.sh	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/doxygen.warnings.report.sh	2023-09-27 13:30:37.534838700 -0700
@@ -247,10 +247,8 @@
 REappend filter_blacklistRE "cairo-wideint"
 
 #   Functions with varying numbers of arguments
-#   This is temporary until we move to C++-14
-REappend filter_blacklistRE "Schedule(Time"
-REappend filter_blacklistRE "ScheduleWithContext(uint32_t"
-REappend filter_blacklistRE "Schedule\\(Now\\|Destroy\\)(\\(MEM\\|void\\)"
+#   Explicit template instantiation declaration
+REappend filter_blacklistRE "MakeCallback< ObjectBase \\* >(ObjectBase \\*"
 
 #   ATTRIBUTE_HELPER_CPP( and _HEADER(
 REappend filter_blacklistRE "ATTRIBUTE_HELPER_\\(CPP\\|HEADER\\)"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/installation/source/conf.py ns-3.40/doc/installation/source/conf.py
--- ns-3.39/doc/installation/source/conf.py	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/installation/source/conf.py	2023-09-27 13:30:55.802883400 -0700
@@ -48,9 +48,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = 'ns-3.39'
+version = 'ns-3.40'
 # The full version, including alpha/beta/rc tags.
-release = 'ns-3.39'
+release = 'ns-3.40'
 
 # 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.39/doc/installation/source/index.rst ns-3.40/doc/installation/source/index.rst
--- ns-3.39/doc/installation/source/index.rst	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/installation/source/index.rst	2023-09-27 13:30:37.534838700 -0700
@@ -24,6 +24,7 @@
 
 .. toctree::
    :maxdepth: 2
+   :numbered:
 
    overview
    quick-start
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/installation/source/macos.rst ns-3.40/doc/installation/source/macos.rst
--- ns-3.39/doc/installation/source/macos.rst	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/installation/source/macos.rst	2023-09-27 13:30:37.534838700 -0700
@@ -38,6 +38,8 @@
 For a short guide on virtual environments, please see
 `this link <https://www.dataquest.io/blog/a-complete-guide-to-python-virtual-environments/>`_.
 
+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).
+
 Requirements
 ************
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/installation/source/quick-start.rst ns-3.40/doc/installation/source/quick-start.rst
--- ns-3.39/doc/installation/source/quick-start.rst	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/installation/source/quick-start.rst	2023-09-27 13:30:37.534838700 -0700
@@ -42,7 +42,7 @@
   |                    | or ``tar`` and ``bunzip2``           | No minimum version           |
   |                    | (for Web download)                   |                              |
   +--------------------+--------------------------------------+------------------------------+
-  | **Compiler**       | ``g++``                              | >= 8                         |
+  | **Compiler**       | ``g++``                              | >= 9                         |
   +                    +                                      +                              +
   |                    | or ``clang++``                       | >= 10                        |
   +--------------------+--------------------------------------+------------------------------+
@@ -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.39``
+1. Download a release tarball.  This will unpack to a directory such as ``ns-allinone-3.40``
 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.39.tar.bz2
-  $ tar xfj ns-allinone-3.39.tar.bz2
-  $ cd ns-allinone-3.39/ns-3.39
+  $ wget https://www.nsnam.org/releases/ns-allinone-3.40.tar.bz2
+  $ tar xfj ns-allinone-3.40.tar.bz2
+  $ cd ns-allinone-3.40/ns-3.40
 
 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.39-release ns-3.39
+  $ git checkout -b ns-3.40-release ns-3.40
 
 In this quick-start, we are omitting download and build instructions for optional |ns3| modules,
 the ``NetAnim`` animator, Python bindings, and ``NetSimulyzer``.  The
@@ -177,3 +177,30 @@
 * Apple's XCode
 * CodeBlocks
 * Eclipse CDT4
+
+Installing ns-3
+***************
+
+Most users do not install |ns3| libraries to typical system library directories; they instead
+just leave the libraries in the ``build`` directory, and the ``ns3`` Python program will
+find these libraries.  However, it is possible to perform an installation step-- ``ns3 install``--
+with the following caveats.
+
+The location of the installed libraries is set by the ``--prefix`` option specified at the
+configure step.  The prefix defaults to ``/usr/local``.  For a given ``--prefix=$PREFIX``,
+the installation step will install headers to a ``$PREFIX/include`` directory, libraries
+and pkgconfig files to a ``$PREFIX/lib`` directory, and a few binaries to a
+``$PREFIX/libexec`` directory.  For example, ``./ns3 configure --prefix=/tmp``, followed
+by ``./ns3 build`` and ``./ns3 install``, will lead to files being installed in
+``/tmp/include``, ``/tmp/lib``, and ``/tmp/libexec``.
+
+Note that the ``ns3`` script prevents running the script as root (or as a sudo user).  As a
+result, with the default prefix of ``/usr/local``, the installation will fail unless the
+user has write privileges in that directory.  Attempts to force this with
+``sudo ./ns3 install`` will fail due to a check in the ``ns3`` program that prevents running
+as root.  This check was installed by |ns3| maintainers for the safety of novice users who may
+run ``./ns3`` in a root shell and later in a normal shell, and become confused about errors
+resulting in lack of privileges to modify files.   For users who know what they are doing and
+who want to install to a privileged directory, users can comment out the statement
+``refuse_run_as_root()`` in the ``ns3`` program (around line 1400), and then run
+``sudo ./ns3 install``.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/installation/source/system.rst ns-3.40/doc/installation/source/system.rst
--- ns-3.39/doc/installation/source/system.rst	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/installation/source/system.rst	2023-09-27 13:30:37.534838700 -0700
@@ -143,6 +143,8 @@
 |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.
 
+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).
+
 Using Python bindings (release 3.30 to ns-3.36)
 ===============================================
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/installation/source/windows.rst ns-3.40/doc/installation/source/windows.rst
--- ns-3.39/doc/installation/source/windows.rst	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/installation/source/windows.rst	2023-09-27 13:30:37.534838700 -0700
@@ -19,7 +19,7 @@
 
 .. note::
   |ns3| is not fully compatible with Visual Studio IDE / MSVC compiler; only Visual Studio Code
-editor, the Msys2/MinGW64 toolchain, and WSL, as explained below.
+  editor, the Msys2/MinGW64 toolchain, and WSL, as explained below.
 
 .. _WSL2:
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/manual/Makefile ns-3.40/doc/manual/Makefile
--- ns-3.39/doc/manual/Makefile	2023-07-05 14:23:47.593426700 -0700
+++ ns-3.40/doc/manual/Makefile	2023-09-27 13:30:37.534838700 -0700
@@ -78,7 +78,6 @@
 	figures/hotspot-top-down.png \
 	figures/perfetto-trace-cmake.png \
 	figures/uprof-collect-callstack.png \
-	figures/uprof-collect-callstack.png \
 	figures/uprof-profile-application.png \
 	figures/uprof-select-events.png \
 	figures/uprof-start.png \
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/manual/source/conf.py ns-3.40/doc/manual/source/conf.py
--- ns-3.39/doc/manual/source/conf.py	2023-07-05 14:23:47.629426700 -0700
+++ ns-3.40/doc/manual/source/conf.py	2023-09-27 13:30:55.802883400 -0700
@@ -73,9 +73,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = u'ns-3.39'
+version = u'ns-3.40'
 # The full version, including alpha/beta/rc tags.
-release = u'ns-3.39'
+release = u'ns-3.40'
 
 # 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.39/doc/manual/source/enable-modules.rst ns-3.40/doc/manual/source/enable-modules.rst
--- ns-3.39/doc/manual/source/enable-modules.rst	2023-07-05 14:23:47.629426700 -0700
+++ ns-3.40/doc/manual/source/enable-modules.rst	2023-09-27 13:30:37.570839000 -0700
@@ -97,6 +97,8 @@
     # Modules that depend on the listed modules will be enabled also.
     #
     # All modules can be enabled by emptying the list.
+    # To list modules, append the modules separated by space or semicolon; e.g.:
+    # set(ns3rc_enabled_modules core propagation)
     set(ns3rc_enabled_modules)
 
     # A list of the modules that will be disabled when ns-3 is run.
@@ -123,6 +125,8 @@
     # Modules that depend on the listed modules will be enabled also.
     #
     # All modules can be enabled by emptying the list.
+    # To list modules, append the modules separated by space or semicolon; e.g.:
+    # set(ns3rc_enabled_modules core propagation)
     set(ns3rc_enabled_modules core)
 
     # A list of the modules that will be disabled when ns-3 is run.
@@ -176,3 +180,16 @@
 .. sourcecode:: text
 
   31 of 31 tests passed (31 passed, 0 skipped, 0 failed, 0 crashed, 0 valgrind errors)
+
+As the comment in the sample ``.ns3rc`` file suggests, users may list multiple enabled modules by
+separating each requested module by space or semicolon; e.g.:
+
+.. sourcecode:: cmake
+
+    set(ns3rc_enabled_modules core propagation)
+
+The following also works (but note that a comma delimiter will not work with this CMake list):
+
+.. sourcecode:: cmake
+
+    set(ns3rc_enabled_modules core;propagation)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/manual/source/enable-tests.rst ns-3.40/doc/manual/source/enable-tests.rst
--- ns-3.39/doc/manual/source/enable-tests.rst	2023-07-05 14:23:47.629426700 -0700
+++ ns-3.40/doc/manual/source/enable-tests.rst	2023-09-27 13:30:37.570839000 -0700
@@ -173,3 +173,48 @@
 .. sourcecode:: text
 
   170 of 170 tests passed (170 passed, 0 skipped, 0 failed, 0 crashed, 0 valgrind errors)
+
+
+Enable examples and tests that depend on a set of modules using |ns3|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+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
+
+  ./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
+
+  ./ns3 configure --filter-module-examples-and-tests="wifi;core" --enable-examples --enable-tests
+
+The first command will generally lead to a shorter build time, but the second option will provide better
+coverage, by building additional test cases and examples directly related to the specified modules.
+
+Enable examples and tests that depend on a set of modules using the |ns3| configuration file
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+As seen above, examples and tests can be enabled for just a subset of the available modules via the
+``ns3`` script. The same can be accomplished via the ``.ns3rc`` configuration file.
+
+.. sourcecode:: cmake
+
+    # A list of the modules that will be enabled when ns-3 is run.
+    # Modules that depend on the listed modules will be enabled also.
+    #
+    # All modules can be enabled by emptying the list.
+    set(ns3rc_enabled_modules)
+
+    # ...
+
+    # Override other ns-3 settings by setting their values below
+    # Note: command-line settings will also be overridden.
+    #set(NS3_LOG ON)
+
+    # The following will build core and wifi tests, plus their examples
+    # and examples on /ns-3-dev/examples that depend on either of them
+    set(NS3_FILTER_MODULE_EXAMPLES_AND_TESTS wifi core) # <==
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/manual/source/events.rst ns-3.40/doc/manual/source/events.rst
--- ns-3.39/doc/manual/source/events.rst	2023-07-05 14:23:47.629426700 -0700
+++ ns-3.40/doc/manual/source/events.rst	2023-09-27 13:30:37.570839000 -0700
@@ -215,9 +215,9 @@
   GlobalValue::Bind("SimulatorImplementationType",
                     StringValue("ns3::DistributedSimulatorImpl"));
 
-or by using a command line argument::
+or by using a command line argument
 
-.. sourcecode:: bash
+.. sourcecode:: terminal
 
   $ ./ns3 run "...  -–SimulatorImplementationType=ns3::DistributedSimulatorImpl"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/manual/source/index.rst ns-3.40/doc/manual/source/index.rst
--- ns-3.39/doc/manual/source/index.rst	2023-07-05 14:23:47.629426700 -0700
+++ ns-3.40/doc/manual/source/index.rst	2023-09-27 13:30:37.570839000 -0700
@@ -24,6 +24,7 @@
 
 .. toctree::
    :maxdepth: 2
+   :numbered:
 
    organization
    simulator
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/manual/source/python.rst ns-3.40/doc/manual/source/python.rst
--- ns-3.39/doc/manual/source/python.rst	2023-07-05 14:23:47.633426700 -0700
+++ ns-3.40/doc/manual/source/python.rst	2023-09-27 13:30:37.570839000 -0700
@@ -38,11 +38,7 @@
 are only built on-demand by Cppyy, and only if the user enables them in the
 configuration of |ns3|.
 
-It is also important to note that the current capability is provided on a
-lightly maintained basis and not officially supported by the project
-(in other words, we are currently looking for a Python bindings maintainer).
-The Cppyy framework could be replaced if it becomes too burdensome to
-maintain as we are presently doing.
+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).
 
 Prior to ns-3.37, the previous Python bindings framework was based on
 `Pybindgen <https://github.com/gjcarneiro/pybindgen>`_.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/manual/source/utilities.rst ns-3.40/doc/manual/source/utilities.rst
--- ns-3.39/doc/manual/source/utilities.rst	2023-07-05 14:23:47.633426700 -0700
+++ ns-3.40/doc/manual/source/utilities.rst	2023-09-27 13:30:37.570839000 -0700
@@ -33,7 +33,7 @@
 
 To run it, simply open terminal and type
 
-.. sourcecode::
+.. sourcecode:: bash
 
     $ ./ns3 run print-introspected-doxygen
 
@@ -78,7 +78,7 @@
 Command-line Arguments
 ++++++++++++++++++++++
 
-.. sourcecode::
+.. sourcecode:: bash
 
     $ ./ns3 run "bench-scheduler --help"
     bench-scheduler [Program Options] [General Arguments]
@@ -129,7 +129,7 @@
 
 To run it, simply open the terminal and type
 
-.. sourcecode::
+.. sourcecode:: bash
 
     $ ./ns3 run bench-scheduler -- --runs=5
 
@@ -156,7 +156,7 @@
 
 Suppose we had to benchmark `CalendarScheduler` instead, we would have written
 
-.. sourcecode::
+.. sourcecode:: bash
 
     $ ./ns3 run bench-scheduler -- --runs=5 --cal"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/manual/source/working-with-cmake.rst ns-3.40/doc/manual/source/working-with-cmake.rst
--- ns-3.39/doc/manual/source/working-with-cmake.rst	2023-07-05 14:23:47.633426700 -0700
+++ ns-3.40/doc/manual/source/working-with-cmake.rst	2023-09-27 13:30:37.570839000 -0700
@@ -125,7 +125,7 @@
   -- Processing src/wimax
   -- ---- Summary of optional ns-3 features:
   Build profile                 : release
-  Build directory               : /mnt/dev/tools/source/ns-3-dev/build
+  Build directory               : /ns-3-dev/build
   ...
   Examples                      : ON
   ...
@@ -147,7 +147,7 @@
 
   -- Configuring done
   -- Generating done
-  -- Build files have been written to: /mnt/dev/tools/source/ns-3-dev/cmake-cache
+  -- Build files have been written to: /ns-3-dev/cmake-cache
   Finished executing the following commands:
   mkdir cmake-cache
   cd cmake-cache; /usr/bin/cmake -DCMAKE_BUILD_TYPE=release -DNS3_NATIVE_OPTIMIZATIONS=OFF -DNS3_EXAMPLES=ON -DNS3_TESTS=ON -G Unix Makefiles .. ; cd ..
@@ -357,7 +357,7 @@
 The last way is omitted, since each underlying build system
 has its own unique command-line syntax.
 
-Building the project with n``s3``
+Building the project with ``ns3``
 +++++++++++++++++++++++++++++++++
 
 The ``ns3`` wrapper script makes life easier for command line users, accepting module names without
@@ -819,6 +819,11 @@
 More details on how find_external_library works and the other
 ways to import third-party libraries are presented next.
 
+It is recommended to use a system package managers to install libraries,
+but ns-3 also supports vcpkg and CPM. More information on how to
+use them is available in `Using C++ library managers`_.
+
+
 .. _Linking third-party libraries without CMake or PkgConfig support:
 
 Linking third-party libraries without CMake or PkgConfig support
@@ -1203,7 +1208,7 @@
 Assume we have a module with optional features that rely on a third-party library
 that provides a FindThirdPartyPackage.cmake. This ``Find${Package}.cmake`` file can be distributed
 by `CMake itself`_, via library/package managers (APT, Pacman,
-`VcPkg`_), or included to the project tree in the build-support/3rd-party directory.
+`vcpkg`_), or included to the project tree in the build-support/3rd-party directory.
 
 .. _CMake itself: https://github.com/Kitware/CMake/tree/master/Modules
 .. _Vcpkg: https://github.com/Microsoft/vcpkg#using-vcpkg-with-cmake
@@ -1494,7 +1499,543 @@
         test/hypothetical.cc
     )
 
+.. _Using C++ library managers:
+
+Using C++ library managers
+++++++++++++++++++++++++++
+
+It is not rare to try using a library that is not available
+on a certain platform or does not have a CMake-friendly
+interface for us to use.
+
+.. _CPM: https://github.com/cpm-cmake/CPM.cmake
+
+Some C++ package managers are fairly easy to use with CMake,
+such as `Vcpkg`_ and `CPM`_.
+
+vcpkg
+=====
+
+Vcpkg requires ``git``, ``curl``, ``zip``, ``unzip`` and ``tar``,
+along with the default ns-3 dependencies. The setup downloads
+and builds vcpkg from their Git repository. Telemetry is disabled
+by default.
+
+.. sourcecode:: console
+
+  ~$ ./ns3 configure -- -DNS3_VCPKG=ON
+  ...
+  -- vcpkg: setting up support
+  Cloning into 'vcpkg'...
+  Updating files: 100% (10376/10376), done.
+  Downloading vcpkg-glibc...
+  vcpkg package management program version 2023-07-19-814b7ec837b59f1c8778f72351c1dd7605983cd2
+  ...
+
+Configuration will finish successfully.
+For example, now we can try using the Armadillo library.
+To do that, we use the following CMake statements:
+
+.. sourcecode:: cmake
+
+    # Check this is not a fluke
+    find_package(Armadillo)
+    message(STATUS "Armadillo was found? ${ARMADILLO_FOUND}")
+
+Reconfigure ns-3 to check if Armadillo is available.
+
+.. sourcecode:: console
+
+  ~$ ./ns3 configure
+  ...
+  -- vcpkg: setting up support
+  -- vcpkg: folder already exists, skipping git download
+  -- vcpkg: already bootstrapped
+  ...
+  -- Could NOT find Armadillo (missing: ARMADILLO_INCLUDE_DIR)
+  -- Armadillo was found? FALSE
+
+As you can see, no Armadillo found.
+We can now use vcpkg to install it, using the CMake
+function ``add_package(package_name)``. CMake
+will then be able to find the installed package using ``find_package``.
+
+Note: some packages may require additional dependencies.
+The Armadillo package requires ``pkg-config`` and a fortran compiler.
+You will be prompted with a CMake error when a missing dependency is found.
+
+.. sourcecode:: cmake
+
+    # Install Armadillo and search for it again
+    add_package(Armadillo) # Installs Armadillo with vcpkg
+    find_package(Armadillo) # Loads vcpkg installation of Armadillo
+    message(STATUS "Armadillo was found? ${ARMADILLO_FOUND}")
+
+Sadly, we will need to reconfigure ns-3 from the scratch,
+since CMake ``find_package`` caches are problematic.
+Installing the packages can take a while, and it can look like it hanged.
+
+.. sourcecode:: console
+
+  ~$ ./ns3 clean
+  ~$ ./ns3 configure -- -DNS3_VCPKG=ON
+  ...
+  -- vcpkg: setting up support
+  -- vcpkg: folder already exists, skipping git download
+  -- vcpkg: already bootstrapped
+  ...
+  -- vcpkg: Armadillo will be installed
+  -- vcpkg: Armadillo was installed
+  -- Armadillo was found? TRUE
+
+As shown above, the Armadillo library gets installed by vcpkg
+and it can be found by CMake's ``find_package`` function.
+We can then use it for our targets.
+
+.. sourcecode:: cmake
+
+    # Install Armadillo
+    add_package(Armadillo) # Installs Armadillo with vcpkg
+    find_package(Armadillo) # Loads vcpkg installation of Armadillo
+    message(STATUS "Armadillo was found? ${ARMADILLO_FOUND}")
+
+    # Include and link Armadillo to targets
+    include_directories(${ARMADILLO_INCLUDE_DIRS})
+    link_libraries(${ARMADILLO_LIBRARIES})
+
+.. _vcpkg manifests: https://learn.microsoft.com/en-us/vcpkg/users/manifests
+
+An alternative to manually installing packages with ``add_package`` is
+placing all packages into a ``vcpkg.json`` file in the ns-3 main directory.
+This mode is known as the "manifest mode" in the Vcpkg manual.
+Packages there will be automatically installed at the beginning of the configuration.
+More information about the manifest mode can be found in `vcpkg manifests`_ website.
+
+Let us see an example of this mode starting with the ``vcpkg.json`` file.
+
+.. sourcecode:: json
+
+    {
+      "dependencies": [
+        "sqlite3",
+        "eigen3",
+        "libxml2",
+        "gsl",
+        "boost-units"
+      ]
+    }
+
+These are some of the optional dependencies used by the upstream ns-3 modules.
+When configuring ns-3 with the Vcpkg support, we will see the following.
+
+.. sourcecode:: console
+
+    /ns-3-dev$ ./ns3 clean
+    /ns-3-dev$ ./ns3 configure -- -DNS3_VCPKG=ON
+    ...
+    -- vcpkg: setting up support
+    Cloning into 'vcpkg'...
+    Updating files: 100% (10434/10434), done.
+    Downloading vcpkg-glibc...
+    vcpkg package management program version 2023-08-02-6d13efa755f9b5e101712d210199e4139b4c29f6
+
+    See LICENSE.txt for license information.
+    -- vcpkg: detected a vcpkg manifest file: /ns-3-dev/vcpkg.json
+    A suitable version of cmake was not found (required v3.27.1) Downloading portable cmake 3.27.1...
+    Downloading cmake...
+    https://github.com/Kitware/CMake/releases/download/v3.27.1/cmake-3.27.1-linux-x86_64.tar.gz->/ns-3-dev/vcpkg/downloads/cmake-3.27.1-linux-x86_64.tar.gz
+    Extracting cmake...
+    Detecting compiler hash for triplet x64-linux...
+    The following packages will be built and installed:
+      * boost-array:x64-linux -> 1.82.0#2
+      ...
+      * boost-winapi:x64-linux -> 1.82.0#2
+        eigen3:x64-linux -> 3.4.0#2
+        gsl:x64-linux -> 2.7.1#3
+      * libiconv:x64-linux -> 1.17#1
+      * liblzma:x64-linux -> 5.4.3#1
+        libxml2[core,iconv,lzma,zlib]:x64-linux -> 2.10.3#1
+        sqlite3[core,json1]:x64-linux -> 3.42.0#1
+      * vcpkg-cmake:x64-linux -> 2023-05-04
+      * vcpkg-cmake-config:x64-linux -> 2022-02-06#1
+      * vcpkg-cmake-get-vars:x64-linux -> 2023-03-02
+      * zlib:x64-linux -> 1.2.13
+    Additional packages (*) will be modified to complete this operation.
+    Restored 0 package(s) from /root/.cache/vcpkg/archives in 98.7 us. Use --debug to see more details.
+    Installing 1/58 boost-uninstall:x64-linux...
+    ...
+    Installing 50/58 boost-units:x64-linux...
+    Building boost-units:x64-linux...
+    -- Downloading https://github.com/boostorg/units/archive/boost-1.82.0.tar.gz -> boostorg-units-boost-1.82.0.tar.gz...
+    -- Extracting source /ns-3-dev/vcpkg/downloads/boostorg-units-boost-1.82.0.tar.gz
+    -- Using source at /ns-3-dev/vcpkg/buildtrees/boost-units/src/ost-1.82.0-a9fdcc40b2.clean
+    -- Copying headers
+    -- Copying headers done
+    -- Installing: /ns-3-dev/vcpkg/packages/boost-units_x64-linux/share/boost-units/usage
+    -- Installing: /ns-3-dev/vcpkg/packages/boost-units_x64-linux/share/boost-units/copyright
+    -- Performing post-build validation
+    Stored binaries in 1 destinations in 276 ms.
+    Elapsed time to handle boost-units:x64-linux: 3.8 s
+    Installing 51/58 vcpkg-cmake-config:x64-linux...
+    Building vcpkg-cmake-config:x64-linux...
+    -- Installing: /ns-3-dev/vcpkg/packages/vcpkg-cmake-config_x64-linux/share/vcpkg-cmake-config/vcpkg_cmake_config_fixup.cmake
+    -- Installing: /ns-3-dev/vcpkg/packages/vcpkg-cmake-config_x64-linux/share/vcpkg-cmake-config/vcpkg-port-config.cmake
+    -- Installing: /ns-3-dev/vcpkg/packages/vcpkg-cmake-config_x64-linux/share/vcpkg-cmake-config/copyright
+    -- Performing post-build validation
+    Stored binaries in 1 destinations in 8.58 ms.
+    Elapsed time to handle vcpkg-cmake-config:x64-linux: 144 ms
+    Installing 52/58 eigen3:x64-linux...
+    Building eigen3:x64-linux...
+    -- Downloading https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz -> libeigen-eigen-3.4.0.tar.gz...
+    -- Extracting source /ns-3-dev/vcpkg/downloads/libeigen-eigen-3.4.0.tar.gz
+    -- Applying patch remove_configure_checks.patch
+    -- Applying patch fix-vectorized-reductions-half.patch
+    -- Using source at /ns-3-dev/vcpkg/buildtrees/eigen3/src/3.4.0-74a8d62212.clean
+    -- Configuring x64-linux
+    -- Building x64-linux-dbg
+    -- Building x64-linux-rel
+    -- Fixing pkgconfig file: /ns-3-dev/vcpkg/packages/eigen3_x64-linux/lib/pkgconfig/eigen3.pc
+    CMake Error at scripts/cmake/vcpkg_find_acquire_program.cmake:163 (message):
+      Could not find pkg-config.  Please install it via your package manager:
+
+          sudo apt-get install pkg-config
+    Call Stack (most recent call first):
+      scripts/cmake/vcpkg_fixup_pkgconfig.cmake:203 (vcpkg_find_acquire_program)
+      ports/eigen3/portfile.cmake:30 (vcpkg_fixup_pkgconfig)
+      scripts/ports.cmake:147 (include)
+
+
+    error: building eigen3:x64-linux failed with: BUILD_FAILED
+    Elapsed time to handle eigen3:x64-linux: 19 s
+    Please ensure you're using the latest port files with `git pull` and `vcpkg update`.
+    Then check for known issues at:
+        https://github.com/microsoft/vcpkg/issues?q=is%3Aissue+is%3Aopen+in%3Atitle+eigen3
+    You can submit a new issue at:
+        https://github.com/microsoft/vcpkg/issues/new?title=[eigen3]+Build+error&body=Copy+issue+body+from+%2Fns-3-dev%2Fvcpkg%2Finstalled%2Fvcpkg%2Fissue_body.md
+
+    CMake Error at build-support/3rd-party/colored-messages.cmake:82 (_message):
+      vcpkg: packages defined in the manifest failed to be installed
+    Call Stack (most recent call first):
+      build-support/custom-modules/ns3-vcpkg-hunter.cmake:138 (message)
+      build-support/custom-modules/ns3-vcpkg-hunter.cmake:183 (setup_vcpkg)
+      build-support/macros-and-definitions.cmake:743 (include)
+      CMakeLists.txt:149 (process_options)
+
+As we can see above, the setup failed during the eigen3 setup due to a missing dependency.
+In this case, pkg-config. We can install it using the system package manager and then
+resume the ns-3 configuration.
+
+
+.. sourcecode:: console
+
+    /ns-3-dev$ apt install -y pkg-config
+    /ns-3-dev$ ./ns3 configure -- -DNS3_VCPKG=ON
+    ...
+    -- vcpkg: folder already exists, skipping git download
+    -- vcpkg: already bootstrapped
+    -- vcpkg: detected a vcpkg manifest file: /ns-3-dev/vcpkg.json
+    Detecting compiler hash for triplet x64-linux...
+    The following packages will be built and installed:
+        eigen3:x64-linux -> 3.4.0#2
+        gsl:x64-linux -> 2.7.1#3
+      * libiconv:x64-linux -> 1.17#1
+      * liblzma:x64-linux -> 5.4.3#1
+        libxml2[core,iconv,lzma,zlib]:x64-linux -> 2.10.3#1
+        sqlite3[core,json1]:x64-linux -> 3.42.0#1
+      * zlib:x64-linux -> 1.2.13
+    Additional packages (*) will be modified to complete this operation.
+    Restored 0 package(s) from /root/.cache/vcpkg/archives in 97.6 us. Use --debug to see more details.
+    Installing 1/7 eigen3:x64-linux...
+    Building eigen3:x64-linux...
+    -- Using cached libeigen-eigen-3.4.0.tar.gz.
+    -- Cleaning sources at /ns-3-dev/vcpkg/buildtrees/eigen3/src/3.4.0-74a8d62212.clean. Use --editable to skip cleaning for the packages you specify.
+    -- Extracting source /ns-3-dev/vcpkg/downloads/libeigen-eigen-3.4.0.tar.gz
+    -- Applying patch remove_configure_checks.patch
+    -- Applying patch fix-vectorized-reductions-half.patch
+    -- Using source at /ns-3-dev/vcpkg/buildtrees/eigen3/src/3.4.0-74a8d62212.clean
+    -- Configuring x64-linux
+    -- Building x64-linux-dbg
+    -- Building x64-linux-rel
+    -- Fixing pkgconfig file: /ns-3-dev/vcpkg/packages/eigen3_x64-linux/lib/pkgconfig/eigen3.pc
+    -- Fixing pkgconfig file: /ns-3-dev/vcpkg/packages/eigen3_x64-linux/debug/lib/pkgconfig/eigen3.pc
+    -- Installing: /ns-3-dev/vcpkg/packages/eigen3_x64-linux/share/eigen3/copyright
+    -- Performing post-build validation
+    Stored binaries in 1 destinations in 1.7 s.
+    Elapsed time to handle eigen3:x64-linux: 28 s
+    Installing 2/7 gsl:x64-linux...
+    ...
+    Installing 7/7 sqlite3:x64-linux...
+    Building sqlite3[core,json1]:x64-linux...
+    -- Downloading https://sqlite.org/2023/sqlite-amalgamation-3420000.zip -> sqlite-amalgamation-3420000.zip...
+    -- Extracting source /ns-3-dev/vcpkg/downloads/sqlite-amalgamation-3420000.zip
+    -- Applying patch fix-arm-uwp.patch
+    -- Applying patch add-config-include.patch
+    -- Using source at /ns-3-dev/vcpkg/buildtrees/sqlite3/src/on-3420000-e624a7f335.clean
+    -- Configuring x64-linux
+    -- Building x64-linux-dbg
+    -- Building x64-linux-rel
+    -- Fixing pkgconfig file: /ns-3-dev/vcpkg/packages/sqlite3_x64-linux/lib/pkgconfig/sqlite3.pc
+    -- Fixing pkgconfig file: /ns-3-dev/vcpkg/packages/sqlite3_x64-linux/debug/lib/pkgconfig/sqlite3.pc
+    -- Installing: /ns-3-dev/vcpkg/packages/sqlite3_x64-linux/share/sqlite3/usage
+    -- Performing post-build validation
+    Stored binaries in 1 destinations in 430 ms.
+    Elapsed time to handle sqlite3:x64-linux: 42 s
+    Total install time: 2.5 min
+    The package boost is compatible with built-in CMake targets:
+
+        find_package(Boost REQUIRED [COMPONENTS <libs>...])
+        target_link_libraries(main PRIVATE Boost::boost Boost::<lib1> Boost::<lib2> ...)
+
+    eigen3 provides CMake targets:
+
+        # this is heuristically generated, and may not be correct
+        find_package(Eigen3 CONFIG REQUIRED)
+        target_link_libraries(main PRIVATE Eigen3::Eigen)
+
+    The package gsl is compatible with built-in CMake targets:
+
+        find_package(GSL REQUIRED)
+        target_link_libraries(main PRIVATE GSL::gsl GSL::gslcblas)
+
+    The package libxml2 is compatible with built-in CMake targets:
+
+        find_package(LibXml2 REQUIRED)
+        target_link_libraries(main PRIVATE LibXml2::LibXml2)
+
+    sqlite3 provides pkgconfig bindings.
+    sqlite3 provides CMake targets:
+
+        find_package(unofficial-sqlite3 CONFIG REQUIRED)
+        target_link_libraries(main PRIVATE unofficial::sqlite3::sqlite3)
+
+    -- vcpkg: packages defined in the manifest were installed
+    -- find_external_library: SQLite3 was found.
+    ...
+    -- LibXML2 was found.
+    ...
+    -- Found Boost: /ns-3-dev/vcpkg/installed/x64-linux/include (found version "1.82.0")
+    ...
+    -- Looking for include files boost/units/quantity.hpp, boost/units/systems/si.hpp
+    -- Looking for include files boost/units/quantity.hpp, boost/units/systems/si.hpp - found
+    -- Boost Units have been found.
+    ...
+    -- ---- Summary of ns-3 settings:
+    Build profile                 : default
+    Build directory               : /ns-3-dev/build
+    Build with runtime asserts    : ON
+    ...
+    GNU Scientific Library (GSL)  : ON
+    ...
+    LibXml2 support               : ON
+    ...
+    SQLite support                : ON
+    Eigen3 support                : ON
+    ...
+
+From the above, we can see that the headers and libraries installed by the packages
+were correctly found by CMake and the optional features were successfully enabled.
+
+.. _Armadillo's port on vcpkg: https://github.com/microsoft/vcpkg/blob/master/ports/armadillo/usage
+
+Note: not every vcpkg package (also known as a port) obeys
+the same pattern for usage. The user of the package needs
+to look into the usage file of said port for instructions.
+In the case of Armadillo, the corresponding file can be found
+in `Armadillo's port on vcpkg`_.
+
+Vcpkg is installed to a ``vcpkg`` directory inside the ns-3 main directory (e.g. ``ns-3-dev``).
+Packages installed via vcpkg are installed to ``ns-3-dev/vcpkg/installed/${VCPKG_TRIPLET}``,
+which is automatically added to the ``CMAKE_PREFIX_PATH``, making headers, libraries, and
+pkg-config and CMake packages discoverable via ``find_file``, ``find_library``, ``find_package``
+and ``pkg_check_modules``.
+
+CPM
+===
+
+`CPM`_ is a package manager made for CMake projects consuming CMake projects.
+Some CMake projects however, create files during the installation step, which
+is not supported by CPM, which treats the package as a CMake subproject that
+we can then depend upon. CPM may require dependencies such as ``git`` and ``tar``,
+depending on the package sources used.
+
+Let's see an example trying to find the Armadillo library via CMake.
+
+.. sourcecode:: cmake
+
+    # Check this is not a fluke
+    find_package(Armadillo)
+    message(STATUS "Armadillo was found? ${ARMADILLO_FOUND}")
+
+Reconfigure ns-3 to check if Armadillo is available.
+
+.. sourcecode:: console
+
+  ~$ ./ns3 configure
+  ...
+  -- Could NOT find Armadillo (missing: ARMADILLO_INCLUDE_DIR)
+  -- Armadillo was found? FALSE
+
+As you can see, no Armadillo found.
+We can now use CPM to install it, using the CMake
+function ``CPMAddPackage(package_info)``.
+
+.. sourcecode:: cmake
+
+    # Install Armadillo and search for it again
+    CPMAddPackage(
+        NAME ARMADILLO
+        GIT_TAG 6cada351248c9a967b137b9fcb3d160dad7c709b
+        GIT_REPOSITORY https://gitlab.com/conradsnicta/armadillo-code.git
+    )
+    find_package(Armadillo) # Loads CPM installation of Armadillo
+    message(STATUS "Armadillo was found? ${ARMADILLO_FOUND}")
+
+Sadly, we will need to reconfigure ns-3 from the scratch,
+since CMake ``find_package`` caches are problematic.
+Installing the packages can take a while, and it can look like it hanged.
+
+.. sourcecode:: console
+
+  ~$ ./ns3 clean
+  ~$ ./ns3 configure -- -DNS3_CPM=ON
+  ...
+  -- CPM: Adding package ARMADILLO@0 (6cada351248c9a967b137b9fcb3d160dad7c709b)
+  -- *** set cmake policy CMP0025 to NEW
+  -- CMAKE_CXX_STANDARD = 11
+  -- Configuring Armadillo 12.6.1
+  --
+  -- *** WARNING: variable 'CMAKE_CXX_FLAGS' is not empty; this may cause problems!
+  --
+  -- Detected Clang 6.0 or newer
+  -- ARMA_USE_EXTERN_RNG = true
+  -- CMAKE_SYSTEM_NAME          = Linux
+  -- CMAKE_CXX_COMPILER_ID      = Clang
+  -- CMAKE_CXX_COMPILER_VERSION = 15.0.7
+  -- CMAKE_COMPILER_IS_GNUCXX   =
+  --
+  -- *** Options:
+  -- BUILD_SHARED_LIBS         = ON
+  -- OPENBLAS_PROVIDES_LAPACK  = OFF
+  -- ALLOW_FLEXIBLAS_LINUX     = ON
+  -- ALLOW_OPENBLAS_MACOS      = OFF
+  -- ALLOW_BLAS_LAPACK_MACOS   = OFF
+  -- BUILD_SMOKE_TEST          = ON
+  --
+  -- *** Looking for external libraries
+  -- Found OpenBLAS: /usr/lib/x86_64-linux-gnu/libopenblas.so
+  -- Found BLAS: /usr/lib/x86_64-linux-gnu/libblas.so
+  -- Found LAPACK: /usr/lib/x86_64-linux-gnu/liblapack.so
+  -- FlexiBLAS_FOUND = NO
+  --       MKL_FOUND = NO
+  --  OpenBLAS_FOUND = YES
+  --     ATLAS_FOUND = NO
+  --      BLAS_FOUND = YES
+  --    LAPACK_FOUND = YES
+  --
+  -- *** NOTE: found both OpenBLAS and BLAS; BLAS will not be used
+  --
+  -- *** NOTE: if OpenBLAS is known to provide LAPACK functions, recommend to
+  -- *** NOTE: rerun cmake with the OPENBLAS_PROVIDES_LAPACK option enabled:
+  -- *** NOTE: cmake -D OPENBLAS_PROVIDES_LAPACK=true .
+  --
+  -- *** If the OpenBLAS library is installed in
+  -- *** /usr/local/lib or /usr/local/lib64
+  -- *** make sure the run-time linker can find it.
+  -- *** On Linux systems this can be done by editing /etc/ld.so.conf
+  -- *** or modifying the LD_LIBRARY_PATH environment variable.
+  --
+  -- Found ARPACK: /usr/lib/x86_64-linux-gnu/libarpack.so
+  -- ARPACK_FOUND = YES
+  -- Looking for SuperLU version 5
+  -- Found SuperLU: /usr/lib/x86_64-linux-gnu/libsuperlu.so
+  -- SuperLU_FOUND = YES
+  -- SuperLU_INCLUDE_DIR = /usr/include/superlu
+  --
+  -- *** Result of configuration:
+  -- *** ARMA_USE_WRAPPER    = true
+  -- *** ARMA_USE_LAPACK     = true
+  -- *** ARMA_USE_BLAS       = true
+  -- *** ARMA_USE_ATLAS      = false
+  -- *** ARMA_USE_ARPACK     = true
+  -- *** ARMA_USE_EXTERN_RNG = true
+  -- *** ARMA_USE_SUPERLU    = true
+  --
+  -- *** Armadillo wrapper library will use the following libraries:
+  -- *** ARMA_LIBS = /usr/lib/x86_64-linux-gnu/libopenblas.so;/usr/lib/x86_64-linux-gnu/liblapack.so;/usr/lib/x86_64-linux-gnu/libarpack.so;/usr/lib/x86_64-linux-gnu/libsuperlu.so
+  --
+  -- 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_SHARED_LINKER_FLAGS =  -Wl,--no-as-needed
+  -- CMAKE_REQUIRED_INCLUDES   = /usr/include;/usr/include/superlu
+  --
+  -- CMAKE_INSTALL_PREFIX     = /usr
+  -- CMAKE_INSTALL_LIBDIR     = lib/x86_64-linux-gnu
+  -- CMAKE_INSTALL_INCLUDEDIR = include
+  -- CMAKE_INSTALL_DATADIR    = share
+  -- CMAKE_INSTALL_BINDIR     = bin
+  -- Generating '/ns-3-dev/cmake-build-release/_deps/armadillo-build/ArmadilloConfig.cmake'
+  -- Generating '/ns-3-dev/cmake-build-release/_deps/armadillo-build/ArmadilloConfigVersion.cmake'
+  -- Generating '/ns-3-dev/cmake-build-release/_deps/armadillo-build/InstallFiles/ArmadilloConfig.cmake'
+  -- Generating '/ns-3-dev/cmake-build-release/_deps/armadillo-build/InstallFiles/ArmadilloConfigVersion.cmake'
+  -- Copying /ns-3-dev/cmake-build-release/_deps/armadillo-src/misc/ to /ns-3-dev/cmake-build-release/_deps/armadillo-build/tmp/misc/
+  -- Generating '/ns-3-dev/cmake-build-release/_deps/armadillo-build/tmp/misc/armadillo.pc'
+  -- *** configuring smoke_test
+  -- Armadillo was found? TRUE
+  ...
+
+As shown above, the Armadillo library gets installed by CPM
+and it can be found by CMake's ``find_package`` function.
+Differently from other packages found via ``find_package``,
+CPM creates native CMake targets from the subprojects.
+In the case of Armadillo, the target is called ``armadillo``,
+which we can link to our targets.
+
+.. sourcecode:: cmake
+
+    # Install Armadillo
+    CPMAddPackage(
+        NAME ARMADILLO
+        GIT_TAG 6cada351248c9a967b137b9fcb3d160dad7c709b
+        GIT_REPOSITORY https://gitlab.com/conradsnicta/armadillo-code.git
+    )
+    find_package(Armadillo) # Loads CPM installation of Armadillo
+    message(STATUS "Armadillo was found? ${ARMADILLO_FOUND}")
 
+    # CPM is kind of jenky. It could get the ARMADILLO_INCLUDE_DIRS
+    # from the ArmadilloConfig.cmake file in ${CMAKE_BINARY_DIR}/_deps/armadillo-build,
+    # but it doesn't... So add its include directories directly from the source directory
+    include_directories(${CMAKE_BINARY_DIR}/_deps/armadillo-src/include)
+
+    # Link to Armadillo and
+    link_libraries(armadillo)
+
+.. _`CPM's examples`: https://github.com/cpm-cmake/CPM.cmake/wiki/More-Snippets
+
+Note: using CPM can be challenging. Users are recommended
+to look at `CPM's examples`_.
+
+For example, the libraries of installed packages will be placed by default in
+the ``ns-3-dev/build/lib`` directory. On the other hand, header placement depends
+on how the CMake project was setup.
+
+If the package CMakeLists.txt was made to build in-source, headers will be
+along the source files, which will be placed in
+``${PROJECT_BINARY_DIR}/_deps/packageName-src``. When configured with the
+ns3 script, ``PROJECT_BINARY_DIR corresponds`` to ``ns-3-dev/cmake-cache``.
+
+If the package CMakeLists.txt copies the headers to an output directory
+(like ns-3 does), it will be placed in
+``${PROJECT_BINARY_DIR}/_deps/packageName-build``,
+possibly in an ``include`` subdirectory.
+
+In case it was configured to copy the headers to ``${CMAKE_BINARY_DIR}/include``,
+the headers will land on ``${PROJECT_BINARY_DIR}/include`` of the most top-level
+project. In our case, the top-level project is the NS3 project.
+
+Since the packages get installed into the ns-3 cache directory
+(``PROJECT_BINARY_DIR``), using ``./ns3 clean`` will delete them,
+requiring them to be rebuilt.
 
 Inclusion of options
 ++++++++++++++++++++
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/models/Makefile ns-3.40/doc/models/Makefile
--- ns-3.39/doc/models/Makefile	2023-07-05 14:23:47.633426700 -0700
+++ ns-3.40/doc/models/Makefile	2023-09-27 13:30:37.570839000 -0700
@@ -360,7 +360,13 @@
 	$(SRC)/lr-wpan/doc/lr-wpan-primitives.dia \
 	$(SRC)/lr-wpan/doc/802-15-4-ber.eps \
 	$(SRC)/lr-wpan/doc/802-15-4-per-sens.eps \
-	$(SRC)/lr-wpan/doc/802-15-4-psr-distance.eps
+	$(SRC)/lr-wpan/doc/802-15-4-psr-distance.eps \
+	$(SRC)/energy/doc/figures/dischargeCurve.png \
+	$(SRC)/energy/doc/figures/energyFramework.dia \
+	$(SRC)/energy/doc/figures/leadacid.png \
+	$(SRC)/energy/doc/figures/liion.png \
+	$(SRC)/energy/doc/figures/nicd.png \
+	$(SRC)/energy/doc/figures/nimh.png
 
 # specify figures from which .png and .pdf figures need to be
 # generated (all dia and eps figures)
@@ -457,6 +463,7 @@
 	$(FIGURES)/802-15-4-ber.eps \
 	$(FIGURES)/802-15-4-per-sens.eps \
 	$(FIGURES)/802-15-4-psr-distance.eps \
+	$(FIGURES)/energyFramework.eps \
 	$(FIGURES)/clear-channel.eps \
 	$(FIGURES)/assoc-manager.eps \
 	$(FIGURES)/nist-frame-success-rate.eps \
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/models/source/conf.py ns-3.40/doc/models/source/conf.py
--- ns-3.39/doc/models/source/conf.py	2023-07-05 14:23:47.633426700 -0700
+++ ns-3.40/doc/models/source/conf.py	2023-09-27 13:30:55.802883400 -0700
@@ -73,9 +73,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = u'ns-3.39'
+version = u'ns-3.40'
 # The full version, including alpha/beta/rc tags.
-release = u'ns-3.39'
+release = u'ns-3.40'
 
 # 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.39/doc/models/source/index.rst ns-3.40/doc/models/source/index.rst
--- ns-3.39/doc/models/source/index.rst	2023-07-05 14:23:47.633426700 -0700
+++ ns-3.40/doc/models/source/index.rst	2023-09-27 13:30:37.570839000 -0700
@@ -25,6 +25,7 @@
 
 .. toctree::
    :maxdepth: 1
+   :numbered:
 
    organization
    animation
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/ns3_html_theme/layout.html ns-3.40/doc/ns3_html_theme/layout.html
--- ns-3.39/doc/ns3_html_theme/layout.html	2023-07-05 14:23:47.633426700 -0700
+++ ns-3.40/doc/ns3_html_theme/layout.html	2023-09-27 13:30:37.574838900 -0700
@@ -38,7 +38,7 @@
             <td id="projectlogo">
               <a id="ns3_home1"
                  href="http://www.nsnam.org/">
-                 <img alt="ns-3 Logo"
+                 <img alt="ns-3 Logo" style="background-color: unset;"
                       src="{{ pathto('_static/' + theme_logo, 1)}}"/>
               </a>
             </td>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/ns3_html_theme/static/ns3_stylesheet.css ns-3.40/doc/ns3_html_theme/static/ns3_stylesheet.css
--- ns-3.39/doc/ns3_html_theme/static/ns3_stylesheet.css	2023-07-05 14:23:47.633426700 -0700
+++ ns-3.40/doc/ns3_html_theme/static/ns3_stylesheet.css	2023-09-27 13:30:37.574838900 -0700
@@ -5,36 +5,14 @@
 div,
 p,
 dl {
-  color: black;
-  font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
-  font-size: 12px;
-}
-
-/* Dark mode is not supported in Doxygen versions earlier than 1.9.6 */
-@media (prefers-color-scheme: dark) {
-  body,
-  table,
-  div,
-  p,
-  dl,
-  div.body,
-  div.sphinxsidebar h3,
-  div.sphinxsidebar h4 ,
-  div.sphinxsidebar h3 a{
-    color: ivory;
-    background:black;
-  }
-  div.sphinxsidebar input{
-    background: #2c2d24;
-  }
-  div.related{
-    background-image: linear-gradient(to bottom, #66696a 0%, transparent 80%);
-  }
+    color: black;
+    font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
+    font-size: 12px;
 }
 
 a {
-  color: #91A501;
-  font-weight: bold;
+    color: #91A501;
+    font-weight: bold;
 }
 
 /* Sphinx headings */
@@ -51,16 +29,16 @@
 
 /* Sphinx figure captions */
 p.caption {
-  font-weight: bold;
+    font-weight: bold;
 }
 
 /* Doxygen side bar */
 #nav-tree {
-  font-size: 12px;
+    font-size: 12px;
 }
 
 #nav-tree a {
-  font-weight: normal;
+    font-weight: normal;
 }
 
 /* Sphinx nav links bar (relbar) */
@@ -71,87 +49,87 @@
 */
 
 div.related h3 {
-  display: none;
+    display: none;
 }
 
 div.related a {
-  color: #91A501;
-  font-size: 14px;
-  font-weight: bold;
+    color: #91A501;
+    font-size: 14px;
+    font-weight: bold;
 }
 
 div.related li {
-  background-image: url('bc_s.png');
-  background-position: 100% 40%;
-  background-repeat: no-repeat;
-  padding-left: 10px;
-  padding-right: 15px;
+    background-image: url('bc_s.png');
+    background-position: 100% 40%;
+    background-repeat: no-repeat;
+    padding-left: 10px;
+    padding-right: 15px;
 }
 
 div.related li.right {
-  background-image: none;
-  padding-left: 0px;
-  padding-right: 0px;
+    background-image: none;
+    padding-left: 0px;
+    padding-right: 0px;
 }
 
 /* Sphinx side bar */
 div.sphinxsidebar {
-  font-size: 12px;
+    font-size: 12px;
 }
 
 div.sphinxsidebar a {
-  font-weight: normal;
+    font-weight: normal;
 }
 
 
 /* Title bar elements */
 
 #titlearea {
-  background-image: url('bar-top.png');
-  background-repeat: repeat;
-  border-bottom: 1px solid #5B5B5B;
-  color: white;
-  position: relative;
-  /* Doxygen tab bar ("Main Page", "Related Pages"..) is at z: 9999 */
-  z-index: 10000;
+    background-image: url('bar-top.png');
+    background-repeat: repeat;
+    border-bottom: 1px solid #5B5B5B;
+    color: white;
+    position: relative;
+    /* Doxygen tab bar ("Main Page", "Related Pages"..) is at z: 9999 */
+    z-index: 10000;
 }
 
 #projectlogo {
-  color: white;
-  margin: 10px;
-  text-align: center;
-  vertical-align: middle;
-  width: 220px;
+    color: white;
+    margin: 10px;
+    text-align: center;
+    vertical-align: middle;
+    width: 220px;
 }
 
 #projecttext {
-  text-align: left;
-  color: white;
-  padding-left: 2em;
-  width: 250px;
+    text-align: left;
+    color: white;
+    padding-left: 2em;
+    width: 250px;
 }
 
 #projectbrief {
-  color: white;
-  font: 120% Tahoma, Arial, sans-serif;
-  margin: 0px;
-  padding: 0px;
+    color: white;
+    font: 120% Tahoma, Arial, sans-serif;
+    margin: 0px;
+    padding: 0px;
 }
 
 #projectnumber {
-  color: white;
-  font: 100% Tahoma, Arial, sans-serif;
-  margin: 0px;
-  padding: 0px;
+    color: white;
+    font: 100% Tahoma, Arial, sans-serif;
+    margin: 0px;
+    padding: 0px;
 }
 
 #projectsection {
-  color: white;
-  font: 24pt Aldo, Tahoma, Arial, sans-serif;
-  margin-right: 10px;
-  margin: 10px;
-  text-align: right;
-  vertical-align: middle;
+    color: white;
+    font: 24pt Aldo, Tahoma, Arial, sans-serif;
+    margin-right: 10px;
+    margin: 10px;
+    text-align: right;
+    vertical-align: middle;
 }
 
 /*
@@ -162,86 +140,217 @@
    */
 
 #ns3-menu .menu {
-  background-image: url('menu-bgr-400.png');
-  /*   background-origin: padding-box; */
-  /*   background-position: -10px 0; */
-  background-repeat: no-repeat;
-  background-size: 100% 39px;
-  display: table-cell;
-  float: left;
-  height: 40px;
-  margin: 0px 0px 0px 0px;
-  padding: 0px 0px 0px 0px;
-  vertical-align: middle;
+    background-image: url('menu-bgr-400.png');
+    /*   background-origin: padding-box; */
+    /*   background-position: -10px 0; */
+    background-repeat: no-repeat;
+    background-size: 100% 39px;
+    display: table-cell;
+    float: left;
+    height: 40px;
+    margin: 0px 0px 0px 0px;
+    padding: 0px 0px 0px 0px;
+    vertical-align: middle;
 }
 
 
 #ns3-menu .menu ul {
-  /*   float:left; */
-  height: 40;
-  list-style: none;
-  margin: 0px 0px 0px -2px;
-  /*   overflow:hidden; */
-  padding: 0px 0px 0px 0px;
-  z-index: 30;
+    /*   float:left; */
+    height: 40;
+    list-style: none;
+    margin: 0px 0px 0px -2px;
+    /*   overflow:hidden; */
+    padding: 0px 0px 0px 0px;
+    z-index: 30;
 }
 
 #ns3-menu .menu ul li {
-  background-image: url('ver.png');
-  background-origin: padding-box;
-  background-position: 0 11px;
-  background-repeat: no-repeat;
-  color: #ffffff;
-  float: left;
-  font-family: Aldo, Tahoma, Arial, sans-serif;
-  font-size: 14px;
-  /*   height:40px; */
-  margin: 0px 0px 0px 0px;
-  /*   overflow:hidden; */
-  padding: 11px 13px 0px 12px;
-  text-transform: uppercase;
+    background-image: url('ver.png');
+    background-origin: padding-box;
+    background-position: 0 11px;
+    background-repeat: no-repeat;
+    color: #ffffff;
+    float: left;
+    font-family: Aldo, Tahoma, Arial, sans-serif;
+    font-size: 14px;
+    /*   height:40px; */
+    margin: 0px 0px 0px 0px;
+    /*   overflow:hidden; */
+    padding: 11px 13px 0px 12px;
+    text-transform: uppercase;
 }
 
 #ns3-menu .menu ul li a {
-  color: #ffffff;
-  /* cursor: pointer; */
-  display: block;
-  float: left;
-  font-weight: normal;
-  /* default anchors are bold */
-  text-decoration: none;
-  /* default anchors are underlined */
+    color: #ffffff;
+    /* cursor: pointer; */
+    display: block;
+    float: left;
+    font-weight: normal;
+    /* default anchors are bold */
+    text-decoration: none;
+    /* default anchors are underlined */
 }
 
 #ns3-menu .menu ul li a:hover {
-  color: #cadc48;
-  text-decoration: none;
-  /* don't add underline on hover */
+    color: #cadc48;
+    text-decoration: none;
+    /* don't add underline on hover */
 }
 
 #ns3-menu .menu div {
-  background: #94A901;
-  background-size: 100%;
-  color: #ffffff;
-  position: absolute;
-  visibility: hidden;
+    background: #94A901;
+    background-size: 100%;
+    color: #ffffff;
+    position: absolute;
+    visibility: hidden;
 }
 
 #ns3-menu .menu div a {
-  position: relative;
-  display: block;
-  float: left;
-  font-family: Aldo, Tahoma, Arial, sans-serif;
-  font-size: 14px;
-  margin: 0;
-  padding: 5px 10px;
-  text-align: left;
-  width: auto;
-  white-space: nowrap;
+    position: relative;
+    display: block;
+    float: left;
+    font-family: Aldo, Tahoma, Arial, sans-serif;
+    font-size: 14px;
+    margin: 0;
+    padding: 5px 10px;
+    text-align: left;
+    width: auto;
+    white-space: nowrap;
 }
 
 #ns3-menu .menu div a:hover {
-  color: #cadc48;
-  text-decoration: none;
-  /* don't add underline on hover */
+    color: #cadc48;
+    text-decoration: none;
+    /* don't add underline on hover */
+}
+
+/* Dark mode is not supported in Doxygen versions earlier than 1.9.6 */
+@media (prefers-color-scheme: dark) {
+    a {
+        color: #cfde63;
+    }
+
+    a:visited {
+        color: #91A501;
+    }
+
+    body,
+    table,
+    div,
+    p,
+    dl,
+    div.body,
+    div.sphinxsidebar h3,
+    div.sphinxsidebar h4,
+    div.sphinxsidebar h3 a {
+        color: ivory;
+        background: #2f2f2f;
+    }
+
+    div.related a,
+    div.sphinxsidebar a {
+        color: #cfde63;
+    }
+
+    div.sphinxsidebar input {
+        background: #2c2d24;
+    }
+
+    div.note {
+        background-color: unset;
+    }
+
+    div.related {
+        background-image: linear-gradient(to bottom, #66696a 0%, transparent 80%);
+    }
+
+    th {
+        background-color: #483448;
+    }
+
+    th p {
+        background-color: transparent;
+    }
+
+    .highlight {
+        background-color: #424e20;
+    }
+
+    .highlight .c,
+    .highlight .c1,
+    .highlight .ch,
+    .highlight .cm,
+    .highlight .cpf {
+        color: #79a6b2;
+    }
+
+    .highlight .fm,
+    .highlight .nf {
+        color: #82abdb;
+    }
+
+    .highlight .gi {
+        color: #65df65;
+    }
+
+    .highlight .go {
+        color: #b6b2ad;
+    }
+
+    .highlight .m,
+    .highlight .mf,
+    .highlight .mh,
+    .highlight .mi {
+        color: #7ec6a2;
+    }
+
+    .highlight .cp,
+    .highlight .k,
+    .highlight .kn,
+    .highlight .nb {
+        color: #7edf9a;
+    }
+
+    .highlight .kt {
+        color: #df876d;
+    }
+
+    .highlight .nn {
+        color: unset;
+    }
+
+    .highlight .nt {
+        color: #87afdb;
+    }
+
+    .highlight .s,
+    .highlight .s1,
+    .highlight .s2 {
+        color: #7c9cb7;
+    }
+
+    .highlight .ss {
+        color: #adcc80;
+    }
+
+    .highlight .nc {
+        color: #5db1d5;
+    }
+
+    .highlight .nv {
+        color: #ae6dc1;
+    }
+
+    .highlight .o {
+        color: #9e9890;
+    }
+
+    pre {
+        color: #ceccca;
+    }
+
+    img {
+        background-color: #ceccca;
+        padding: 3px;
+    }
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/tutorial/pickle-to-xml.py ns-3.40/doc/tutorial/pickle-to-xml.py
--- ns-3.39/doc/tutorial/pickle-to-xml.py	2023-07-05 14:23:47.661426800 -0700
+++ ns-3.40/doc/tutorial/pickle-to-xml.py	2023-09-27 13:30:37.598839000 -0700
@@ -12,11 +12,11 @@
 import codecs
 
 def dump_pickles(out, dirname, filename, path):
-    f = open(os.path.join(dirname, filename), 'r')
-    data = pickle.load(f)
-    fragment_file = codecs.open(data['current_page_name'] + '.frag', mode='w', encoding='utf-8')
-    fragment_file.write(data['body'])
-    fragment_file.close()
+    with open(os.path.join(dirname, filename), 'r', encoding='utf-8') as f:
+        data = pickle.load(f)
+    with codecs.open(data['current_page_name'] + '.frag', mode='w', encoding='utf-8') as fragment_file:
+        fragment_file.write(data['body'])
+
     out.write('  <page url="%s">\n' % path)
     out.write('    <fragment>%s.frag</fragment>\n' % data['current_page_name'])
     if data['prev'] is not None:
@@ -28,12 +28,11 @@
                   (os.path.normpath(os.path.join(path, data['next']['link'])),
                    data['next']['title']))
     out.write('  </page>\n')
-    f.close()
+
     if data['next'] is not None:
         next_path = os.path.normpath(os.path.join(path, data['next']['link']))
         next_filename = os.path.basename(next_path) + '.fpickle'
         dump_pickles(out, dirname, next_filename, next_path)
-    return
 
 import sys
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/tutorial/source/conf.py ns-3.40/doc/tutorial/source/conf.py
--- ns-3.39/doc/tutorial/source/conf.py	2023-07-05 14:23:47.661426800 -0700
+++ ns-3.40/doc/tutorial/source/conf.py	2023-09-27 13:30:55.802883400 -0700
@@ -71,9 +71,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = u'ns-3.39'
+version = u'ns-3.40'
 # The full version, including alpha/beta/rc tags.
-release = u'ns-3.39'
+release = u'ns-3.40'
 
 # 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.39/doc/tutorial/source/getting-started.rst ns-3.40/doc/tutorial/source/getting-started.rst
--- ns-3.39/doc/tutorial/source/getting-started.rst	2023-07-05 14:23:47.661426800 -0700
+++ ns-3.40/doc/tutorial/source/getting-started.rst	2023-09-27 13:30:37.602839000 -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.39), the following tools
+As of the most recent |ns3| release (ns-3.40), 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.39.tar.bz2
-  $ tar xjf ns-allinone-3.39.tar.bz2
+  $ wget https://www.nsnam.org/release/ns-allinone-3.40.tar.bz2
+  $ tar xjf ns-allinone-3.40.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.39``, you should see a number of files and directories
+``ns-allinone-3.40``, you should see a number of files and directories
 
 .. sourcecode:: text
 
-  $ cd ns-allinone-3.39
+  $ cd ns-allinone-3.40
   $ ls
-  bake  build.py  constants.py  netanim-3.109 ns-3.39  README.md  util.py
+  bake  build.py  constants.py  netanim-3.109 ns-3.40  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.39
+  $ python3 download.py -n ns-3.40
 
 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.39``:  the code corresponding to the release
+1.  ``ns-3.40``:  the code corresponding to the release
 2.  ``ns-3-dev``:  a similar module but using the development code tree
-3.  ``ns-allinone-3.39``:  the module that includes other optional features
+3.  ``ns-allinone-3.40``:  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.39``.
+this tutorial example with ``ns-3.40``.
 
 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.39
+  $ ./bake.py configure -e ns-allinone-3.40
 
 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.39 (target directory:ns-3.39) - OK
+  >> Downloading ns-3.40 (target directory:ns-3.40) - 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.39  openflow-dev
+  BRITE  click-ns-3.37  netanim-3.109  ns-3.40  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.39`` under your ``~/workspace`` directory.
+``ns-allinone-3.40`` under your ``~/workspace`` directory.
 Type the following:
 
 .. sourcecode:: console
@@ -419,7 +419,7 @@
 .. sourcecode:: text
 
   >> Building netanim-3.109 - OK
-  >> Building ns-3.39 - OK
+  >> Building ns-3.40 - OK
 
 There may be failures to build all components, but the build will proceed
 anyway if the component is optional.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/tutorial/source/index.rst ns-3.40/doc/tutorial/source/index.rst
--- ns-3.39/doc/tutorial/source/index.rst	2023-07-05 14:23:47.661426800 -0700
+++ ns-3.40/doc/tutorial/source/index.rst	2023-09-27 13:30:37.602839000 -0700
@@ -24,6 +24,7 @@
 
 .. toctree::
    :maxdepth: 2
+   :numbered:
 
    quick-start
    introduction
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/tutorial/source/quick-start.rst ns-3.40/doc/tutorial/source/quick-start.rst
--- ns-3.39/doc/tutorial/source/quick-start.rst	2023-07-05 14:23:47.661426800 -0700
+++ ns-3.40/doc/tutorial/source/quick-start.rst	2023-09-27 13:30:37.602839000 -0700
@@ -64,13 +64,13 @@
 
    ::
 
-    $ tar xjf ns-allinone-3.39.tar.bz2
+    $ tar xjf ns-allinone-3.40.tar.bz2
 
 3) Change into the |ns3| directory directly; e.g.
 
    ::
 
-    $ cd ns-allinone-3.39/ns-3.39
+    $ cd ns-allinone-3.40/ns-3.40
 
 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.39 as of this
+If instead you want to try the most recent release (version 3.40 as of this
 writing), you can checkout a branch corresponding to that git tag:
 
 ::
 
-  $ git checkout -b ns-3.39-branch ns-3.39
+  $ git checkout -b ns-3.40-branch ns-3.40
 
 Building and testing ns-3
 *************************
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/doc/tutorial/source/tracing.rst ns-3.40/doc/tutorial/source/tracing.rst
--- ns-3.39/doc/tutorial/source/tracing.rst	2023-07-05 14:23:47.665426700 -0700
+++ ns-3.40/doc/tutorial/source/tracing.rst	2023-09-27 13:30:37.602839000 -0700
@@ -1463,8 +1463,8 @@
 
 Previous versions of |ns3| declared a custom application called ``MyApp``
 for use in this program.  Current versions of |ns3| have moved this to
-a separate header file (``tutorial-app.h'') and implementation file
-(``tutorial-app.cc'').  This simple application allows the ``Socket''
+a separate header file (``tutorial-app.h``) and implementation file
+(``tutorial-app.cc``).  This simple application allows the ``Socket``
 to be created at configuration time.
 
 ::
@@ -1887,11 +1887,11 @@
 ~~~~~~~~~~~~
 
 The main function starts off by configuring the TCP type to use a legacy
-``NewReno`` congestion control variant, with what is called the ``classic''
+``NewReno`` congestion control variant, with what is called the ``classic``
 TCP loss recovery mechanism.  When this tutorial program was originally
 written, these were the default TCP configurations, but over time,
 |ns3| TCP has evolved to use the current Linux TCP defaults of ``Cubic``
-and ``Prr'' loss recovery.  The first statements also configure the
+and ``Prr`` loss recovery.  The first statements also configure the
 command-line argument processing.
 
 ::
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/channel-models/three-gpp-v2v-channel-example.cc ns-3.40/examples/channel-models/three-gpp-v2v-channel-example.cc
--- ns-3.39/examples/channel-models/three-gpp-v2v-channel-example.cc	2023-07-05 14:23:47.665426700 -0700
+++ ns-3.40/examples/channel-models/three-gpp-v2v-channel-example.cc	2023-09-27 13:30:37.602839000 -0700
@@ -161,7 +161,7 @@
         return;
     }
     uint32_t index = 0;
-    for (BuildingList::Iterator it = BuildingList::Begin(); it != BuildingList::End(); ++it)
+    for (auto it = BuildingList::Begin(); it != BuildingList::End(); ++it)
     {
         ++index;
         Box box = (*it)->GetBoundaries();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/energy/energy-model-example.cc ns-3.40/examples/energy/energy-model-example.cc
--- ns-3.39/examples/energy/energy-model-example.cc	2023-07-05 14:23:47.665426700 -0700
+++ ns-3.40/examples/energy/energy-model-example.cc	2023-09-27 13:30:37.602839000 -0700
@@ -289,9 +289,7 @@
     Simulator::Stop(Seconds(10.0));
     Simulator::Run();
 
-    for (DeviceEnergyModelContainer::Iterator iter = deviceModels.Begin();
-         iter != deviceModels.End();
-         iter++)
+    for (auto iter = deviceModels.Begin(); iter != deviceModels.End(); iter++)
     {
         double energyConsumed = (*iter)->GetTotalEnergyConsumption();
         NS_LOG_UNCOND("End of simulation ("
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/energy/energy-model-with-harvesting-example.cc ns-3.40/examples/energy/energy-model-with-harvesting-example.cc
--- ns-3.39/examples/energy/energy-model-with-harvesting-example.cc	2023-07-05 14:23:47.665426700 -0700
+++ ns-3.40/examples/energy/energy-model-with-harvesting-example.cc	2023-09-27 13:30:37.602839000 -0700
@@ -354,9 +354,7 @@
     Simulator::Stop(Seconds(10.0));
     Simulator::Run();
 
-    for (DeviceEnergyModelContainer::Iterator iter = deviceModels.Begin();
-         iter != deviceModels.End();
-         iter++)
+    for (auto iter = deviceModels.Begin(); iter != deviceModels.End(); iter++)
     {
         double energyConsumed = (*iter)->GetTotalEnergyConsumption();
         NS_LOG_UNCOND("End of simulation ("
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/ipv6/radvd-two-prefix.cc ns-3.40/examples/ipv6/radvd-two-prefix.cc
--- ns-3.39/examples/ipv6/radvd-two-prefix.cc	2023-07-05 14:23:47.665426700 -0700
+++ ns-3.40/examples/ipv6/radvd-two-prefix.cc	2023-09-27 13:30:37.602839000 -0700
@@ -164,8 +164,7 @@
     routerInterface->SetMaxRtrAdvInterval(2000);
     routerInterface->SetMinRtrAdvInterval(1000);
     RadvdInterface::RadvdPrefixList prefixList = routerInterface->GetPrefixes();
-    for (RadvdInterface::RadvdPrefixListI iter = prefixList.begin(); iter != prefixList.end();
-         iter++)
+    for (auto iter = prefixList.begin(); iter != prefixList.end(); iter++)
     {
         (*iter)->SetPreferredLifeTime(3);
         (*iter)->SetValidLifeTime(5);
@@ -179,8 +178,7 @@
     routerInterface->SetMaxRtrAdvInterval(2000);
     routerInterface->SetMinRtrAdvInterval(1000);
     prefixList = routerInterface->GetPrefixes();
-    for (RadvdInterface::RadvdPrefixListI iter = prefixList.begin(); iter != prefixList.end();
-         iter++)
+    for (auto iter = prefixList.begin(); iter != prefixList.end(); iter++)
     {
         (*iter)->SetPreferredLifeTime(3);
         (*iter)->SetValidLifeTime(5);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/matrix-topology/matrix-topology.cc ns-3.40/examples/matrix-topology/matrix-topology.cc
--- ns-3.39/examples/matrix-topology/matrix-topology.cc	2023-07-05 14:23:47.665426700 -0700
+++ ns-3.40/examples/matrix-topology/matrix-topology.cc	2023-09-27 13:30:37.602839000 -0700
@@ -163,7 +163,7 @@
     {
         for (size_t j = 0; j < Adj_Matrix[i].size(); j++)
         {
-            if (Adj_Matrix[i][j] == 1)
+            if (Adj_Matrix[i][j])
             {
                 NodeContainer n_links = NodeContainer(nodes.Get(i), nodes.Get(j));
                 NetDeviceContainer n_devs = p2p.Install(n_links);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/routing/global-routing-multi-switch-plus-router.cc ns-3.40/examples/routing/global-routing-multi-switch-plus-router.cc
--- ns-3.39/examples/routing/global-routing-multi-switch-plus-router.cc	2023-07-05 14:23:47.665426700 -0700
+++ ns-3.40/examples/routing/global-routing-multi-switch-plus-router.cc	2023-09-27 13:30:37.602839000 -0700
@@ -350,9 +350,7 @@
             }
         }
 
-        for (std::vector<std::string>::const_iterator ploc = pcapLocationVec.begin();
-             ploc != pcapLocationVec.end();
-             ++ploc)
+        for (auto ploc = pcapLocationVec.begin(); ploc != pcapLocationVec.end(); ++ploc)
         {
             NS_LOG_INFO("PCAP capture at: <" + *ploc + ">");
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/tcp/tcp-pacing.cc ns-3.40/examples/tcp/tcp-pacing.cc
--- ns-3.39/examples/tcp/tcp-pacing.cc	2023-07-05 14:23:47.665426700 -0700
+++ ns-3.40/examples/tcp/tcp-pacing.cc	2023-09-27 13:30:37.606839000 -0700
@@ -161,7 +161,7 @@
     Time simulationEndTime = Seconds(5);
     DataRate bottleneckBandwidth("10Mbps"); // value of x as shown in the above network topology
     Time bottleneckDelay = MilliSeconds(40);
-    DataRate regLinkBandwidth = DataRate(4 * bottleneckBandwidth.GetBitRate());
+    DataRate regLinkBandwidth(4 * bottleneckBandwidth.GetBitRate());
     Time regLinkDelay = MilliSeconds(5);
     DataRate maxPacingRate("4Gbps");
 
@@ -324,9 +324,7 @@
     monitor->CheckForLostPackets();
     Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier>(flowmon.GetClassifier());
     FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats();
-    for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin();
-         i != stats.end();
-         ++i)
+    for (auto i = stats.begin(); i != stats.end(); ++i)
     {
         Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(i->first);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/examples-to-run.py ns-3.40/examples/wireless/examples-to-run.py
--- ns-3.39/examples/wireless/examples-to-run.py	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/examples-to-run.py	2023-09-27 13:30:37.606839000 -0700
@@ -60,7 +60,7 @@
     ("wifi-eht-network --simulationTime=0.1 --frequency=5 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=547", "True", "True"),
     ("wifi-eht-network --simulationTime=0.1 --frequency=2.4 --useRts=0 --useExtendedBlockAck=1 --frequency2=5 --minExpectedThroughput=12 --maxExpectedThroughput=500", "True", "True"),
     ("wifi-eht-network --simulationTime=0.1 --frequency=2.4 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=212", "True", "True"),
-    ("wifi-eht-network --simulationTime=0.22 --udp=0 --downlink=1 --useRts=0 --nStations=4 --dlAckType=ACK-SU-FORMAT --enableUlOfdma=1 --enableBsrp=0 --mcs=4 --frequency2=6  --minExpectedThroughput=35 --maxExpectedThroughput=280", "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=4 --frequency2=6  --minExpectedThroughput=35 --maxExpectedThroughput=280", "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 --useExtendedBlockAck=1 --minExpectedThroughput=40 --maxExpectedThroughput=100", "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", "True", "True"),
     ("wifi-eht-network --simulationTime=0.2 --udp=1 --downlink=0 --useRts=0 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --muSchedAccessReqInterval=50ms --frequency2=6 --minExpectedThroughput=70 --maxExpectedThroughput=715", "True", "True"),
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-80211e-txop.cc ns-3.40/examples/wireless/wifi-80211e-txop.cc
--- ns-3.39/examples/wireless/wifi-80211e-txop.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-80211e-txop.cc	2023-09-27 13:30:37.606839000 -0700
@@ -96,8 +96,8 @@
     uint32_t payloadSize = 1472; // bytes
     double simulationTime = 10;  // seconds
     double distance = 5;         // meters
-    bool enablePcap = 0;
-    bool verifyResults = 0; // used for regression
+    bool enablePcap = false;
+    bool verifyResults = false; // used for regression
     Time txopLimit = MicroSeconds(4096);
 
     CommandLine cmd(__FILE__);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-aggregation.cc ns-3.40/examples/wireless/wifi-aggregation.cc
--- ns-3.39/examples/wireless/wifi-aggregation.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-aggregation.cc	2023-09-27 13:30:37.606839000 -0700
@@ -84,9 +84,9 @@
     uint32_t payloadSize = 1472; // bytes
     double simulationTime = 10;  // seconds
     double distance = 5;         // meters
-    bool enableRts = 0;
-    bool enablePcap = 0;
-    bool verifyResults = 0; // used for regression
+    bool enableRts = false;
+    bool enablePcap = false;
+    bool verifyResults = false; // used for regression
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("payloadSize", "Payload size in bytes", payloadSize);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-ap.py ns-3.40/examples/wireless/wifi-ap.py
--- ns-3.39/examples/wireless/wifi-ap.py	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-ap.py	2023-09-27 13:30:37.606839000 -0700
@@ -85,7 +85,7 @@
 def main(argv):
     ns.core.CommandLine().Parse(argv)
 
-    ns.network.Packet.EnablePrinting();
+    ns.network.Packet.EnablePrinting()
 
     wifi = ns.wifi.WifiHelper()
     mobility = ns.mobility.MobilityHelper()
@@ -110,7 +110,10 @@
 
     # setup stas.
     wifiMac.SetType("ns3::StaWifiMac",
-                    "Ssid", ns.wifi.SsidValue(ssid))
+                    "ActiveProbing",
+                    ns.core.BooleanValue(True),
+                    "Ssid",
+                    ns.wifi.SsidValue(ssid))
     staDevs = wifi.Install(wifiPhy, wifiMac, stas)
     # setup ap.
     wifiMac.SetType("ns3::ApWifiMac",
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-dsss-validation.cc ns-3.40/examples/wireless/wifi-dsss-validation.cc
--- ns-3.39/examples/wireless/wifi-dsss-validation.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-dsss-validation.cc	2023-09-27 13:30:37.606839000 -0700
@@ -35,7 +35,7 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t FrameSize = 1500; // bytes
+    uint32_t frameSizeBytes = 1500;
     std::ofstream file("frame-success-rate-dsss.plt");
 
     const std::vector<std::string> modes{
@@ -46,7 +46,7 @@
     };
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("FrameSize", "The frame size in bytes", FrameSize);
+    cmd.AddValue("FrameSize", "The frame size in bytes", frameSizeBytes);
     cmd.Parse(argc, argv);
 
     Gnuplot plot = Gnuplot("frame-success-rate-dsss.eps");
@@ -56,27 +56,27 @@
     Ptr<TableBasedErrorRateModel> table = CreateObject<TableBasedErrorRateModel>();
     WifiTxVector txVector;
 
-    for (uint32_t i = 0; i < modes.size(); i++)
+    uint32_t frameSizeBits = frameSizeBytes * 8;
+
+    for (const auto& mode : modes)
     {
-        std::cout << modes[i] << std::endl;
-        Gnuplot2dDataset dataset(modes[i]);
-        txVector.SetMode(modes[i]);
+        std::cout << mode << std::endl;
+        Gnuplot2dDataset dataset(mode);
+        txVector.SetMode(mode);
+
+        WifiMode wifiMode(mode);
 
-        for (double snr = -10.0; snr <= 20.0; snr += 0.1)
+        for (double snrDb = -10.0; snrDb <= 20.0; snrDb += 0.1)
         {
-            double psYans = yans->GetChunkSuccessRate(WifiMode(modes[i]),
-                                                      txVector,
-                                                      std::pow(10.0, snr / 10.0),
-                                                      FrameSize * 8);
+            double snr = std::pow(10.0, snrDb / 10.0);
+
+            double psYans = yans->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (psYans < 0.0 || psYans > 1.0)
             {
                 // error
                 exit(1);
             }
-            double psNist = nist->GetChunkSuccessRate(WifiMode(modes[i]),
-                                                      txVector,
-                                                      std::pow(10.0, snr / 10.0),
-                                                      FrameSize * 8);
+            double psNist = nist->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (psNist < 0.0 || psNist > 1.0)
             {
                 std::cout << psNist << std::endl;
@@ -87,10 +87,7 @@
             {
                 exit(1);
             }
-            double psTable = table->GetChunkSuccessRate(WifiMode(modes[i]),
-                                                        txVector,
-                                                        std::pow(10.0, snr / 10.0),
-                                                        FrameSize * 8);
+            double psTable = table->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (psTable < 0.0 || psTable > 1.0)
             {
                 std::cout << psTable << std::endl;
@@ -101,7 +98,7 @@
             {
                 exit(1);
             }
-            dataset.Add(snr, psYans);
+            dataset.Add(snrDb, psYans);
         }
 
         plot.AddDataset(dataset);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-error-models-comparison.cc ns-3.40/examples/wireless/wifi-error-models-comparison.cc
--- ns-3.39/examples/wireless/wifi-error-models-comparison.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-error-models-comparison.cc	2023-09-27 13:30:37.606839000 -0700
@@ -86,66 +86,61 @@
     mode << format << "Mcs" << +endMcs;
     modes.push_back(mode.str());
 
-    for (uint32_t i = 0; i < modes.size(); i++)
+    for (const auto& mode : modes)
     {
-        std::cout << modes[i] << std::endl;
-        Gnuplot2dDataset yansdataset(modes[i]);
-        Gnuplot2dDataset nistdataset(modes[i]);
-        Gnuplot2dDataset tabledataset(modes[i]);
-        txVector.SetMode(modes[i]);
+        std::cout << mode << std::endl;
+        Gnuplot2dDataset yansdataset(mode);
+        Gnuplot2dDataset nistdataset(mode);
+        Gnuplot2dDataset tabledataset(mode);
+        txVector.SetMode(mode);
 
-        for (double snr = -5.0; snr <= (endMcs * 5); snr += 0.1)
+        WifiMode wifiMode(mode);
+
+        for (double snrDb = -5.0; snrDb <= (endMcs * 5); snrDb += 0.1)
         {
-            double ps = yans->GetChunkSuccessRate(WifiMode(modes[i]),
-                                                  txVector,
-                                                  std::pow(10.0, snr / 10.0),
-                                                  size);
+            double snr = std::pow(10.0, snrDb / 10.0);
+
+            double ps = yans->GetChunkSuccessRate(wifiMode, txVector, snr, size);
             if (ps < 0 || ps > 1)
             {
                 // error
                 exit(1);
             }
-            yansdataset.Add(snr, 1 - ps);
-            ps = nist->GetChunkSuccessRate(WifiMode(modes[i]),
-                                           txVector,
-                                           std::pow(10.0, snr / 10.0),
-                                           size);
+            yansdataset.Add(snrDb, 1 - ps);
+            ps = nist->GetChunkSuccessRate(wifiMode, txVector, snr, size);
             if (ps < 0 || ps > 1)
             {
                 // error
                 exit(1);
             }
-            nistdataset.Add(snr, 1 - ps);
-            ps = table->GetChunkSuccessRate(WifiMode(modes[i]),
-                                            txVector,
-                                            std::pow(10.0, snr / 10.0),
-                                            size);
+            nistdataset.Add(snrDb, 1 - ps);
+            ps = table->GetChunkSuccessRate(wifiMode, txVector, snr, size);
             if (ps < 0 || ps > 1)
             {
                 // error
                 exit(1);
             }
-            tabledataset.Add(snr, 1 - ps);
+            tabledataset.Add(snrDb, 1 - ps);
         }
 
         if (tableErrorModelEnabled)
         {
             std::stringstream ss;
-            ss << "Table-" << modes[i];
+            ss << "Table-" << mode;
             tabledataset.SetTitle(ss.str());
             plot.AddDataset(tabledataset);
         }
         if (yansErrorModelEnabled)
         {
             std::stringstream ss;
-            ss << "Yans-" << modes[i];
+            ss << "Yans-" << mode;
             yansdataset.SetTitle(ss.str());
             plot.AddDataset(yansdataset);
         }
         if (nistErrorModelEnabled)
         {
             std::stringstream ss;
-            ss << "Nist-" << modes[i];
+            ss << "Nist-" << mode;
             nistdataset.SetTitle(ss.str());
             plot.AddDataset(nistdataset);
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-hidden-terminal.cc ns-3.40/examples/wireless/wifi-hidden-terminal.cc
--- ns-3.39/examples/wireless/wifi-hidden-terminal.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-hidden-terminal.cc	2023-09-27 13:30:37.606839000 -0700
@@ -163,9 +163,7 @@
     monitor->CheckForLostPackets();
     Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier>(flowmon.GetClassifier());
     FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats();
-    for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin();
-         i != stats.end();
-         ++i)
+    for (auto i = stats.begin(); i != stats.end(); ++i)
     {
         // first 2 FlowIds are for ECHO apps, we don't want to display them
         //
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-ht-network.cc ns-3.40/examples/wireless/wifi-ht-network.cc
--- ns-3.39/examples/wireless/wifi-ht-network.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-ht-network.cc	2023-09-27 13:30:37.606839000 -0700
@@ -118,7 +118,7 @@
         double previous = 0;
         for (int channelWidth = 20; channelWidth <= 40;)
         {
-            for (int sgi = 0; sgi < 2; sgi++)
+            for (auto sgi : {false, true})
             {
                 uint32_t payloadSize; // 1500 byte IP packet
                 if (udp)
@@ -283,11 +283,11 @@
 
                 Simulator::Destroy();
 
-                std::cout << mcs << "\t\t\t" << channelWidth << " MHz\t\t\t" << sgi << "\t\t\t"
-                          << throughput << " Mbit/s" << std::endl;
+                std::cout << mcs << "\t\t\t" << channelWidth << " MHz\t\t\t" << std::boolalpha
+                          << sgi << "\t\t\t" << throughput << " Mbit/s" << std::endl;
 
                 // test first element
-                if (mcs == 0 && channelWidth == 20 && sgi == 0)
+                if (mcs == 0 && channelWidth == 20 && !sgi)
                 {
                     if (throughput < minExpectedThroughput)
                     {
@@ -295,7 +295,7 @@
                     }
                 }
                 // test last element
-                if (mcs == 7 && channelWidth == 40 && sgi == 1)
+                if (mcs == 7 && channelWidth == 40 && sgi)
                 {
                     if (maxExpectedThroughput > 0 && throughput > maxExpectedThroughput)
                     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-mixed-network.cc ns-3.40/examples/wireless/wifi-mixed-network.cc
--- ns-3.39/examples/wireless/wifi-mixed-network.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-mixed-network.cc	2023-09-27 13:30:37.610839000 -0700
@@ -370,7 +370,7 @@
     params.payloadSize = 1472;  // bytes
     params.simulationTime = 10; // seconds
 
-    bool verifyResults = 0; // used for regression
+    bool verifyResults = false; // used for regression
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("payloadSize", "Payload size in bytes", params.payloadSize);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-multirate.cc ns-3.40/examples/wireless/wifi-multirate.cc
--- ns-3.39/examples/wireless/wifi-multirate.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-multirate.cc	2023-09-27 13:30:37.610839000 -0700
@@ -116,7 +116,7 @@
      */
     bool IsRouting() const
     {
-        return (m_enableRouting == 1) ? 1 : 0;
+        return m_enableRouting;
     }
 
     /**
@@ -126,7 +126,7 @@
      */
     bool IsMobility() const
     {
-        return (m_enableMobility == 1) ? 1 : 0;
+        return m_enableMobility;
     }
 
     /**
@@ -239,7 +239,7 @@
     uint32_t m_gridSize;     //!< Grid size.
     uint32_t m_nodeDistance; //!< Node distance.
     uint32_t m_port;         //!< Listening port.
-    uint32_t m_scenario;     //!< Scnario number.
+    uint32_t m_scenario;     //!< Scenario number.
 
     bool m_enablePcap;     //!< True if PCAP output is enabled.
     bool m_enableTracing;  //!< True if tracing output is enabled.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-ofdm-eht-validation.cc ns-3.40/examples/wireless/wifi-ofdm-eht-validation.cc
--- ns-3.39/examples/wireless/wifi-ofdm-eht-validation.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-ofdm-eht-validation.cc	2023-09-27 13:30:37.610839000 -0700
@@ -37,7 +37,7 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t FrameSize = 1500; // bytes
+    uint32_t frameSizeBytes = 1500;
     std::ofstream yansfile("yans-frame-success-rate-be.plt");
     std::ofstream nistfile("nist-frame-success-rate-be.plt");
     std::ofstream tablefile("table-frame-success-rate-be.plt");
@@ -60,7 +60,7 @@
     };
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("FrameSize", "The frame size", FrameSize);
+    cmd.AddValue("FrameSize", "The frame size", frameSizeBytes);
     cmd.Parse(argc, argv);
 
     Gnuplot yansplot = Gnuplot("yans-frame-success-rate-be.eps");
@@ -72,48 +72,45 @@
     Ptr<TableBasedErrorRateModel> table = CreateObject<TableBasedErrorRateModel>();
     WifiTxVector txVector;
 
-    for (uint32_t i = 0; i < modes.size(); i++)
+    uint32_t frameSizeBits = frameSizeBytes * 8;
+
+    for (const auto& mode : modes)
     {
-        std::cout << modes[i] << std::endl;
-        Gnuplot2dDataset yansdataset(modes[i]);
-        Gnuplot2dDataset nistdataset(modes[i]);
-        Gnuplot2dDataset tabledataset(modes[i]);
-        txVector.SetMode(modes[i]);
+        std::cout << mode << std::endl;
+        Gnuplot2dDataset yansdataset(mode);
+        Gnuplot2dDataset nistdataset(mode);
+        Gnuplot2dDataset tabledataset(mode);
+        txVector.SetMode(mode);
+
+        WifiMode wifiMode(mode);
 
-        for (double snr = -5.0; snr <= 55.0; snr += 0.1)
+        for (double snrDb = -5.0; snrDb <= 55.0; snrDb += 0.1)
         {
-            double ps = yans->GetChunkSuccessRate(WifiMode(modes[i]),
-                                                  txVector,
-                                                  std::pow(10.0, snr / 10.0),
-                                                  FrameSize * 8);
+            double snr = std::pow(10.0, snrDb / 10.0);
+
+            double ps = yans->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            yansdataset.Add(snr, ps);
+            yansdataset.Add(snrDb, ps);
 
-            ps = nist->GetChunkSuccessRate(WifiMode(modes[i]),
-                                           txVector,
-                                           std::pow(10.0, snr / 10.0),
-                                           FrameSize * 8);
+            ps = nist->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            nistdataset.Add(snr, ps);
+            nistdataset.Add(snrDb, ps);
 
-            ps = table->GetChunkSuccessRate(WifiMode(modes[i]),
-                                            txVector,
-                                            std::pow(10.0, snr / 10.0),
-                                            FrameSize * 8);
+            ps = table->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            tabledataset.Add(snr, ps);
+            tabledataset.Add(snrDb, ps);
         }
 
         yansplot.AddDataset(yansdataset);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-ofdm-he-validation.cc ns-3.40/examples/wireless/wifi-ofdm-he-validation.cc
--- ns-3.39/examples/wireless/wifi-ofdm-he-validation.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-ofdm-he-validation.cc	2023-09-27 13:30:37.610839000 -0700
@@ -35,7 +35,7 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t FrameSize = 1500; // bytes
+    uint32_t frameSizeBytes = 1500;
     std::ofstream yansfile("yans-frame-success-rate-ax.plt");
     std::ofstream nistfile("nist-frame-success-rate-ax.plt");
     std::ofstream tablefile("table-frame-success-rate-ax.plt");
@@ -56,7 +56,7 @@
     };
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("FrameSize", "The frame size", FrameSize);
+    cmd.AddValue("FrameSize", "The frame size", frameSizeBytes);
     cmd.Parse(argc, argv);
 
     Gnuplot yansplot = Gnuplot("yans-frame-success-rate-ax.eps");
@@ -68,48 +68,45 @@
     Ptr<TableBasedErrorRateModel> table = CreateObject<TableBasedErrorRateModel>();
     WifiTxVector txVector;
 
-    for (uint32_t i = 0; i < modes.size(); i++)
+    uint32_t frameSizeBits = frameSizeBytes * 8;
+
+    for (const auto& mode : modes)
     {
-        std::cout << modes[i] << std::endl;
-        Gnuplot2dDataset yansdataset(modes[i]);
-        Gnuplot2dDataset nistdataset(modes[i]);
-        Gnuplot2dDataset tabledataset(modes[i]);
-        txVector.SetMode(modes[i]);
+        std::cout << mode << std::endl;
+        Gnuplot2dDataset yansdataset(mode);
+        Gnuplot2dDataset nistdataset(mode);
+        Gnuplot2dDataset tabledataset(mode);
+        txVector.SetMode(mode);
+
+        WifiMode wifiMode(mode);
 
-        for (double snr = -5.0; snr <= 40.0; snr += 0.1)
+        for (double snrDb = -5.0; snrDb <= 40.0; snrDb += 0.1)
         {
-            double ps = yans->GetChunkSuccessRate(WifiMode(modes[i]),
-                                                  txVector,
-                                                  std::pow(10.0, snr / 10.0),
-                                                  FrameSize * 8);
+            double snr = std::pow(10.0, snrDb / 10.0);
+
+            double ps = yans->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            yansdataset.Add(snr, ps);
+            yansdataset.Add(snrDb, ps);
 
-            ps = nist->GetChunkSuccessRate(WifiMode(modes[i]),
-                                           txVector,
-                                           std::pow(10.0, snr / 10.0),
-                                           FrameSize * 8);
+            ps = nist->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            nistdataset.Add(snr, ps);
+            nistdataset.Add(snrDb, ps);
 
-            ps = table->GetChunkSuccessRate(WifiMode(modes[i]),
-                                            txVector,
-                                            std::pow(10.0, snr / 10.0),
-                                            FrameSize * 8);
+            ps = table->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            tabledataset.Add(snr, ps);
+            tabledataset.Add(snrDb, ps);
         }
 
         yansplot.AddDataset(yansdataset);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-ofdm-ht-validation.cc ns-3.40/examples/wireless/wifi-ofdm-ht-validation.cc
--- ns-3.39/examples/wireless/wifi-ofdm-ht-validation.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-ofdm-ht-validation.cc	2023-09-27 13:30:37.610839000 -0700
@@ -35,7 +35,7 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t FrameSize = 1500; // bytes
+    uint32_t frameSizeBytes = 1500;
     std::ofstream yansfile("yans-frame-success-rate-n.plt");
     std::ofstream nistfile("nist-frame-success-rate-n.plt");
     std::ofstream tablefile("table-frame-success-rate-n.plt");
@@ -52,7 +52,7 @@
     };
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("FrameSize", "The frame size in bytes", FrameSize);
+    cmd.AddValue("FrameSize", "The frame size in bytes", frameSizeBytes);
     cmd.Parse(argc, argv);
 
     Gnuplot yansplot = Gnuplot("yans-frame-success-rate-n.eps");
@@ -64,48 +64,45 @@
     Ptr<NistErrorRateModel> nist = CreateObject<NistErrorRateModel>();
     Ptr<TableBasedErrorRateModel> table = CreateObject<TableBasedErrorRateModel>();
 
-    for (uint32_t i = 0; i < modes.size(); i++)
+    uint32_t frameSizeBits = frameSizeBytes * 8;
+
+    for (const auto& mode : modes)
     {
-        std::cout << modes[i] << std::endl;
-        Gnuplot2dDataset yansdataset(modes[i]);
-        Gnuplot2dDataset nistdataset(modes[i]);
-        Gnuplot2dDataset tabledataset(modes[i]);
-        txVector.SetMode(modes[i]);
+        std::cout << mode << std::endl;
+        Gnuplot2dDataset yansdataset(mode);
+        Gnuplot2dDataset nistdataset(mode);
+        Gnuplot2dDataset tabledataset(mode);
+        txVector.SetMode(mode);
+
+        WifiMode wifiMode(mode);
 
-        for (double snr = -5.0; snr <= 30.0; snr += 0.1)
+        for (double snrDb = -5.0; snrDb <= 30.0; snrDb += 0.1)
         {
-            double ps = yans->GetChunkSuccessRate(WifiMode(modes[i]),
-                                                  txVector,
-                                                  std::pow(10.0, snr / 10.0),
-                                                  FrameSize * 8);
+            double snr = std::pow(10.0, snrDb / 10.0);
+
+            double ps = yans->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            yansdataset.Add(snr, ps);
+            yansdataset.Add(snrDb, ps);
 
-            ps = nist->GetChunkSuccessRate(WifiMode(modes[i]),
-                                           txVector,
-                                           std::pow(10.0, snr / 10.0),
-                                           FrameSize * 8);
+            ps = nist->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            nistdataset.Add(snr, ps);
+            nistdataset.Add(snrDb, ps);
 
-            ps = table->GetChunkSuccessRate(WifiMode(modes[i]),
-                                            txVector,
-                                            std::pow(10.0, snr / 10.0),
-                                            FrameSize * 8);
+            ps = table->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            tabledataset.Add(snr, ps);
+            tabledataset.Add(snrDb, ps);
         }
 
         yansplot.AddDataset(yansdataset);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-ofdm-validation.cc ns-3.40/examples/wireless/wifi-ofdm-validation.cc
--- ns-3.39/examples/wireless/wifi-ofdm-validation.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-ofdm-validation.cc	2023-09-27 13:30:37.610839000 -0700
@@ -37,7 +37,7 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t FrameSize = 1500; // bytes
+    uint32_t frameSizeBytes = 1500;
     std::ofstream yansfile("yans-frame-success-rate-ofdm.plt");
     std::ofstream nistfile("nist-frame-success-rate-ofdm.plt");
     std::ofstream tablefile("table-frame-success-rate-ofdm.plt");
@@ -54,7 +54,7 @@
     };
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("FrameSize", "The frame size in bytes", FrameSize);
+    cmd.AddValue("FrameSize", "The frame size in bytes", frameSizeBytes);
     cmd.Parse(argc, argv);
 
     Gnuplot yansplot = Gnuplot("yans-frame-success-rate-ofdm.eps");
@@ -66,48 +66,45 @@
     Ptr<TableBasedErrorRateModel> table = CreateObject<TableBasedErrorRateModel>();
     WifiTxVector txVector;
 
-    for (uint32_t i = 0; i < modes.size(); i++)
+    uint32_t frameSizeBits = frameSizeBytes * 8;
+
+    for (const auto& mode : modes)
     {
-        std::cout << modes[i] << std::endl;
-        Gnuplot2dDataset yansdataset(modes[i]);
-        Gnuplot2dDataset nistdataset(modes[i]);
-        Gnuplot2dDataset tabledataset(modes[i]);
-        txVector.SetMode(modes[i]);
+        std::cout << mode << std::endl;
+        Gnuplot2dDataset yansdataset(mode);
+        Gnuplot2dDataset nistdataset(mode);
+        Gnuplot2dDataset tabledataset(mode);
+        txVector.SetMode(mode);
+
+        WifiMode wifiMode(mode);
 
-        for (double snr = -5.0; snr <= 30.0; snr += 0.1)
+        for (double snrDb = -5.0; snrDb <= 30.0; snrDb += 0.1)
         {
-            double ps = yans->GetChunkSuccessRate(WifiMode(modes[i]),
-                                                  txVector,
-                                                  std::pow(10.0, snr / 10.0),
-                                                  FrameSize * 8);
+            double snr = std::pow(10.0, snrDb / 10.0);
+
+            double ps = yans->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            yansdataset.Add(snr, ps);
+            yansdataset.Add(snrDb, ps);
 
-            ps = nist->GetChunkSuccessRate(WifiMode(modes[i]),
-                                           txVector,
-                                           std::pow(10.0, snr / 10.0),
-                                           FrameSize * 8);
+            ps = nist->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            nistdataset.Add(snr, ps);
+            nistdataset.Add(snrDb, ps);
 
-            ps = table->GetChunkSuccessRate(WifiMode(modes[i]),
-                                            txVector,
-                                            std::pow(10.0, snr / 10.0),
-                                            FrameSize * 8);
+            ps = table->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            tabledataset.Add(snr, ps);
+            tabledataset.Add(snrDb, ps);
         }
 
         yansplot.AddDataset(yansdataset);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-ofdm-vht-validation.cc ns-3.40/examples/wireless/wifi-ofdm-vht-validation.cc
--- ns-3.39/examples/wireless/wifi-ofdm-vht-validation.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-ofdm-vht-validation.cc	2023-09-27 13:30:37.610839000 -0700
@@ -36,7 +36,7 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t FrameSize = 1500; // bytes
+    uint32_t frameSizeBytes = 1500;
     std::ofstream yansfile("yans-frame-success-rate-ac.plt");
     std::ofstream nistfile("nist-frame-success-rate-ac.plt");
     std::ofstream tablefile("table-frame-success-rate-ac.plt");
@@ -54,7 +54,7 @@
     };
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("FrameSize", "The frame size in bytes", FrameSize);
+    cmd.AddValue("FrameSize", "The frame size in bytes", frameSizeBytes);
     cmd.Parse(argc, argv);
 
     Gnuplot yansplot = Gnuplot("yans-frame-success-rate-ac.eps");
@@ -66,48 +66,45 @@
     Ptr<TableBasedErrorRateModel> table = CreateObject<TableBasedErrorRateModel>();
     WifiTxVector txVector;
 
-    for (uint32_t i = 0; i < modes.size(); i++)
+    uint32_t frameSizeBits = frameSizeBytes * 8;
+
+    for (const auto& mode : modes)
     {
-        std::cout << modes[i] << std::endl;
-        Gnuplot2dDataset yansdataset(modes[i]);
-        Gnuplot2dDataset nistdataset(modes[i]);
-        Gnuplot2dDataset tabledataset(modes[i]);
-        txVector.SetMode(modes[i]);
+        std::cout << mode << std::endl;
+        Gnuplot2dDataset yansdataset(mode);
+        Gnuplot2dDataset nistdataset(mode);
+        Gnuplot2dDataset tabledataset(mode);
+        txVector.SetMode(mode);
+
+        WifiMode wifiMode(mode);
 
-        for (double snr = -5.0; snr <= 30.0; snr += 0.1)
+        for (double snrDb = -5.0; snrDb <= 30.0; snrDb += 0.1)
         {
-            double ps = yans->GetChunkSuccessRate(WifiMode(modes[i]),
-                                                  txVector,
-                                                  std::pow(10.0, snr / 10.0),
-                                                  FrameSize * 8);
+            double snr = std::pow(10.0, snrDb / 10.0);
+
+            double ps = yans->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            yansdataset.Add(snr, ps);
+            yansdataset.Add(snrDb, ps);
 
-            ps = nist->GetChunkSuccessRate(WifiMode(modes[i]),
-                                           txVector,
-                                           std::pow(10.0, snr / 10.0),
-                                           FrameSize * 8);
+            ps = nist->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            nistdataset.Add(snr, ps);
+            nistdataset.Add(snrDb, ps);
 
-            ps = table->GetChunkSuccessRate(WifiMode(modes[i]),
-                                            txVector,
-                                            std::pow(10.0, snr / 10.0),
-                                            FrameSize * 8);
+            ps = table->GetChunkSuccessRate(wifiMode, txVector, snr, frameSizeBits);
             if (ps < 0.0 || ps > 1.0)
             {
                 // error
                 exit(1);
             }
-            tabledataset.Add(snr, ps);
+            tabledataset.Add(snrDb, ps);
         }
 
         yansplot.AddDataset(yansdataset);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-power-adaptation-distance.cc ns-3.40/examples/wireless/wifi-power-adaptation-distance.cc
--- ns-3.39/examples/wireless/wifi-power-adaptation-distance.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-power-adaptation-distance.cc	2023-09-27 13:30:37.610839000 -0700
@@ -253,7 +253,7 @@
         txVector.SetMode(mode);
         txVector.SetPreambleType(WIFI_PREAMBLE_LONG);
         txVector.SetChannelWidth(phy->GetChannelWidth());
-        DataRate dataRate = DataRate(mode.GetDataRate(phy->GetChannelWidth()));
+        DataRate dataRate(mode.GetDataRate(phy->GetChannelWidth()));
         Time time = phy->CalculateTxDuration(packetSize, txVector, phy->GetPhyBand());
         NS_LOG_DEBUG(mode.GetUniqueName() << " " << time.GetSeconds() << " " << dataRate);
         m_timeTable.emplace_back(time, dataRate);
@@ -263,7 +263,7 @@
 Time
 NodeStatistics::GetCalcTxTime(DataRate rate)
 {
-    for (TxTime::const_iterator i = m_timeTable.begin(); i != m_timeTable.end(); i++)
+    for (auto i = m_timeTable.begin(); i != m_timeTable.end(); i++)
     {
         if (rate == i->second)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-power-adaptation-interference.cc ns-3.40/examples/wireless/wifi-power-adaptation-interference.cc
--- ns-3.39/examples/wireless/wifi-power-adaptation-interference.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-power-adaptation-interference.cc	2023-09-27 13:30:37.610839000 -0700
@@ -274,7 +274,7 @@
         txVector.SetMode(mode);
         txVector.SetPreambleType(WIFI_PREAMBLE_LONG);
         txVector.SetChannelWidth(phy->GetChannelWidth());
-        DataRate dataRate = DataRate(mode.GetDataRate(phy->GetChannelWidth()));
+        DataRate dataRate(mode.GetDataRate(phy->GetChannelWidth()));
         Time time = phy->CalculateTxDuration(packetSize, txVector, phy->GetPhyBand());
         NS_LOG_DEBUG(mode.GetUniqueName() << " " << time.GetSeconds() << " " << dataRate);
         m_timeTable.emplace_back(time, dataRate);
@@ -284,7 +284,7 @@
 Time
 NodeStatistics::GetCalcTxTime(DataRate rate)
 {
-    for (TxTime::const_iterator i = m_timeTable.begin(); i != m_timeTable.end(); i++)
+    for (auto i = m_timeTable.begin(); i != m_timeTable.end(); i++)
     {
         if (rate == i->second)
         {
@@ -667,9 +667,7 @@
 
     Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier>(flowmon.GetClassifier());
     std::map<FlowId, FlowMonitor::FlowStats> stats = monitor->GetFlowStats();
-    for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin();
-         i != stats.end();
-         ++i)
+    for (auto i = stats.begin(); i != stats.end(); ++i)
     {
         Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(i->first);
         if ((t.sourceAddress == "10.1.1.3" && t.destinationAddress == "10.1.1.1"))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-rate-adaptation-distance.cc ns-3.40/examples/wireless/wifi-rate-adaptation-distance.cc
--- ns-3.39/examples/wireless/wifi-rate-adaptation-distance.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-rate-adaptation-distance.cc	2023-09-27 13:30:37.610839000 -0700
@@ -403,8 +403,8 @@
     std::ofstream outfile("throughput-" + outputFileName + ".plt");
     Gnuplot gnuplot = Gnuplot("throughput-" + outputFileName + ".eps", "Throughput");
     gnuplot.SetTerminal("post eps color enhanced");
-    gnuplot.SetLegend("Time (seconds)", "Throughput (Mb/s)");
-    gnuplot.SetTitle("Throughput (AP to STA) vs time");
+    gnuplot.SetLegend("Distance (meters)", "Throughput (Mb/s)");
+    gnuplot.SetTitle("Throughput (AP to STA) vs distance");
     gnuplot.AddDataset(atpCounter.GetDatafile());
     gnuplot.GenerateOutput(outfile);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-simple-ht-hidden-stations.cc ns-3.40/examples/wireless/wifi-simple-ht-hidden-stations.cc
--- ns-3.39/examples/wireless/wifi-simple-ht-hidden-stations.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-simple-ht-hidden-stations.cc	2023-09-27 13:30:37.610839000 -0700
@@ -59,7 +59,7 @@
     double simulationTime = 10;  // seconds
     uint32_t nMpdus = 1;
     uint32_t maxAmpduSize = 0;
-    bool enableRts = 0;
+    bool enableRts = false;
     double minExpectedThroughput = 0;
     double maxExpectedThroughput = 0;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-sleep.cc ns-3.40/examples/wireless/wifi-sleep.cc
--- ns-3.39/examples/wireless/wifi-sleep.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-sleep.cc	2023-09-27 13:30:37.610839000 -0700
@@ -228,7 +228,7 @@
                                         DoubleValue(eta));
 
     // install an energy source on each node
-    for (NodeContainer::Iterator n = c.Begin(); n != c.End(); n++)
+    for (auto n = c.Begin(); n != c.End(); n++)
     {
         eSources.Add(basicSourceHelper.Install(*n));
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-txop-aggregation.cc ns-3.40/examples/wireless/wifi-txop-aggregation.cc
--- ns-3.39/examples/wireless/wifi-txop-aggregation.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-txop-aggregation.cc	2023-09-27 13:30:37.610839000 -0700
@@ -111,9 +111,9 @@
     double simulationTime = 10;  // seconds
     double txopLimit = 3520;     // microseconds
     double distance = 5;         // meters
-    bool enableRts = 0;
-    bool enablePcap = 0;
-    bool verifyResults = 0; // used for regression
+    bool enableRts = false;
+    bool enablePcap = false;
+    bool verifyResults = false; // used for regression
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("payloadSize", "Payload size in bytes", payloadSize);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/examples/wireless/wifi-vht-network.cc ns-3.40/examples/wireless/wifi-vht-network.cc
--- ns-3.39/examples/wireless/wifi-vht-network.cc	2023-07-05 14:23:47.669427000 -0700
+++ ns-3.40/examples/wireless/wifi-vht-network.cc	2023-09-27 13:30:37.610839000 -0700
@@ -117,7 +117,7 @@
                 channelWidth *= 2;
                 continue;
             }
-            for (int sgi = 0; sgi < 2; sgi++)
+            for (auto sgi : {false, true})
             {
                 uint32_t payloadSize; // 1500 byte IP packet
                 if (udp)
@@ -265,11 +265,11 @@
 
                 Simulator::Destroy();
 
-                std::cout << mcs << "\t\t\t" << channelWidth << " MHz\t\t\t" << sgi << "\t\t\t"
-                          << throughput << " Mbit/s" << std::endl;
+                std::cout << mcs << "\t\t\t" << channelWidth << " MHz\t\t\t" << std::boolalpha
+                          << sgi << "\t\t\t" << throughput << " Mbit/s" << std::endl;
 
                 // test first element
-                if (mcs == 0 && channelWidth == 20 && sgi == 0)
+                if (mcs == 0 && channelWidth == 20 && !sgi)
                 {
                     if (throughput < minExpectedThroughput)
                     {
@@ -278,7 +278,7 @@
                     }
                 }
                 // test last element
-                if (mcs == 9 && channelWidth == 160 && sgi == 1)
+                if (mcs == 9 && channelWidth == 160 && sgi)
                 {
                     if (maxExpectedThroughput > 0 && throughput > maxExpectedThroughput)
                     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/ns3 ns-3.40/ns3
--- ns-3.39/ns3	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/ns3	2023-09-27 13:30:37.610839000 -0700
@@ -167,13 +167,14 @@
         parser_configure = on_off_argument(parser_configure, *on_off_option)
 
     parser_configure.add_argument('--enable-modules',
-                                  help='List of modules to build (e.g. core;network;internet)',
+                                  help='List of modules to build (e.g. \"core;network;internet\")',
                                   action="store", type=str, default=None)
     parser_configure.add_argument('--disable-modules',
-                                  help='List of modules not to build (e.g. lte;wimax)',
+                                  help='List of modules not to build (e.g. \"lte;wimax\")',
                                   action="store", type=str, default=None)
     parser_configure.add_argument('--filter-module-examples-and-tests',
-                                  help='List of modules that should have their examples and tests built (e.g. lte;wifi)',
+                                  help=('List of modules that should have their examples '
+                                        'and tests built (e.g. \"lte;wifi\")'),
                                   action="store", type=str, default=None)
     parser_configure.add_argument('--lcov-report',
                                   help=('Generate a code coverage report '
@@ -429,7 +430,8 @@
 def remove_dir(dir_to_remove, dry_run, directory_qualifier=""):
     dir_to_remove = os.path.abspath(dir_to_remove)
     if os.path.exists(dir_to_remove):
-        if ".." in os.path.relpath(dir_to_remove, ns3_path):
+        if (".." in os.path.relpath(dir_to_remove, ns3_path)
+            or os.path.abspath(dir_to_remove) == os.path.abspath(ns3_path)):
             # In case the directory to remove isn't within
             # the current ns-3 directory, print an error
             # message for the dry-run case
@@ -505,6 +507,10 @@
         remove_dir(directory, dry_run)
 
 
+def clean_vcpkg_artifacts(dry_run=False):
+    remove_dir(os.path.join(ns3_path, "vcpkg"), dry_run)
+
+
 def search_cmake_cache(build_profile):
     # Search for the CMake cache
     cmake_cache_files = glob.glob("%s/**/CMakeCache.txt" % ns3_path, recursive=True)
@@ -1445,6 +1451,7 @@
         clean_cmake_artifacts(dry_run=args.dry_run)
         clean_docs_and_tests_artifacts(dry_run=args.dry_run)
         clean_pip_packaging_artifacts(dry_run=args.dry_run)
+        clean_vcpkg_artifacts(dry_run=args.dry_run)
         # We end things earlier when cleaning
         return
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/README.md ns-3.40/README.md
--- ns-3.39/README.md	2023-07-05 14:23:47.581426600 -0700
+++ ns-3.40/README.md	2023-09-27 13:30:37.526838800 -0700
@@ -1,36 +1,33 @@
 # The Network Simulator, Version 3
 
-
 [![codecov](https://codecov.io/gh/nsnam/ns-3-dev-git/branch/master/graph/badge.svg)](https://codecov.io/gh/nsnam/ns-3-dev-git/branch/master/)
 [![Gitlab CI](https://gitlab.com/nsnam/ns-3-dev/badges/master/pipeline.svg)](https://gitlab.com/nsnam/ns-3-dev/-/pipelines)
 [![Github CI](https://github.com/nsnam/ns-3-dev-git/actions/workflows/per_commit.yml/badge.svg)](https://github.com/nsnam/ns-3-dev-git/actions)
 
-
 ## Table of Contents
 
-1) [An overview](#an-open-source-project)
-2) [Building ns-3](#building-ns-3)
-3) [Running ns-3](#running-ns-3)
-4) [Getting access to the ns-3 documentation](#getting-access-to-the-ns-3-documentation)
-5) [Working with the development version of ns-3](#working-with-the-development-version-of-ns-3)
+* [Overview](#overview-an-open-source-project)
+* [Building ns-3](#building-ns-3)
+* [Testing ns-3](#testing-ns-3)
+* [Running ns-3](#running-ns-3)
+* [ns-3 Documentation](#ns-3-documentation)
+* [Working with the Development Version of ns-3](#working-with-the-development-version-of-ns-3)
+* [Contributing to ns-3](#contributing-to-ns-3)
+* [Reporting Issues](#reporting-issues)
+* [ns-3 App Store](#ns-3-app-store)
 
 > **NOTE**: Much more substantial information about ns-3 can be found at
 <https://www.nsnam.org>
 
-## An Open Source project
+## Overview: An Open Source Project
 
 ns-3 is a free open source project aiming to build a discrete-event
 network simulator targeted for simulation research and education.
 This is a collaborative project; we hope that
 the missing pieces of the models we have not yet implemented
 will be contributed by the community in an open collaboration
-process.
-
-The process of contributing to the ns-3 project varies with
-the people involved, the amount of time they can invest
-and the type of model they want to work on, but the current
-process that the project tries to follow is described here:
-<https://www.nsnam.org/developers/contributing-code/>
+process. If you would like to contribute to ns-3, please check
+the [Contributing to ns-3](#contributing-to-ns-3) section below.
 
 This README excerpts some details from a more extensive
 tutorial that is maintained at:
@@ -45,24 +42,31 @@
 
 To build the set of default libraries and the example
 programs included in this package, you need to use the
-tool 'ns3'. Detailed information on how to use ns3 is
-included in the file doc/build.txt
+`ns3` tool. This tool provides a Waf-like API to the
+underlying CMake build manager.
+Detailed information on how to use `ns3` is included in the
+[quick start guide](doc/installation/source/quick-start.rst).
+
+Before building ns-3, you must configure it.
+This step allows the configuration of the build options,
+such as whether to enable the examples, tests and more.
 
-However, the real quick and dirty way to get started is to
-type the command
+To configure ns-3 with examples and tests enabled,
+run the following command on the ns-3 main directory:
 
 ```shell
-./ns3 configure --enable-examples
+./ns3 configure --enable-examples --enable-tests
 ```
 
-followed by
+Then, build ns-3 by running the following command:
 
 ```shell
-./ns3
+./ns3 build
 ```
 
-in the directory which contains this README file. The files
-built will be copied in the build/ directory.
+By default, the build artifacts will be stored in the `build/` directory.
+
+### Supported Platforms
 
 The current codebase is expected to build and run on the
 set of platforms listed in the [release notes](RELEASE_NOTES.md)
@@ -71,6 +75,18 @@
 Other platforms may or may not work: we welcome patches to
 improve the portability of the code to these other platforms.
 
+## Testing ns-3
+
+ns-3 contains test suites to validate the models and detect regressions.
+To run the test suite, run the following command on the ns-3 main directory:
+
+```shell
+./test.py
+```
+
+More information about ns-3 tests is available in the
+[test framework](doc/manual/source/test-framework.rst) section of the manual.
+
 ## Running ns-3
 
 On recent Linux systems, once you have built ns-3 (with examples
@@ -83,11 +99,10 @@
 
 That program should generate a `simple-global-routing.tr` text
 trace file and a set of `simple-global-routing-xx-xx.pcap` binary
-pcap trace files, which can be read by `tcpdump -tt -r filename.pcap`
-The program source can be found in the examples/routing directory.
-
+PCAP trace files, which can be read by `tcpdump -n -tt -r filename.pcap`.
+The program source can be found in the `examples/routing` directory.
 
-## Running ns-3 from python
+## Running ns-3 from Python
 
 If you do not plan to modify ns-3 upstream modules, you can get
 a pre-built version of the ns-3 python bindings.
@@ -117,26 +132,26 @@
 
 Use `help(ns)` to check the prototypes for all functions defined in the
 ns3 namespace. To get more useful results, query specific classes of
-interest and their functions e.g. `help(ns.Simulator)`.
+interest and their functions e.g., `help(ns.Simulator)`.
 
 Smart pointers `Ptr<>` can be differentiated from objects by checking if
 `__deref__` is listed in `dir(variable)`. To dereference the pointer,
 use `variable.__deref__()`.
 
 Most ns-3 simulations are written in C++ and the documentation is
-oriented towards C++ users. The ns-3 tutorial programs (first.cc,
-second.cc, etc.) have Python equivalents, if you are looking for
+oriented towards C++ users. The ns-3 tutorial programs (`first.cc`,
+`second.cc`, etc.) have Python equivalents, if you are looking for
 some initial guidance on how to use the Python API. The Python
 API may not be as full-featured as the C++ API, and an API guide
 for what C++ APIs are supported or not from Python do not currently exist.
 The project is looking for additional Python maintainers to improve
 the support for future Python users.
 
-## Getting access to the ns-3 documentation
+## ns-3 Documentation
 
 Once you have verified that your build of ns-3 works by running
-the simple-point-to-point example as outlined in 3) above, it is
-quite likely that you will want to get started on reading
+the `simple-global-routing` example as outlined in the [running ns-3](#running-ns-3)
+section, it is quite likely that you will want to get started on reading
 some ns-3 documentation.
 
 All of that documentation should always be available from
@@ -144,31 +159,55 @@
 
 This documentation includes:
 
-- a tutorial
-- a reference manual
-- models in the ns-3 model library
-- a wiki for user-contributed tips: <https://www.nsnam.org/wiki/>
-- API documentation generated using doxygen: this is
+* a tutorial
+* a reference manual
+* models in the ns-3 model library
+* a wiki for user-contributed tips: <https://www.nsnam.org/wiki/>
+* API documentation generated using doxygen: this is
   a reference manual, most likely not very well suited
   as introductory text:
   <https://www.nsnam.org/doxygen/index.html>
 
-## Working with the development version of ns-3
+## Working with the Development Version of ns-3
 
 If you want to download and use the development version of ns-3, you
 need to use the tool `git`. A quick and dirty cheat sheet is included
-in the manual, but reading through the git
+in the manual, but reading through the Git
 tutorials found in the Internet is usually a good idea if you are not
 familiar with it.
 
-If you have successfully installed git, you can get
+If you have successfully installed Git, you can get
 a copy of the development version with the following command:
 
 ```shell
 git clone https://gitlab.com/nsnam/ns-3-dev.git
 ```
 
-However, we recommend to follow the Gitlab guidelines for starters,
-that includes creating a Gitlab account, forking the ns-3-dev project
+However, we recommend to follow the GitLab guidelines for starters,
+that includes creating a GitLab account, forking the ns-3-dev project
 under the new account's name, and then cloning the forked repository.
 You can find more information in the [manual](https://www.nsnam.org/docs/manual/html/working-with-git.html).
+
+## Contributing to ns-3
+
+The process of contributing to the ns-3 project varies with
+the people involved, the amount of time they can invest
+and the type of model they want to work on, but the current
+process that the project tries to follow is described in the
+[contributing code](https://www.nsnam.org/developers/contributing-code/)
+website and in the [CONTRIBUTING.md](CONTRIBUTING.md) file.
+
+## Reporting Issues
+
+If you would like to report an issue, you can open a new issue in the
+[GitLab issue tracker](https://gitlab.com/nsnam/ns-3-dev/-/issues).
+Before creating a new issue, please check if the problem that you are facing
+was already reported and contribute to the discussion, if necessary.
+
+## ns-3 App Store
+
+The official [ns-3 App Store](https://apps.nsnam.org/) is a centralized directory
+listing third-party modules for ns-3 available on the Internet.
+
+More information on how to submit an ns-3 module to the ns-3 App Store is available
+in the [ns-3 App Store documentation](https://www.nsnam.org/docs/contributing/html/external.html).
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/RELEASE_NOTES.md ns-3.40/RELEASE_NOTES.md
--- ns-3.39/RELEASE_NOTES.md	2023-07-05 14:23:47.585426600 -0700
+++ ns-3.40/RELEASE_NOTES.md	2023-09-27 13:30:37.526838800 -0700
@@ -13,6 +13,55 @@
 and references prefixed by '!' refer to a
 [GitLab.com merge request](https://gitlab.com/nsnam/ns-3-dev/-/merge_requests) number.
 
+Release 3.40
+------------
+
+### Availability
+
+This release is available from:
+<https://www.nsnam.org/release/ns-allinone-3.40.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.10 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 works for Linux only.  Specifically, avoid Cppyy version 3; stay with version 2.4.2 for this release.
+
+### New user-visible features
+
+- (core) !1586 - `EmpiricalRandomVariable` CDF pairs can now be added in any order.
+- (energy) !1329 - Extensions to battery discharge module
+- (lr-wpan) !1604 - Add CapabilityField bitmap functions
+- (lr-wpan) !1645 - Add LQI to MlmeAssociateIndicationParams
+- (wifi) Added support for 802.11be TID-to-Link Mapping
+- (wifi) Added a new trace source to WifiPhy to indicate operating channel change
+- (wifi) Improved support for multiple spectrum PHY interfaces
+- (wifi) Added initial support for MU-MIMO (ideal PHY layer only)
+
+### Bugs fixed
+
+- (antenna) #889 - Improve `WrapTo*` functions
+- (core) #922 - `EmpiricalRandomVariable` no longer requires that a CDF pair with a range value exactly equal to 1.0 be added.
+- (core) #949 - Fix bound callbacks arguments type detection
+- (internet) #956 - Avoid sending RS when link goes down
+- (lr-wpan) !1591 - Removed unnecessary Bcst filter from MAC
+- (lr-wpan) #944 - Fix for-loop in PrintTxQueue(s) functions
+- (lr-wpan) - Fix incorrect return parameter in the MAC MlmeAssociateConfirm
+- (mobility) #943 - Fix node direction change when node is in a corner
+- (wifi) - Reset MU PPDU UID to prevent STA from receiving the TB PPDU sent by another STA
+- (wifi) - Fix max value for UL MCS field of User Info fields (depends on TF variant)
+- (wifi) - Update TXOP bandwidth upon every transmission
+- (wifi) - Fix flush operation on WifiMacQueues
+- (wifi) #942 - Trace expired MPDUs before removing them from the queue to avoid blocking the recipient buffer
+- (wifi) - Fix wrong condition preventing PHY from aborting RX when starting TX
+
 Release 3.39
 ------------
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/doc/source/antenna-design.rst ns-3.40/src/antenna/doc/source/antenna-design.rst
--- ns-3.39/src/antenna/doc/source/antenna-design.rst	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/doc/source/antenna-design.rst	2023-09-27 13:30:37.610839000 -0700
@@ -153,6 +153,7 @@
 The class PhasedArrayModel also assumes that all antenna elements are equal, a typical key assumption which allows to model the PAA field pattern as the sum of the array factor, given by the geometry of the location of the antenna elements, and the element field pattern.
 Any class derived from AntennaModel is a valid antenna element for the PhasedArrayModel, allowing for a great flexibility of the framework.
 
+.. _3gpp-antenna-model:
 
 UniformPlanarArray
 ++++++++++++++++++
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/model/angles.cc ns-3.40/src/antenna/model/angles.cc
--- ns-3.39/src/antenna/model/angles.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/model/angles.cc	2023-09-27 13:30:37.610839000 -0700
@@ -74,55 +74,85 @@
 double
 WrapTo360(double a)
 {
-    a = fmod(a, 360);
-    if (a < 0)
+    static constexpr int64_t INT_RANGE = 100000000000;
+    // Divide the input by 360.
+    // Multiply it by INT_RANGE and store into an integer.
+    int64_t b(a / (360.0) * INT_RANGE);
+    // Clamp it between [-INT_RANGE / 2, INT_RANGE / 2)
+    b = b % INT_RANGE;
+    if (b < 0)
     {
-        a += 360;
+        b += INT_RANGE;
     }
-
-    NS_ASSERT_MSG(0 <= a && a < 360, "Invalid wrap, a=" << a);
-    return a;
+    else if (b >= INT_RANGE)
+    {
+        b -= INT_RANGE;
+    }
+    // Divide by INT_RANGE and multiply by 360.
+    return b * (360.0) / INT_RANGE;
 }
 
 double
 WrapTo180(double a)
 {
-    a = fmod(a + 180, 360);
-    if (a < 0)
+    static constexpr int64_t INT_RANGE = 100000000000;
+    // Divide the input by 360.
+    // Multiply it by INT_RANGE and store into an integer.
+    int64_t b(a / (360.0) * INT_RANGE);
+    // Clamp it between [-INT_RANGE / 2, INT_RANGE / 2)
+    b = b % INT_RANGE;
+    if (b < -INT_RANGE / 2)
     {
-        a += 360;
+        b += INT_RANGE;
     }
-    a -= 180;
-
-    NS_ASSERT_MSG(-180 <= a && a < 180, "Invalid wrap, a=" << a);
-    return a;
+    else if (b >= INT_RANGE / 2)
+    {
+        b -= INT_RANGE;
+    }
+    // Divide by INT_RANGE and multiply by 360.
+    return b * (360.0) / INT_RANGE;
 }
 
 double
 WrapTo2Pi(double a)
 {
-    a = fmod(a, 2 * M_PI);
-    if (a < 0)
+    static constexpr int64_t INT_RANGE = 100000000000;
+    // Divide the input by 2*M_PI.
+    // Multiply it by INT_RANGE and store into an integer.
+    int64_t b(a / (2 * M_PI) * INT_RANGE);
+    // Clamp it between [-INT_RANGE / 2, INT_RANGE / 2)
+    b = b % INT_RANGE;
+    if (b < 0)
     {
-        a += 2 * M_PI;
+        b += INT_RANGE;
     }
-
-    NS_ASSERT_MSG(0 <= a && a < 2 * M_PI, "Invalid wrap, a=" << a);
-    return a;
+    else if (b >= INT_RANGE)
+    {
+        b -= INT_RANGE;
+    }
+    // Divide by INT_RANGE and multiply by 2*M_PI.
+    return b * (2 * M_PI) / INT_RANGE;
 }
 
 double
 WrapToPi(double a)
 {
-    a = fmod(a + M_PI, 2 * M_PI);
-    if (a < 0)
+    static constexpr int64_t INT_RANGE = 100000000000;
+    // Divide the input by 2*M_PI.
+    // Multiply it by INT_RANGE and store into an integer.
+    int64_t b(a / (2 * M_PI) * INT_RANGE);
+    // Clamp it between [-INT_RANGE / 2, INT_RANGE / 2)
+    b = b % INT_RANGE;
+    if (b < -INT_RANGE / 2)
     {
-        a += 2 * M_PI;
+        b += INT_RANGE;
     }
-    a -= M_PI;
-
-    NS_ASSERT_MSG(-M_PI <= a && a < M_PI, "Invalid wrap, a=" << a);
-    return a;
+    else if (b >= INT_RANGE / 2)
+    {
+        b -= INT_RANGE;
+    }
+    // Divide by INT_RANGE and multiply by 2*M_PI.
+    return b * (2 * M_PI) / INT_RANGE;
 }
 
 std::ostream&
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/model/antenna-model.h ns-3.40/src/antenna/model/antenna-model.h
--- ns-3.39/src/antenna/model/antenna-model.h	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/model/antenna-model.h	2023-09-27 13:30:37.610839000 -0700
@@ -20,7 +20,8 @@
 #ifndef ANTENNA_MODEL_H
 #define ANTENNA_MODEL_H
 
-#include <ns3/angles.h>
+#include "angles.h"
+
 #include <ns3/object.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/model/cosine-antenna-model.h ns-3.40/src/antenna/model/cosine-antenna-model.h
--- ns-3.39/src/antenna/model/cosine-antenna-model.h	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/model/cosine-antenna-model.h	2023-09-27 13:30:37.610839000 -0700
@@ -20,7 +20,8 @@
 #ifndef COSINE_ANTENNA_MODEL_H
 #define COSINE_ANTENNA_MODEL_H
 
-#include <ns3/antenna-model.h>
+#include "antenna-model.h"
+
 #include <ns3/object.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/model/isotropic-antenna-model.h ns-3.40/src/antenna/model/isotropic-antenna-model.h
--- ns-3.39/src/antenna/model/isotropic-antenna-model.h	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/model/isotropic-antenna-model.h	2023-09-27 13:30:37.610839000 -0700
@@ -20,7 +20,8 @@
 #ifndef ISOTROPIC_ANTENNA_MODEL_H
 #define ISOTROPIC_ANTENNA_MODEL_H
 
-#include <ns3/antenna-model.h>
+#include "antenna-model.h"
+
 #include <ns3/object.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/model/parabolic-antenna-model.h ns-3.40/src/antenna/model/parabolic-antenna-model.h
--- ns-3.39/src/antenna/model/parabolic-antenna-model.h	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/model/parabolic-antenna-model.h	2023-09-27 13:30:37.610839000 -0700
@@ -20,7 +20,8 @@
 #ifndef PARABOLIC_ANTENNA_MODEL_H
 #define PARABOLIC_ANTENNA_MODEL_H
 
-#include <ns3/antenna-model.h>
+#include "antenna-model.h"
+
 #include <ns3/object.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/model/phased-array-model.cc ns-3.40/src/antenna/model/phased-array-model.cc
--- ns-3.39/src/antenna/model/phased-array-model.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/model/phased-array-model.cc	2023-09-27 13:30:37.610839000 -0700
@@ -17,9 +17,10 @@
 
 #include "phased-array-model.h"
 
+#include "isotropic-antenna-model.h"
+
 #include <ns3/boolean.h>
 #include <ns3/double.h>
-#include <ns3/isotropic-antenna-model.h>
 #include <ns3/log.h>
 #include <ns3/pointer.h>
 #include <ns3/uinteger.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/model/phased-array-model.h ns-3.40/src/antenna/model/phased-array-model.h
--- ns-3.39/src/antenna/model/phased-array-model.h	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/model/phased-array-model.h	2023-09-27 13:30:37.610839000 -0700
@@ -18,8 +18,9 @@
 #ifndef PHASED_ARRAY_MODEL_H
 #define PHASED_ARRAY_MODEL_H
 
-#include <ns3/angles.h>
-#include <ns3/antenna-model.h>
+#include "angles.h"
+#include "antenna-model.h"
+
 #include <ns3/matrix-array.h>
 #include <ns3/object.h>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/model/three-gpp-antenna-model.h ns-3.40/src/antenna/model/three-gpp-antenna-model.h
--- ns-3.39/src/antenna/model/three-gpp-antenna-model.h	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/model/three-gpp-antenna-model.h	2023-09-27 13:30:37.610839000 -0700
@@ -18,7 +18,8 @@
 #ifndef THREE_GPP_ANTENNA_MODEL_H
 #define THREE_GPP_ANTENNA_MODEL_H
 
-#include <ns3/antenna-model.h>
+#include "antenna-model.h"
+
 #include <ns3/object.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/model/uniform-planar-array.h ns-3.40/src/antenna/model/uniform-planar-array.h
--- ns-3.39/src/antenna/model/uniform-planar-array.h	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/model/uniform-planar-array.h	2023-09-27 13:30:37.610839000 -0700
@@ -18,8 +18,9 @@
 #ifndef UNIFORM_PLANAR_ARRAY_H
 #define UNIFORM_PLANAR_ARRAY_H
 
+#include "phased-array-model.h"
+
 #include <ns3/object.h>
-#include <ns3/phased-array-model.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/antenna/test/test-angles.cc ns-3.40/src/antenna/test/test-angles.cc
--- ns-3.39/src/antenna/test/test-angles.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/antenna/test/test-angles.cc	2023-09-27 13:30:37.610839000 -0700
@@ -134,6 +134,156 @@
     NS_TEST_EXPECT_MSG_EQ_TOL(a.GetInclination(), m_a.GetInclination(), 1e-10, "incorrect theta");
 }
 
+using WrapToRangeFunction = std::function<double(double)>;
+
+/**
+ * \ingroup tests
+ *
+ * \brief  Test bounds for various WrapTo... methods (WrapTo180, WrapTo360, WrapToPi, and WrapTo2Pi)
+ * by using a std::function wrapper
+ */
+class WrapToRangeTestCase : public TestCase
+{
+  public:
+    /**
+     * Build the test name
+     * \param lowerBound the lower bound of the WrapTo... function
+     * \param upperBound the upper bound of the WrapTo... function
+     * \return the test name
+     */
+    static std::string BuildNameString(double lowerBound, double upperBound);
+    /**
+     * Constructor
+     * \param wrapper for one of WrapTo180, WrapTo360, WrapToPi, and WrapTo2Pi
+     * \param lowerBound the corresponding lower bound
+     * \param upperBound the corresponding upper bound
+     */
+    WrapToRangeTestCase(WrapToRangeFunction wrapper, double lowerBound, double upperBound);
+
+  protected:
+    /**
+     * The given wrapper shall wrap an angle into the expected range
+     * \param wrapPoint an angle
+     */
+    void CheckWrappingPoint(double wrapPoint);
+
+  private:
+    void DoRun() override;
+
+    WrapToRangeFunction m_wrapper; //!< the wrapper function
+    double m_lowerBound;           //!< the corresponding lower bound
+    double m_upperBound;           //!< the corresponding upper bound
+};
+
+std::string
+WrapToRangeTestCase::BuildNameString(double lowerBound, double upperBound)
+{
+    std::ostringstream oss;
+    oss << "WrapTo [" << lowerBound << ", " << upperBound << ")";
+    return oss.str();
+}
+
+WrapToRangeTestCase::WrapToRangeTestCase(WrapToRangeFunction wrapper,
+                                         double lowerBound,
+                                         double upperBound)
+    : TestCase(BuildNameString(lowerBound, upperBound)),
+      m_wrapper(wrapper),
+      m_lowerBound(lowerBound),
+      m_upperBound(upperBound)
+{
+}
+
+void
+WrapToRangeTestCase::DoRun()
+{
+    CheckWrappingPoint(m_lowerBound);
+    CheckWrappingPoint(m_upperBound);
+}
+
+void
+WrapToRangeTestCase::CheckWrappingPoint(double wrapPoint)
+{
+    constexpr int STEP_NUM = 100;
+    double directions[] = {std::numeric_limits<double>::lowest(),
+                           std::numeric_limits<double>::max()};
+    for (double dir : directions)
+    {
+        int i = 0;
+        for (double x = wrapPoint; i < STEP_NUM; x = std::nextafter(x, dir), ++i)
+        {
+            // If asserts are enabled, this test will crash with an assert instead of failing
+            double result = m_wrapper(x);
+            NS_TEST_EXPECT_MSG_EQ((m_lowerBound <= result),
+                                  true,
+                                  "Invalid wrap (too low) " << x << " maps to " << result << " and "
+                                                            << result - m_lowerBound);
+            NS_TEST_EXPECT_MSG_EQ((result < m_upperBound),
+                                  true,
+                                  "Invalid wrap (too high) " << x << " maps to " << result
+                                                             << " and " << result - m_lowerBound);
+        }
+    }
+}
+
+/**
+ * \ingroup tests
+ *
+ * \brief Test the output for WrapToRangeFunction
+ */
+class WrapToRangeFunctionalTestCase : public TestCase
+{
+  public:
+    /**
+     * Build the test name
+     * \param angle the angle
+     * \param wrappedAngle the expected result
+     * \return the test name
+     */
+    static std::string BuildNameString(double angle, double wrappedAngle);
+    /**
+     * Constructor
+     * \param wrapper one WrapToRangeFunction
+     * \param angle the angle
+     * \param wrappedAngle the expected result
+     */
+    WrapToRangeFunctionalTestCase(WrapToRangeFunction wrapper, double angle, double wrappedAngle);
+
+  private:
+    void DoRun() override;
+
+    WrapToRangeFunction m_wrapper; //!< the wrapper function
+    double m_angle;                //!< the input angle
+    double m_wrappedAngle;         //!< the expected wrapper angle
+};
+
+std::string
+WrapToRangeFunctionalTestCase::BuildNameString(double angle, double wrappedAngle)
+{
+    std::ostringstream oss;
+    oss << "Wrap " << angle << " to " << wrappedAngle;
+    return oss.str();
+}
+
+WrapToRangeFunctionalTestCase::WrapToRangeFunctionalTestCase(WrapToRangeFunction wrapper,
+                                                             double angle,
+                                                             double wrappedAngle)
+    : TestCase(BuildNameString(angle, wrappedAngle)),
+      m_wrapper(wrapper),
+      m_angle(angle),
+      m_wrappedAngle(wrappedAngle)
+{
+}
+
+void
+WrapToRangeFunctionalTestCase::DoRun()
+{
+    NS_TEST_EXPECT_MSG_EQ_TOL(m_wrapper(m_angle),
+                              m_wrappedAngle,
+                              1e-6,
+                              "Invalid wrap " << m_angle << " wrapped to " << m_wrapper(m_angle)
+                                              << " instead of " << m_wrappedAngle);
+}
+
 /**
  * \ingroup tests
  *
@@ -355,6 +505,18 @@
                                                   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);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/aodv/helper/aodv-helper.cc ns-3.40/src/aodv/helper/aodv-helper.cc
--- ns-3.39/src/aodv/helper/aodv-helper.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/aodv/helper/aodv-helper.cc	2023-09-27 13:30:37.610839000 -0700
@@ -59,7 +59,7 @@
 {
     int64_t currentStream = stream;
     Ptr<Node> node;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         node = (*i);
         Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/aodv/model/aodv-id-cache.cc ns-3.40/src/aodv/model/aodv-id-cache.cc
--- ns-3.39/src/aodv/model/aodv-id-cache.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/aodv/model/aodv-id-cache.cc	2023-09-27 13:30:37.610839000 -0700
@@ -36,7 +36,7 @@
 IdCache::IsDuplicate(Ipv4Address addr, uint32_t id)
 {
     Purge();
-    for (std::vector<UniqueId>::const_iterator i = m_idCache.begin(); i != m_idCache.end(); ++i)
+    for (auto i = m_idCache.begin(); i != m_idCache.end(); ++i)
     {
         if (i->m_context == addr && i->m_id == id)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/aodv/model/aodv-neighbor.cc ns-3.40/src/aodv/model/aodv-neighbor.cc
--- ns-3.39/src/aodv/model/aodv-neighbor.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/aodv/model/aodv-neighbor.cc	2023-09-27 13:30:37.610839000 -0700
@@ -51,7 +51,7 @@
 Neighbors::IsNeighbor(Ipv4Address addr)
 {
     Purge();
-    for (std::vector<Neighbor>::const_iterator i = m_nb.begin(); i != m_nb.end(); ++i)
+    for (auto i = m_nb.begin(); i != m_nb.end(); ++i)
     {
         if (i->m_neighborAddress == addr)
         {
@@ -65,7 +65,7 @@
 Neighbors::GetExpireTime(Ipv4Address addr)
 {
     Purge();
-    for (std::vector<Neighbor>::const_iterator i = m_nb.begin(); i != m_nb.end(); ++i)
+    for (auto i = m_nb.begin(); i != m_nb.end(); ++i)
     {
         if (i->m_neighborAddress == addr)
         {
@@ -78,7 +78,7 @@
 void
 Neighbors::Update(Ipv4Address addr, Time expire)
 {
-    for (std::vector<Neighbor>::iterator i = m_nb.begin(); i != m_nb.end(); ++i)
+    for (auto i = m_nb.begin(); i != m_nb.end(); ++i)
     {
         if (i->m_neighborAddress == addr)
         {
@@ -125,7 +125,7 @@
     CloseNeighbor pred;
     if (!m_handleLinkFailure.IsNull())
     {
-        for (std::vector<Neighbor>::iterator j = m_nb.begin(); j != m_nb.end(); ++j)
+        for (auto j = m_nb.begin(); j != m_nb.end(); ++j)
         {
             if (pred(*j))
             {
@@ -162,7 +162,7 @@
 Neighbors::LookupMacAddress(Ipv4Address addr)
 {
     Mac48Address hwaddr;
-    for (std::vector<Ptr<ArpCache>>::const_iterator i = m_arp.begin(); i != m_arp.end(); ++i)
+    for (auto i = m_arp.begin(); i != m_arp.end(); ++i)
     {
         ArpCache::Entry* entry = (*i)->Lookup(addr);
         if (entry != nullptr && (entry->IsAlive() || entry->IsPermanent()) && !entry->IsExpired())
@@ -179,7 +179,7 @@
 {
     Mac48Address addr = hdr.GetAddr1();
 
-    for (std::vector<Neighbor>::iterator i = m_nb.begin(); i != m_nb.end(); ++i)
+    for (auto i = m_nb.begin(); i != m_nb.end(); ++i)
     {
         if (i->m_hardwareAddress == addr)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/aodv/model/aodv-packet.cc ns-3.40/src/aodv/model/aodv-packet.cc
--- ns-3.39/src/aodv/model/aodv-packet.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/aodv/model/aodv-packet.cc	2023-09-27 13:30:37.610839000 -0700
@@ -554,8 +554,7 @@
     i.WriteU8(m_flag);
     i.WriteU8(m_reserved);
     i.WriteU8(GetDestCount());
-    std::map<Ipv4Address, uint32_t>::const_iterator j;
-    for (j = m_unreachableDstSeqNo.begin(); j != m_unreachableDstSeqNo.end(); ++j)
+    for (auto j = m_unreachableDstSeqNo.begin(); j != m_unreachableDstSeqNo.end(); ++j)
     {
         WriteTo(i, (*j).first);
         i.WriteHtonU32((*j).second);
@@ -588,8 +587,7 @@
 RerrHeader::Print(std::ostream& os) const
 {
     os << "Unreachable destination (ipv4 address, seq. number):";
-    std::map<Ipv4Address, uint32_t>::const_iterator j;
-    for (j = m_unreachableDstSeqNo.begin(); j != m_unreachableDstSeqNo.end(); ++j)
+    for (auto j = m_unreachableDstSeqNo.begin(); j != m_unreachableDstSeqNo.end(); ++j)
     {
         os << (*j).first << ", " << (*j).second;
     }
@@ -635,7 +633,7 @@
     {
         return false;
     }
-    std::map<Ipv4Address, uint32_t>::iterator i = m_unreachableDstSeqNo.begin();
+    auto i = m_unreachableDstSeqNo.begin();
     un = *i;
     m_unreachableDstSeqNo.erase(i);
     return true;
@@ -657,8 +655,8 @@
         return false;
     }
 
-    std::map<Ipv4Address, uint32_t>::const_iterator j = m_unreachableDstSeqNo.begin();
-    std::map<Ipv4Address, uint32_t>::const_iterator k = o.m_unreachableDstSeqNo.begin();
+    auto j = m_unreachableDstSeqNo.begin();
+    auto k = o.m_unreachableDstSeqNo.begin();
     for (uint8_t i = 0; i < GetDestCount(); ++i)
     {
         if ((j->first != k->first) || (j->second != k->second))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/aodv/model/aodv-routing-protocol.cc ns-3.40/src/aodv/model/aodv-routing-protocol.cc
--- ns-3.39/src/aodv/model/aodv-routing-protocol.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/aodv/model/aodv-routing-protocol.cc	2023-09-27 13:30:37.614839000 -0700
@@ -362,15 +362,12 @@
 RoutingProtocol::DoDispose()
 {
     m_ipv4 = nullptr;
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::iterator iter = m_socketAddresses.begin();
-         iter != m_socketAddresses.end();
-         iter++)
+    for (auto iter = m_socketAddresses.begin(); iter != m_socketAddresses.end(); iter++)
     {
         iter->first->Close();
     }
     m_socketAddresses.clear();
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::iterator iter =
-             m_socketSubnetBroadcastAddresses.begin();
+    for (auto iter = m_socketSubnetBroadcastAddresses.begin();
          iter != m_socketSubnetBroadcastAddresses.end();
          iter++)
     {
@@ -541,9 +538,7 @@
     }
 
     // Broadcast local delivery/forwarding
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         Ipv4InterfaceAddress iface = j->second;
         if (m_ipv4->GetInterfaceForAddress(iface.GetLocal()) == iif)
@@ -984,9 +979,7 @@
 RoutingProtocol::IsMyOwnAddress(Ipv4Address src)
 {
     NS_LOG_FUNCTION(this << src);
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         Ipv4InterfaceAddress iface = j->second;
         if (src == iface.GetLocal())
@@ -1020,7 +1013,7 @@
     // If RouteOutput() caller specified an outgoing interface, that
     // further constrains the selection of source address
     //
-    std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
+    auto j = m_socketAddresses.begin();
     if (oif)
     {
         // Iterate to find an address on the oif device
@@ -1136,9 +1129,7 @@
     rreqHeader.SetId(m_requestId);
 
     // Send RREQ as subnet directed broadcast from each interface used by aodv
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         Ptr<Socket> socket = j->first;
         Ipv4InterfaceAddress iface = j->second;
@@ -1505,9 +1496,7 @@
         return;
     }
 
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         Ptr<Socket> socket = j->first;
         Ipv4InterfaceAddress iface = j->second;
@@ -1868,9 +1857,7 @@
     std::pair<Ipv4Address, uint32_t> un;
     while (rerrHeader.RemoveUnDestination(un))
     {
-        for (std::map<Ipv4Address, uint32_t>::const_iterator i = dstWithNextHopSrc.begin();
-             i != dstWithNextHopSrc.end();
-             ++i)
+        for (auto i = dstWithNextHopSrc.begin(); i != dstWithNextHopSrc.end(); ++i)
         {
             if (i->first == un.first)
             {
@@ -1880,8 +1867,7 @@
     }
 
     std::vector<Ipv4Address> precursors;
-    for (std::map<Ipv4Address, uint32_t>::const_iterator i = unreachable.begin();
-         i != unreachable.end();)
+    for (auto i = unreachable.begin(); i != unreachable.end();)
     {
         if (!rerrHeader.AddUnDestination(i->first, i->second))
         {
@@ -2013,9 +1999,7 @@
      *   Hop Count                      0
      *   Lifetime                       AllowedHelloLoss * HelloInterval
      */
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         Ptr<Socket> socket = j->first;
         Ipv4InterfaceAddress iface = j->second;
@@ -2087,8 +2071,7 @@
     toNextHop.GetPrecursors(precursors);
     rerrHeader.AddUnDestination(nextHop, toNextHop.GetSeqNo());
     m_routingTable.GetListOfDestinationWithNextHop(nextHop, unreachable);
-    for (std::map<Ipv4Address, uint32_t>::const_iterator i = unreachable.begin();
-         i != unreachable.end();)
+    for (auto i = unreachable.begin(); i != unreachable.end();)
     {
         if (!rerrHeader.AddUnDestination(i->first, i->second))
         {
@@ -2161,10 +2144,7 @@
     }
     else
     {
-        for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator i =
-                 m_socketAddresses.begin();
-             i != m_socketAddresses.end();
-             ++i)
+        for (auto i = m_socketAddresses.begin(); i != m_socketAddresses.end(); ++i)
         {
             Ptr<Socket> socket = i->first;
             Ipv4InterfaceAddress iface = i->second;
@@ -2232,8 +2212,7 @@
     //  route
     std::vector<Ipv4InterfaceAddress> ifaces;
     RoutingTableEntry toPrecursor;
-    for (std::vector<Ipv4Address>::const_iterator i = precursors.begin(); i != precursors.end();
-         ++i)
+    for (auto i = precursors.begin(); i != precursors.end(); ++i)
     {
         if (m_routingTable.LookupValidRoute(*i, toPrecursor) &&
             std::find(ifaces.begin(), ifaces.end(), toPrecursor.GetInterface()) == ifaces.end())
@@ -2242,8 +2221,7 @@
         }
     }
 
-    for (std::vector<Ipv4InterfaceAddress>::const_iterator i = ifaces.begin(); i != ifaces.end();
-         ++i)
+    for (auto i = ifaces.begin(); i != ifaces.end(); ++i)
     {
         Ptr<Socket> socket = FindSocketWithInterfaceAddress(*i);
         NS_ASSERT(socket);
@@ -2273,9 +2251,7 @@
 RoutingProtocol::FindSocketWithInterfaceAddress(Ipv4InterfaceAddress addr) const
 {
     NS_LOG_FUNCTION(this << addr);
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         Ptr<Socket> socket = j->first;
         Ipv4InterfaceAddress iface = j->second;
@@ -2292,8 +2268,7 @@
 RoutingProtocol::FindSubnetBroadcastSocketWithInterfaceAddress(Ipv4InterfaceAddress addr) const
 {
     NS_LOG_FUNCTION(this << addr);
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j =
-             m_socketSubnetBroadcastAddresses.begin();
+    for (auto j = m_socketSubnetBroadcastAddresses.begin();
          j != m_socketSubnetBroadcastAddresses.end();
          ++j)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/aodv/model/aodv-rqueue.cc ns-3.40/src/aodv/model/aodv-rqueue.cc
--- ns-3.39/src/aodv/model/aodv-rqueue.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/aodv/model/aodv-rqueue.cc	2023-09-27 13:30:37.614839000 -0700
@@ -51,7 +51,7 @@
 RequestQueue::Enqueue(QueueEntry& entry)
 {
     Purge();
-    for (std::vector<QueueEntry>::const_iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if ((i->GetPacket()->GetUid() == entry.GetPacket()->GetUid()) &&
             (i->GetIpv4Header().GetDestination() == entry.GetIpv4Header().GetDestination()))
@@ -74,7 +74,7 @@
 {
     NS_LOG_FUNCTION(this << dst);
     Purge();
-    for (std::vector<QueueEntry>::iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if (i->GetIpv4Header().GetDestination() == dst)
         {
@@ -91,7 +91,7 @@
 RequestQueue::Dequeue(Ipv4Address dst, QueueEntry& entry)
 {
     Purge();
-    for (std::vector<QueueEntry>::iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if (i->GetIpv4Header().GetDestination() == dst)
         {
@@ -106,7 +106,7 @@
 bool
 RequestQueue::Find(Ipv4Address dst)
 {
-    for (std::vector<QueueEntry>::const_iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if (i->GetIpv4Header().GetDestination() == dst)
         {
@@ -138,7 +138,7 @@
 RequestQueue::Purge()
 {
     IsExpired pred;
-    for (std::vector<QueueEntry>::iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if (pred(*i))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/aodv/model/aodv-rtable.cc ns-3.40/src/aodv/model/aodv-rtable.cc
--- ns-3.39/src/aodv/model/aodv-rtable.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/aodv/model/aodv-rtable.cc	2023-09-27 13:30:37.614839000 -0700
@@ -94,9 +94,7 @@
 RoutingTableEntry::LookupPrecursor(Ipv4Address id)
 {
     NS_LOG_FUNCTION(this << id);
-    for (std::vector<Ipv4Address>::const_iterator i = m_precursorList.begin();
-         i != m_precursorList.end();
-         ++i)
+    for (auto i = m_precursorList.begin(); i != m_precursorList.end(); ++i)
     {
         if (*i == id)
         {
@@ -112,8 +110,7 @@
 RoutingTableEntry::DeletePrecursor(Ipv4Address id)
 {
     NS_LOG_FUNCTION(this << id);
-    std::vector<Ipv4Address>::iterator i =
-        std::remove(m_precursorList.begin(), m_precursorList.end(), id);
+    auto i = std::remove(m_precursorList.begin(), m_precursorList.end(), id);
     if (i == m_precursorList.end())
     {
         NS_LOG_LOGIC("Precursor " << id << " not found");
@@ -148,16 +145,15 @@
     {
         return;
     }
-    for (std::vector<Ipv4Address>::const_iterator i = m_precursorList.begin();
-         i != m_precursorList.end();
-         ++i)
+    for (auto i = m_precursorList.begin(); i != m_precursorList.end(); ++i)
     {
         bool result = true;
-        for (std::vector<Ipv4Address>::const_iterator j = prec.begin(); j != prec.end(); ++j)
+        for (auto j = prec.begin(); j != prec.end(); ++j)
         {
             if (*j == *i)
             {
                 result = false;
+                break;
             }
         }
         if (result)
@@ -243,7 +239,7 @@
         NS_LOG_LOGIC("Route to " << id << " not found; m_ipv4AddressEntry is empty");
         return false;
     }
-    std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = m_ipv4AddressEntry.find(id);
+    auto i = m_ipv4AddressEntry.find(id);
     if (i == m_ipv4AddressEntry.end())
     {
         NS_LOG_LOGIC("Route to " << id << " not found");
@@ -291,8 +287,7 @@
     {
         rt.SetRreqCnt(0);
     }
-    std::pair<std::map<Ipv4Address, RoutingTableEntry>::iterator, bool> result =
-        m_ipv4AddressEntry.insert(std::make_pair(rt.GetDestination(), rt));
+    auto result = m_ipv4AddressEntry.insert(std::make_pair(rt.GetDestination(), rt));
     return result.second;
 }
 
@@ -300,8 +295,7 @@
 RoutingTable::Update(RoutingTableEntry& rt)
 {
     NS_LOG_FUNCTION(this);
-    std::map<Ipv4Address, RoutingTableEntry>::iterator i =
-        m_ipv4AddressEntry.find(rt.GetDestination());
+    auto i = m_ipv4AddressEntry.find(rt.GetDestination());
     if (i == m_ipv4AddressEntry.end())
     {
         NS_LOG_LOGIC("Route update to " << rt.GetDestination() << " fails; not found");
@@ -320,7 +314,7 @@
 RoutingTable::SetEntryState(Ipv4Address id, RouteFlags state)
 {
     NS_LOG_FUNCTION(this);
-    std::map<Ipv4Address, RoutingTableEntry>::iterator i = m_ipv4AddressEntry.find(id);
+    auto i = m_ipv4AddressEntry.find(id);
     if (i == m_ipv4AddressEntry.end())
     {
         NS_LOG_LOGIC("Route set entry state to " << id << " fails; not found");
@@ -339,9 +333,7 @@
     NS_LOG_FUNCTION(this);
     Purge();
     unreachable.clear();
-    for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = m_ipv4AddressEntry.begin();
-         i != m_ipv4AddressEntry.end();
-         ++i)
+    for (auto i = m_ipv4AddressEntry.begin(); i != m_ipv4AddressEntry.end(); ++i)
     {
         if (i->second.GetNextHop() == nextHop)
         {
@@ -356,13 +348,9 @@
 {
     NS_LOG_FUNCTION(this);
     Purge();
-    for (std::map<Ipv4Address, RoutingTableEntry>::iterator i = m_ipv4AddressEntry.begin();
-         i != m_ipv4AddressEntry.end();
-         ++i)
-    {
-        for (std::map<Ipv4Address, uint32_t>::const_iterator j = unreachable.begin();
-             j != unreachable.end();
-             ++j)
+    for (auto i = m_ipv4AddressEntry.begin(); i != m_ipv4AddressEntry.end(); ++i)
+    {
+        for (auto j = unreachable.begin(); j != unreachable.end(); ++j)
         {
             if ((i->first == j->first) && (i->second.GetFlag() == VALID))
             {
@@ -381,12 +369,11 @@
     {
         return;
     }
-    for (std::map<Ipv4Address, RoutingTableEntry>::iterator i = m_ipv4AddressEntry.begin();
-         i != m_ipv4AddressEntry.end();)
+    for (auto i = m_ipv4AddressEntry.begin(); i != m_ipv4AddressEntry.end();)
     {
         if (i->second.GetInterface() == iface)
         {
-            std::map<Ipv4Address, RoutingTableEntry>::iterator tmp = i;
+            auto tmp = i;
             ++i;
             m_ipv4AddressEntry.erase(tmp);
         }
@@ -405,14 +392,13 @@
     {
         return;
     }
-    for (std::map<Ipv4Address, RoutingTableEntry>::iterator i = m_ipv4AddressEntry.begin();
-         i != m_ipv4AddressEntry.end();)
+    for (auto i = m_ipv4AddressEntry.begin(); i != m_ipv4AddressEntry.end();)
     {
         if (i->second.GetLifeTime() < Seconds(0))
         {
             if (i->second.GetFlag() == INVALID)
             {
-                std::map<Ipv4Address, RoutingTableEntry>::iterator tmp = i;
+                auto tmp = i;
                 ++i;
                 m_ipv4AddressEntry.erase(tmp);
             }
@@ -442,13 +428,13 @@
     {
         return;
     }
-    for (std::map<Ipv4Address, RoutingTableEntry>::iterator i = table.begin(); i != table.end();)
+    for (auto i = table.begin(); i != table.end();)
     {
         if (i->second.GetLifeTime() < Seconds(0))
         {
             if (i->second.GetFlag() == INVALID)
             {
-                std::map<Ipv4Address, RoutingTableEntry>::iterator tmp = i;
+                auto tmp = i;
                 ++i;
                 table.erase(tmp);
             }
@@ -474,7 +460,7 @@
 RoutingTable::MarkLinkAsUnidirectional(Ipv4Address neighbor, Time blacklistTimeout)
 {
     NS_LOG_FUNCTION(this << neighbor << blacklistTimeout.As(Time::S));
-    std::map<Ipv4Address, RoutingTableEntry>::iterator i = m_ipv4AddressEntry.find(neighbor);
+    auto i = m_ipv4AddressEntry.find(neighbor);
     if (i == m_ipv4AddressEntry.end())
     {
         NS_LOG_LOGIC("Mark link unidirectional to  " << neighbor << " fails; not found");
@@ -505,9 +491,7 @@
     *os << std::setw(16) << "Flag";
     *os << std::setw(16) << "Expire";
     *os << "Hops" << std::endl;
-    for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = table.begin();
-         i != table.end();
-         ++i)
+    for (auto i = table.begin(); i != table.end(); ++i)
     {
         i->second.Print(stream, unit);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/aodv/test/aodv-test-suite.cc ns-3.40/src/aodv/test/aodv-test-suite.cc
--- ns-3.39/src/aodv/test/aodv-test-suite.cc	2023-07-05 14:23:47.673426900 -0700
+++ ns-3.40/src/aodv/test/aodv-test-suite.cc	2023-09-27 13:30:37.614839000 -0700
@@ -317,11 +317,11 @@
         RerrHeader h;
         h.SetNoDelete(true);
         NS_TEST_EXPECT_MSG_EQ(h.GetNoDelete(), true, "trivial");
-        Ipv4Address dst = Ipv4Address("1.2.3.4");
+        Ipv4Address dst("1.2.3.4");
         NS_TEST_EXPECT_MSG_EQ(h.AddUnDestination(dst, 12), true, "trivial");
         NS_TEST_EXPECT_MSG_EQ(h.GetDestCount(), 1, "trivial");
         NS_TEST_EXPECT_MSG_EQ(h.AddUnDestination(dst, 13), true, "trivial");
-        Ipv4Address dst2 = Ipv4Address("4.3.2.1");
+        Ipv4Address dst2("4.3.2.1");
         NS_TEST_EXPECT_MSG_EQ(h.AddUnDestination(dst2, 12), true, "trivial");
         NS_TEST_EXPECT_MSG_EQ(h.GetDestCount(), 2, "trivial");
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/helper/bulk-send-helper.cc ns-3.40/src/applications/helper/bulk-send-helper.cc
--- ns-3.39/src/applications/helper/bulk-send-helper.cc	2023-07-05 14:23:47.677426800 -0700
+++ ns-3.40/src/applications/helper/bulk-send-helper.cc	2023-09-27 13:30:37.614839000 -0700
@@ -59,7 +59,7 @@
 BulkSendHelper::Install(NodeContainer c) const
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         apps.Add(InstallPriv(*i));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/helper/on-off-helper.cc ns-3.40/src/applications/helper/on-off-helper.cc
--- ns-3.39/src/applications/helper/on-off-helper.cc	2023-07-05 14:23:47.677426800 -0700
+++ ns-3.40/src/applications/helper/on-off-helper.cc	2023-09-27 13:30:37.614839000 -0700
@@ -60,7 +60,7 @@
 OnOffHelper::Install(NodeContainer c) const
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         apps.Add(InstallPriv(*i));
     }
@@ -82,7 +82,7 @@
 {
     int64_t currentStream = stream;
     Ptr<Node> node;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         node = (*i);
         for (uint32_t j = 0; j < node->GetNApplications(); j++)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/helper/packet-sink-helper.cc ns-3.40/src/applications/helper/packet-sink-helper.cc
--- ns-3.39/src/applications/helper/packet-sink-helper.cc	2023-07-05 14:23:47.677426800 -0700
+++ ns-3.40/src/applications/helper/packet-sink-helper.cc	2023-09-27 13:30:37.614839000 -0700
@@ -56,7 +56,7 @@
 PacketSinkHelper::Install(NodeContainer c) const
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         apps.Add(InstallPriv(*i));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/helper/three-gpp-http-helper.cc ns-3.40/src/applications/helper/three-gpp-http-helper.cc
--- ns-3.39/src/applications/helper/three-gpp-http-helper.cc	2023-07-05 14:23:47.677426800 -0700
+++ ns-3.40/src/applications/helper/three-gpp-http-helper.cc	2023-09-27 13:30:37.614839000 -0700
@@ -61,7 +61,7 @@
 ThreeGppHttpClientHelper::Install(NodeContainer c) const
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         apps.Add(InstallPriv(*i));
     }
@@ -109,7 +109,7 @@
 ThreeGppHttpServerHelper::Install(NodeContainer c) const
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         apps.Add(InstallPriv(*i));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/helper/udp-client-server-helper.cc ns-3.40/src/applications/helper/udp-client-server-helper.cc
--- ns-3.39/src/applications/helper/udp-client-server-helper.cc	2023-07-05 14:23:47.677426800 -0700
+++ ns-3.40/src/applications/helper/udp-client-server-helper.cc	2023-09-27 13:30:37.614839000 -0700
@@ -48,7 +48,7 @@
 UdpServerHelper::Install(NodeContainer c)
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
 
@@ -93,7 +93,7 @@
 UdpClientHelper::Install(NodeContainer c)
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<UdpClient> client = m_factory.Create<UdpClient>();
@@ -133,7 +133,7 @@
 UdpTraceClientHelper::Install(NodeContainer c)
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<UdpTraceClient> client = m_factory.Create<UdpTraceClient>();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/helper/udp-echo-helper.cc ns-3.40/src/applications/helper/udp-echo-helper.cc
--- ns-3.39/src/applications/helper/udp-echo-helper.cc	2023-07-05 14:23:47.677426800 -0700
+++ ns-3.40/src/applications/helper/udp-echo-helper.cc	2023-09-27 13:30:37.614839000 -0700
@@ -55,7 +55,7 @@
 UdpEchoServerHelper::Install(NodeContainer c) const
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         apps.Add(InstallPriv(*i));
     }
@@ -129,7 +129,7 @@
 UdpEchoClientHelper::Install(NodeContainer c) const
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         apps.Add(InstallPriv(*i));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/application-packet-probe.cc ns-3.40/src/applications/model/application-packet-probe.cc
--- ns-3.39/src/applications/model/application-packet-probe.cc	2023-07-05 14:23:47.677426800 -0700
+++ ns-3.40/src/applications/model/application-packet-probe.cc	2023-09-27 13:30:37.614839000 -0700
@@ -20,7 +20,7 @@
  * Modified by: Mitch Watrous (watrous@u.washington.edu)
  */
 
-#include "ns3/application-packet-probe.h"
+#include "application-packet-probe.h"
 
 #include "ns3/config.h"
 #include "ns3/log.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/bulk-send-application.h ns-3.40/src/applications/model/bulk-send-application.h
--- ns-3.39/src/applications/model/bulk-send-application.h	2023-07-05 14:23:47.677426800 -0700
+++ ns-3.40/src/applications/model/bulk-send-application.h	2023-09-27 13:30:37.614839000 -0700
@@ -20,11 +20,12 @@
 #ifndef BULK_SEND_APPLICATION_H
 #define BULK_SEND_APPLICATION_H
 
+#include "seq-ts-size-header.h"
+
 #include "ns3/address.h"
 #include "ns3/application.h"
 #include "ns3/event-id.h"
 #include "ns3/ptr.h"
-#include "ns3/seq-ts-size-header.h"
 #include "ns3/traced-callback.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/onoff-application.h ns-3.40/src/applications/model/onoff-application.h
--- ns-3.39/src/applications/model/onoff-application.h	2023-07-05 14:23:47.677426800 -0700
+++ ns-3.40/src/applications/model/onoff-application.h	2023-09-27 13:30:37.614839000 -0700
@@ -24,12 +24,13 @@
 #ifndef ONOFF_APPLICATION_H
 #define ONOFF_APPLICATION_H
 
+#include "seq-ts-size-header.h"
+
 #include "ns3/address.h"
 #include "ns3/application.h"
 #include "ns3/data-rate.h"
 #include "ns3/event-id.h"
 #include "ns3/ptr.h"
-#include "ns3/seq-ts-size-header.h"
 #include "ns3/traced-callback.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/packet-loss-counter.cc ns-3.40/src/applications/model/packet-loss-counter.cc
--- ns-3.39/src/applications/model/packet-loss-counter.cc	2023-07-05 14:23:47.677426800 -0700
+++ ns-3.40/src/applications/model/packet-loss-counter.cc	2023-09-27 13:30:37.614839000 -0700
@@ -113,14 +113,14 @@
     NS_LOG_FUNCTION(this << seqNum);
     for (uint32_t i = m_lastMaxSeqNum + 1; i <= seqNum; i++)
     {
-        if (GetBit(i) != 1)
+        if (!GetBit(i))
         {
             NS_LOG_INFO("Packet lost: " << i - (m_bitMapSize * 8));
             m_lost++;
         }
-        SetBit(i, 0);
+        SetBit(i, false);
     }
-    SetBit(seqNum, 1);
+    SetBit(seqNum, true);
     if (seqNum > m_lastMaxSeqNum)
     {
         m_lastMaxSeqNum = seqNum;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/packet-sink.h ns-3.40/src/applications/model/packet-sink.h
--- ns-3.39/src/applications/model/packet-sink.h	2023-07-05 14:23:47.705427000 -0700
+++ ns-3.40/src/applications/model/packet-sink.h	2023-09-27 13:30:37.614839000 -0700
@@ -20,13 +20,14 @@
 #ifndef PACKET_SINK_H
 #define PACKET_SINK_H
 
+#include "seq-ts-size-header.h"
+
 #include "ns3/address.h"
 #include "ns3/application.h"
 #include "ns3/event-id.h"
 #include "ns3/inet-socket-address.h"
 #include "ns3/inet6-socket-address.h"
 #include "ns3/ptr.h"
-#include "ns3/seq-ts-size-header.h"
 #include "ns3/traced-callback.h"
 
 #include <unordered_map>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/seq-ts-size-header.h ns-3.40/src/applications/model/seq-ts-size-header.h
--- ns-3.39/src/applications/model/seq-ts-size-header.h	2023-07-05 14:23:47.705427000 -0700
+++ ns-3.40/src/applications/model/seq-ts-size-header.h	2023-09-27 13:30:37.614839000 -0700
@@ -20,7 +20,7 @@
 #ifndef SEQ_TS_SIZE_HEADER_H
 #define SEQ_TS_SIZE_HEADER_H
 
-#include <ns3/seq-ts-header.h>
+#include "seq-ts-header.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/three-gpp-http-client.cc ns-3.40/src/applications/model/three-gpp-http-client.cc
--- ns-3.39/src/applications/model/three-gpp-http-client.cc	2023-07-05 14:23:47.705427000 -0700
+++ ns-3.40/src/applications/model/three-gpp-http-client.cc	2023-09-27 13:30:37.614839000 -0700
@@ -20,6 +20,8 @@
 
 #include "three-gpp-http-client.h"
 
+#include "three-gpp-http-variables.h"
+
 #include <ns3/callback.h>
 #include <ns3/double.h>
 #include <ns3/inet-socket-address.h>
@@ -30,7 +32,6 @@
 #include <ns3/simulator.h>
 #include <ns3/socket.h>
 #include <ns3/tcp-socket-factory.h>
-#include <ns3/three-gpp-http-variables.h>
 #include <ns3/uinteger.h>
 
 NS_LOG_COMPONENT_DEFINE("ThreeGppHttpClient");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/three-gpp-http-client.h ns-3.40/src/applications/model/three-gpp-http-client.h
--- ns-3.39/src/applications/model/three-gpp-http-client.h	2023-07-05 14:23:47.705427000 -0700
+++ ns-3.40/src/applications/model/three-gpp-http-client.h	2023-09-27 13:30:37.614839000 -0700
@@ -21,9 +21,10 @@
 #ifndef THREE_GPP_HTTP_CLIENT_H
 #define THREE_GPP_HTTP_CLIENT_H
 
+#include "three-gpp-http-header.h"
+
 #include <ns3/address.h>
 #include <ns3/application.h>
-#include <ns3/three-gpp-http-header.h>
 #include <ns3/traced-callback.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/three-gpp-http-server.cc ns-3.40/src/applications/model/three-gpp-http-server.cc
--- ns-3.39/src/applications/model/three-gpp-http-server.cc	2023-07-05 14:23:47.705427000 -0700
+++ ns-3.40/src/applications/model/three-gpp-http-server.cc	2023-09-27 13:30:37.614839000 -0700
@@ -20,6 +20,8 @@
 
 #include "three-gpp-http-server.h"
 
+#include "three-gpp-http-variables.h"
+
 #include <ns3/callback.h>
 #include <ns3/config.h>
 #include <ns3/inet-socket-address.h>
@@ -31,7 +33,6 @@
 #include <ns3/socket.h>
 #include <ns3/tcp-socket-factory.h>
 #include <ns3/tcp-socket.h>
-#include <ns3/three-gpp-http-variables.h>
 #include <ns3/uinteger.h>
 
 NS_LOG_COMPONENT_DEFINE("ThreeGppHttpServer");
@@ -632,8 +633,7 @@
 bool
 ThreeGppHttpServerTxBuffer::IsSocketAvailable(Ptr<Socket> socket) const
 {
-    std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     return (it != m_txBuffer.end());
 }
 
@@ -659,8 +659,7 @@
 {
     NS_LOG_FUNCTION(this << socket);
 
-    std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
 
     if (!Simulator::IsExpired(it->second.nextServe))
@@ -683,8 +682,7 @@
 {
     NS_LOG_FUNCTION(this << socket);
 
-    std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
 
     if (!Simulator::IsExpired(it->second.nextServe))
@@ -715,8 +713,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
-    for (it = m_txBuffer.begin(); it != m_txBuffer.end(); ++it)
+    for (auto it = m_txBuffer.begin(); it != m_txBuffer.end(); ++it)
     {
         if (!Simulator::IsExpired(it->second.nextServe))
         {
@@ -738,8 +735,7 @@
 bool
 ThreeGppHttpServerTxBuffer::IsBufferEmpty(Ptr<Socket> socket) const
 {
-    std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
     return (it->second.txBufferSize == 0);
 }
@@ -747,8 +743,7 @@
 Time
 ThreeGppHttpServerTxBuffer::GetClientTs(Ptr<Socket> socket) const
 {
-    std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
     return it->second.clientTs;
 }
@@ -756,8 +751,7 @@
 ThreeGppHttpHeader::ContentType_t
 ThreeGppHttpServerTxBuffer::GetBufferContentType(Ptr<Socket> socket) const
 {
-    std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
     return it->second.txBufferContentType;
 }
@@ -765,8 +759,7 @@
 uint32_t
 ThreeGppHttpServerTxBuffer::GetBufferSize(Ptr<Socket> socket) const
 {
-    std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
     return it->second.txBufferSize;
 }
@@ -774,8 +767,7 @@
 bool
 ThreeGppHttpServerTxBuffer::HasTxedPartOfObject(Ptr<Socket> socket) const
 {
-    std::map<Ptr<Socket>, TxBuffer_t>::const_iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found");
     return it->second.hasTxedPartOfObject;
 }
@@ -791,8 +783,7 @@
                   "Unable to write an object without a proper Content-Type.");
     NS_ASSERT_MSG(objectSize > 0, "Unable to write a zero-sized object.");
 
-    std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
     NS_ASSERT_MSG(it->second.txBufferSize == 0,
                   "Cannot write to Tx buffer of socket "
@@ -809,8 +800,7 @@
 {
     NS_LOG_FUNCTION(this << socket << clientTs.As(Time::S));
 
-    std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
     it->second.nextServe = eventId;
     it->second.clientTs = clientTs;
@@ -823,8 +813,7 @@
 
     NS_ASSERT_MSG(amount > 0, "Unable to consume zero bytes.");
 
-    std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
     NS_ASSERT_MSG(it->second.txBufferSize >= amount,
                   "The requested amount is larger than the current buffer size.");
@@ -846,8 +835,7 @@
 ThreeGppHttpServerTxBuffer::PrepareClose(Ptr<Socket> socket)
 {
     NS_LOG_FUNCTION(this << socket);
-    std::map<Ptr<Socket>, TxBuffer_t>::iterator it;
-    it = m_txBuffer.find(socket);
+    auto it = m_txBuffer.find(socket);
     NS_ASSERT_MSG(it != m_txBuffer.end(), "Socket " << socket << " cannot be found.");
     it->second.isClosing = true;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/three-gpp-http-server.h ns-3.40/src/applications/model/three-gpp-http-server.h
--- ns-3.39/src/applications/model/three-gpp-http-server.h	2023-07-05 14:23:47.705427000 -0700
+++ ns-3.40/src/applications/model/three-gpp-http-server.h	2023-09-27 13:30:37.614839000 -0700
@@ -21,13 +21,14 @@
 #ifndef THREE_GPP_HTTP_SERVER_H
 #define THREE_GPP_HTTP_SERVER_H
 
+#include "three-gpp-http-header.h"
+
 #include <ns3/address.h>
 #include <ns3/application.h>
 #include <ns3/event-id.h>
 #include <ns3/nstime.h>
 #include <ns3/ptr.h>
 #include <ns3/simple-ref-count.h>
-#include <ns3/three-gpp-http-header.h>
 #include <ns3/traced-callback.h>
 
 #include <map>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/three-gpp-http-variables.cc ns-3.40/src/applications/model/three-gpp-http-variables.cc
--- ns-3.39/src/applications/model/three-gpp-http-variables.cc	2023-07-05 14:23:47.705427000 -0700
+++ ns-3.40/src/applications/model/three-gpp-http-variables.cc	2023-09-27 13:30:37.614839000 -0700
@@ -267,7 +267,7 @@
 ThreeGppHttpVariables::GetNumOfEmbeddedObjects()
 {
     // Validate parameters.
-    const uint32_t upperBound = static_cast<uint32_t>(m_numOfEmbeddedObjectsRng->GetBound());
+    const auto upperBound = static_cast<uint32_t>(m_numOfEmbeddedObjectsRng->GetBound());
     if (upperBound <= m_numOfEmbeddedObjectsScale)
     {
         NS_FATAL_ERROR("`NumOfEmbeddedObjectsMax` attribute "
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/applications/model/udp-trace-client.h ns-3.40/src/applications/model/udp-trace-client.h
--- ns-3.39/src/applications/model/udp-trace-client.h	2023-07-05 14:23:47.705427000 -0700
+++ ns-3.40/src/applications/model/udp-trace-client.h	2023-09-27 13:30:37.614839000 -0700
@@ -39,15 +39,18 @@
  *
  * \brief A trace based streamer
  *
- * Sends UDP packets based on a trace file of an MPEG4 stream
- * trace files could be downloaded form:
- * https://web.archive.org/web/20200729203634/https://earth-info.nga.mil/GandG/publications/tr8350.2/wgs84fin.pdf
+ * Sends UDP packets based on a trace file of a MPEG4 stream.
+ * Trace files can be downloaded from:
+ * http://trace.eas.asu.edu/mpeg4/index.html
  * (the 2 first lines of the file should be removed) A valid trace file is a file with 4 columns:
  * \li -1- the first one represents the frame index
  * \li -2- the second one indicates the type of the frame: I, P or B
  * \li -3- the third one indicates the time on which the frame was generated by the encoder
  * (integer, milliseconds) \li -4- the fourth one indicates the frame size in byte
  *
+ * Additional trace files can be generated from MPEG4 files using the tool
+ * available in https://pypi.org/project/trace-extractor/
+ *
  * If no valid MPEG4 trace file is provided to the application the trace from
  * g_defaultEntries array will be loaded.
  *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/bridge/helper/bridge-helper.cc ns-3.40/src/bridge/helper/bridge-helper.cc
--- ns-3.39/src/bridge/helper/bridge-helper.cc	2023-07-05 14:23:47.709426900 -0700
+++ ns-3.40/src/bridge/helper/bridge-helper.cc	2023-09-27 13:30:37.618839000 -0700
@@ -57,7 +57,7 @@
     devs.Add(dev);
     node->AddDevice(dev);
 
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         NS_LOG_LOGIC("**** Add BridgePort " << *i);
         dev->AddBridgePort(*i);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/bridge/model/bridge-channel.cc ns-3.40/src/bridge/model/bridge-channel.cc
--- ns-3.39/src/bridge/model/bridge-channel.cc	2023-07-05 14:23:47.709426900 -0700
+++ ns-3.40/src/bridge/model/bridge-channel.cc	2023-09-27 13:30:37.618839000 -0700
@@ -52,9 +52,7 @@
 {
     NS_LOG_FUNCTION_NOARGS();
 
-    for (std::vector<Ptr<Channel>>::iterator iter = m_bridgedChannels.begin();
-         iter != m_bridgedChannels.end();
-         iter++)
+    for (auto iter = m_bridgedChannels.begin(); iter != m_bridgedChannels.end(); iter++)
     {
         *iter = nullptr;
     }
@@ -71,9 +69,7 @@
 BridgeChannel::GetNDevices() const
 {
     uint32_t ndevices = 0;
-    for (std::vector<Ptr<Channel>>::const_iterator iter = m_bridgedChannels.begin();
-         iter != m_bridgedChannels.end();
-         iter++)
+    for (auto iter = m_bridgedChannels.begin(); iter != m_bridgedChannels.end(); iter++)
     {
         ndevices += (*iter)->GetNDevices();
     }
@@ -84,9 +80,7 @@
 BridgeChannel::GetDevice(std::size_t i) const
 {
     std::size_t ndevices = 0;
-    for (std::vector<Ptr<Channel>>::const_iterator iter = m_bridgedChannels.begin();
-         iter != m_bridgedChannels.end();
-         iter++)
+    for (auto iter = m_bridgedChannels.begin(); iter != m_bridgedChannels.end(); iter++)
     {
         if ((i - ndevices) < (*iter)->GetNDevices())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/bridge/model/bridge-net-device.cc ns-3.40/src/bridge/model/bridge-net-device.cc
--- ns-3.39/src/bridge/model/bridge-net-device.cc	2023-07-05 14:23:47.709426900 -0700
+++ ns-3.40/src/bridge/model/bridge-net-device.cc	2023-09-27 13:30:37.618839000 -0700
@@ -80,8 +80,7 @@
 BridgeNetDevice::DoDispose()
 {
     NS_LOG_FUNCTION_NOARGS();
-    for (std::vector<Ptr<NetDevice>>::iterator iter = m_ports.begin(); iter != m_ports.end();
-         iter++)
+    for (auto iter = m_ports.begin(); iter != m_ports.end(); iter++)
     {
         *iter = nullptr;
     }
@@ -163,8 +162,7 @@
     else
     {
         NS_LOG_LOGIC("No learned state: send through all ports");
-        for (std::vector<Ptr<NetDevice>>::iterator iter = m_ports.begin(); iter != m_ports.end();
-             iter++)
+        for (auto iter = m_ports.begin(); iter != m_ports.end(); iter++)
         {
             Ptr<NetDevice> port = *iter;
             if (port != incomingPort)
@@ -193,8 +191,7 @@
                  << ", protocol=" << protocol << ", src=" << src << ", dst=" << dst << ")");
     Learn(src, incomingPort);
 
-    for (std::vector<Ptr<NetDevice>>::iterator iter = m_ports.begin(); iter != m_ports.end();
-         iter++)
+    for (auto iter = m_ports.begin(); iter != m_ports.end(); iter++)
     {
         Ptr<NetDevice> port = *iter;
         if (port != incomingPort)
@@ -227,7 +224,7 @@
     if (m_enableLearning)
     {
         Time now = Simulator::Now();
-        std::map<Mac48Address, LearnedState>::iterator iter = m_learnState.find(source);
+        auto iter = m_learnState.find(source);
         if (iter != m_learnState.end())
         {
             LearnedState& state = iter->second;
@@ -420,8 +417,7 @@
     // data was not unicast or no state has been learned for that mac
     // address => flood through all ports.
     Ptr<Packet> pktCopy;
-    for (std::vector<Ptr<NetDevice>>::iterator iter = m_ports.begin(); iter != m_ports.end();
-         iter++)
+    for (auto iter = m_ports.begin(); iter != m_ports.end(); iter++)
     {
         pktCopy = packet->Copy();
         Ptr<NetDevice> port = *iter;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/bridge/model/bridge-net-device.h ns-3.40/src/bridge/model/bridge-net-device.h
--- ns-3.39/src/bridge/model/bridge-net-device.h	2023-07-05 14:23:47.709426900 -0700
+++ ns-3.40/src/bridge/model/bridge-net-device.h	2023-09-27 13:30:37.618839000 -0700
@@ -17,7 +17,8 @@
 #ifndef BRIDGE_NET_DEVICE_H
 #define BRIDGE_NET_DEVICE_H
 
-#include "ns3/bridge-channel.h"
+#include "bridge-channel.h"
+
 #include "ns3/mac48-address.h"
 #include "ns3/net-device.h"
 #include "ns3/nstime.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/brite/helper/brite-topology-helper.cc ns-3.40/src/brite/helper/brite-topology-helper.cc
--- ns-3.39/src/brite/helper/brite-topology-helper.cc	2023-07-05 14:23:47.713427000 -0700
+++ ns-3.40/src/brite/helper/brite-topology-helper.cc	2023-09-27 13:30:37.618839000 -0700
@@ -186,10 +186,9 @@
 {
     NS_LOG_FUNCTION(this);
     brite::Graph* g = m_topology->GetGraph();
-    std::list<brite::Edge*>::iterator el;
     std::list<brite::Edge*> edgeList = g->GetEdges();
 
-    for (el = edgeList.begin(); el != edgeList.end(); el++)
+    for (auto el = edgeList.begin(); el != edgeList.end(); el++)
     {
         BriteEdgeInfo edgeInfo;
         edgeInfo.edgeId = (*el)->GetId();
@@ -418,9 +417,7 @@
     }
 
     // create nodes
-    for (BriteTopologyHelper::BriteNodeInfoList::iterator it = m_briteNodeInfoList.begin();
-         it != m_briteNodeInfoList.end();
-         ++it)
+    for (auto it = m_briteNodeInfoList.begin(); it != m_briteNodeInfoList.end(); ++it)
     {
         m_nodes.Add(CreateObject<Node>(GetSystemNumberForAs((*it).asId)));
         m_numNodes++;
@@ -468,9 +465,7 @@
         m_nodesByAs.push_back(new NodeContainer());
     }
 
-    for (BriteTopologyHelper::BriteEdgeInfoList::iterator it = m_briteEdgeInfoList.begin();
-         it != m_briteEdgeInfoList.end();
-         ++it)
+    for (auto it = m_briteEdgeInfoList.begin(); it != m_briteEdgeInfoList.end(); ++it)
     {
         // Set the link delay
         // The brite value for delay is given in milliseconds
@@ -492,9 +487,7 @@
     NS_LOG_INFO("Created " << m_numEdges << " edges in BRITE topology");
 
     // iterate through all nodes and add leaf nodes for each AS
-    for (BriteTopologyHelper::BriteNodeInfoList::iterator it = m_briteNodeInfoList.begin();
-         it != m_briteNodeInfoList.end();
-         ++it)
+    for (auto it = m_briteNodeInfoList.begin(); it != m_briteNodeInfoList.end(); ++it)
     {
         m_nodesByAs[(*it).asId]->Add(m_nodes.Get((*it).nodeId));
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/examples/outdoor-group-mobility-example.cc ns-3.40/src/buildings/examples/outdoor-group-mobility-example.cc
--- ns-3.39/src/buildings/examples/outdoor-group-mobility-example.cc	2023-07-05 14:23:47.713427000 -0700
+++ ns-3.40/src/buildings/examples/outdoor-group-mobility-example.cc	2023-09-27 13:30:37.618839000 -0700
@@ -111,7 +111,7 @@
         return;
     }
     uint32_t index = 1;
-    for (BuildingList::Iterator it = BuildingList::Begin(); it != BuildingList::End(); ++it)
+    for (auto it = BuildingList::Begin(); it != BuildingList::End(); ++it)
     {
         ++index;
         Box box = (*it)->GetBoundaries();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/examples/outdoor-random-walk-example.cc ns-3.40/src/buildings/examples/outdoor-random-walk-example.cc
--- ns-3.39/src/buildings/examples/outdoor-random-walk-example.cc	2023-07-05 14:23:47.713427000 -0700
+++ ns-3.40/src/buildings/examples/outdoor-random-walk-example.cc	2023-09-27 13:30:37.618839000 -0700
@@ -44,7 +44,7 @@
         return;
     }
     uint32_t index = 0;
-    for (BuildingList::Iterator it = BuildingList::Begin(); it != BuildingList::End(); ++it)
+    for (auto it = BuildingList::Begin(); it != BuildingList::End(); ++it)
     {
         ++index;
         Box box = (*it)->GetBoundaries();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/helper/building-allocator.h ns-3.40/src/buildings/helper/building-allocator.h
--- ns-3.39/src/buildings/helper/building-allocator.h	2023-07-05 14:23:47.713427000 -0700
+++ ns-3.40/src/buildings/helper/building-allocator.h	2023-09-27 13:30:37.618839000 -0700
@@ -22,7 +22,8 @@
 #ifndef BUILDING_ALLOCATOR_H
 #define BUILDING_ALLOCATOR_H
 
-#include "ns3/building-container.h"
+#include "building-container.h"
+
 #include "ns3/object-factory.h"
 #include "ns3/object.h"
 #include "ns3/position-allocator.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/helper/building-container.cc ns-3.40/src/buildings/helper/building-container.cc
--- ns-3.39/src/buildings/helper/building-container.cc	2023-07-05 14:23:47.713427000 -0700
+++ ns-3.40/src/buildings/helper/building-container.cc	2023-09-27 13:30:37.618839000 -0700
@@ -77,7 +77,7 @@
 void
 BuildingContainer::Add(BuildingContainer other)
 {
-    for (Iterator i = other.Begin(); i != other.End(); i++)
+    for (auto i = other.Begin(); i != other.End(); i++)
     {
         m_buildings.push_back(*i);
     }
@@ -100,7 +100,7 @@
 BuildingContainer::GetGlobal()
 {
     BuildingContainer c;
-    for (BuildingList::Iterator i = BuildingList::Begin(); i != BuildingList::End(); ++i)
+    for (auto i = BuildingList::Begin(); i != BuildingList::End(); ++i)
     {
         c.Add(*i);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/helper/building-position-allocator.cc ns-3.40/src/buildings/helper/building-position-allocator.cc
--- ns-3.39/src/buildings/helper/building-position-allocator.cc	2023-07-05 14:23:47.713427000 -0700
+++ ns-3.40/src/buildings/helper/building-position-allocator.cc	2023-09-27 13:30:37.618839000 -0700
@@ -19,11 +19,12 @@
  */
 #include "building-position-allocator.h"
 
+#include "buildings-helper.h"
+
 #include "ns3/boolean.h"
 #include "ns3/box.h"
 #include "ns3/building-list.h"
 #include "ns3/building.h"
-#include "ns3/buildings-helper.h"
 #include "ns3/double.h"
 #include "ns3/enum.h"
 #include "ns3/log.h"
@@ -81,8 +82,7 @@
     {
         if (m_buildingListWithoutReplacement.empty())
         {
-            for (BuildingList::Iterator bit = BuildingList::Begin(); bit != BuildingList::End();
-                 ++bit)
+            for (auto bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
             {
                 m_buildingListWithoutReplacement.push_back(*bit);
             }
@@ -188,7 +188,7 @@
         NS_LOG_INFO("Position " << position);
 
         bool inside = false;
-        for (BuildingList::Iterator bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
+        for (auto bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
         {
             if ((*bit)->IsInside(position))
             {
@@ -254,7 +254,7 @@
 
     if (m_roomListWithoutReplacement.empty())
     {
-        for (BuildingList::Iterator bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
+        for (auto bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
         {
             NS_LOG_LOGIC("building " << (*bit)->GetId());
             for (uint32_t rx = 1; rx <= (*bit)->GetNRoomsX(); ++rx)
@@ -326,7 +326,7 @@
     m_rand = CreateObject<UniformRandomVariable>();
     m_nodeIt = m_nodes.Begin();
     // this is needed to make sure the building models associated with c have been initialized
-    for (NodeContainer::Iterator it = m_nodes.Begin(); it != m_nodes.End(); ++it)
+    for (auto it = m_nodes.Begin(); it != m_nodes.End(); ++it)
     {
         Ptr<MobilityModel> mm = (*it)->GetObject<MobilityModel>();
         NS_ASSERT_MSG(mm, "no mobility model aggregated to this node");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/helper/buildings-helper.cc ns-3.40/src/buildings/helper/buildings-helper.cc
--- ns-3.39/src/buildings/helper/buildings-helper.cc	2023-07-05 14:23:47.713427000 -0700
+++ ns-3.40/src/buildings/helper/buildings-helper.cc	2023-09-27 13:30:37.618839000 -0700
@@ -35,7 +35,7 @@
 void
 BuildingsHelper::Install(NodeContainer c)
 {
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Install(*i);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/building-list.cc ns-3.40/src/buildings/model/building-list.cc
--- ns-3.39/src/buildings/model/building-list.cc	2023-07-05 14:23:47.713427000 -0700
+++ ns-3.40/src/buildings/model/building-list.cc	2023-09-27 13:30:37.618839000 -0700
@@ -158,7 +158,7 @@
 BuildingListPriv::DoDispose()
 {
     NS_LOG_FUNCTION_NOARGS();
-    for (std::vector<Ptr<Building>>::iterator i = m_buildings.begin(); i != m_buildings.end(); i++)
+    for (auto i = m_buildings.begin(); i != m_buildings.end(); i++)
     {
         Ptr<Building> building = *i;
         building->Dispose();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/buildings-channel-condition-model.cc ns-3.40/src/buildings/model/buildings-channel-condition-model.cc
--- ns-3.39/src/buildings/model/buildings-channel-condition-model.cc	2023-07-05 14:23:47.713427000 -0700
+++ ns-3.40/src/buildings/model/buildings-channel-condition-model.cc	2023-09-27 13:30:37.618839000 -0700
@@ -18,11 +18,12 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include "ns3/buildings-channel-condition-model.h"
+#include "buildings-channel-condition-model.h"
+
+#include "building-list.h"
+#include "mobility-building-info.h"
 
-#include "ns3/building-list.h"
 #include "ns3/log.h"
-#include "ns3/mobility-building-info.h"
 #include "ns3/mobility-model.h"
 
 namespace ns3
@@ -170,7 +171,7 @@
 BuildingsChannelConditionModel::IsLineOfSightBlocked(const ns3::Vector& l1,
                                                      const ns3::Vector& l2) const
 {
-    for (BuildingList::Iterator bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
+    for (auto bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
     {
         if ((*bit)->IsIntersect(l1, l2))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/buildings-propagation-loss-model.cc ns-3.40/src/buildings/model/buildings-propagation-loss-model.cc
--- ns-3.39/src/buildings/model/buildings-propagation-loss-model.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/buildings-propagation-loss-model.cc	2023-09-27 13:30:37.618839000 -0700
@@ -21,13 +21,14 @@
 
 #include "buildings-propagation-loss-model.h"
 
+#include "mobility-building-info.h"
+
 #include "ns3/double.h"
 #include "ns3/enum.h"
 #include "ns3/log.h"
 #include "ns3/mobility-model.h"
 #include "ns3/pointer.h"
 #include "ns3/propagation-loss-model.h"
-#include <ns3/mobility-building-info.h>
 
 #include <cmath>
 
@@ -159,11 +160,10 @@
     Ptr<MobilityBuildingInfo> b1 = b->GetObject<MobilityBuildingInfo>();
     NS_ASSERT_MSG(a1 && b1, "BuildingsPropagationLossModel only works with MobilityBuildingInfo");
 
-    std::map<Ptr<MobilityModel>, std::map<Ptr<MobilityModel>, ShadowingLoss>>::iterator ait =
-        m_shadowingLossMap.find(a);
+    auto ait = m_shadowingLossMap.find(a);
     if (ait != m_shadowingLossMap.end())
     {
-        std::map<Ptr<MobilityModel>, ShadowingLoss>::iterator bit = ait->second.find(b);
+        auto bit = ait->second.find(b);
         if (bit != ait->second.end())
         {
             return (bit->second.GetLoss());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/buildings-propagation-loss-model.h ns-3.40/src/buildings/model/buildings-propagation-loss-model.h
--- ns-3.39/src/buildings/model/buildings-propagation-loss-model.h	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/buildings-propagation-loss-model.h	2023-09-27 13:30:37.618839000 -0700
@@ -22,11 +22,12 @@
 #ifndef BUILDINGS_PROPAGATION_LOSS_MODEL_H_
 #define BUILDINGS_PROPAGATION_LOSS_MODEL_H_
 
+#include "building.h"
+#include "mobility-building-info.h"
+
 #include "ns3/nstime.h"
 #include "ns3/propagation-loss-model.h"
 #include "ns3/random-variable-stream.h"
-#include <ns3/building.h>
-#include <ns3/mobility-building-info.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/hybrid-buildings-propagation-loss-model.cc ns-3.40/src/buildings/model/hybrid-buildings-propagation-loss-model.cc
--- ns-3.39/src/buildings/model/hybrid-buildings-propagation-loss-model.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/hybrid-buildings-propagation-loss-model.cc	2023-09-27 13:30:37.618839000 -0700
@@ -21,9 +21,11 @@
 
 #include "hybrid-buildings-propagation-loss-model.h"
 
+#include "itu-r-1238-propagation-loss-model.h"
+#include "mobility-building-info.h"
+
 #include "ns3/double.h"
 #include "ns3/enum.h"
-#include "ns3/itu-r-1238-propagation-loss-model.h"
 #include "ns3/itu-r-1411-los-propagation-loss-model.h"
 #include "ns3/itu-r-1411-nlos-over-rooftop-propagation-loss-model.h"
 #include "ns3/kun-2600-mhz-propagation-loss-model.h"
@@ -31,7 +33,6 @@
 #include "ns3/mobility-model.h"
 #include "ns3/okumura-hata-propagation-loss-model.h"
 #include "ns3/pointer.h"
-#include <ns3/mobility-building-info.h>
 
 #include <cmath>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/hybrid-buildings-propagation-loss-model.h ns-3.40/src/buildings/model/hybrid-buildings-propagation-loss-model.h
--- ns-3.39/src/buildings/model/hybrid-buildings-propagation-loss-model.h	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/hybrid-buildings-propagation-loss-model.h	2023-09-27 13:30:37.618839000 -0700
@@ -22,7 +22,8 @@
 #ifndef HYBRID_BUILDINGS_PROPAGATION_LOSS_MODEL_H_
 #define HYBRID_BUILDINGS_PROPAGATION_LOSS_MODEL_H_
 
-#include <ns3/buildings-propagation-loss-model.h>
+#include "buildings-propagation-loss-model.h"
+
 #include <ns3/propagation-environment.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/itu-r-1238-propagation-loss-model.cc ns-3.40/src/buildings/model/itu-r-1238-propagation-loss-model.cc
--- ns-3.39/src/buildings/model/itu-r-1238-propagation-loss-model.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/itu-r-1238-propagation-loss-model.cc	2023-09-27 13:30:37.618839000 -0700
@@ -20,11 +20,12 @@
  */
 #include "itu-r-1238-propagation-loss-model.h"
 
+#include "mobility-building-info.h"
+
 #include "ns3/double.h"
 #include "ns3/enum.h"
 #include "ns3/log.h"
 #include "ns3/mobility-model.h"
-#include <ns3/mobility-building-info.h>
 
 #include <cmath>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/mobility-building-info.cc ns-3.40/src/buildings/model/mobility-building-info.cc
--- ns-3.39/src/buildings/model/mobility-building-info.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/mobility-building-info.cc	2023-09-27 13:30:37.618839000 -0700
@@ -18,10 +18,12 @@
  *
  */
 
+#include "mobility-building-info.h"
+
+#include "building-list.h"
+
 #include <ns3/assert.h>
-#include <ns3/building-list.h>
 #include <ns3/log.h>
-#include <ns3/mobility-building-info.h>
 #include <ns3/pointer.h>
 #include <ns3/position-allocator.h>
 #include <ns3/simulator.h>
@@ -166,7 +168,7 @@
 {
     bool found = false;
     Vector pos = mm->GetPosition();
-    for (BuildingList::Iterator bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
+    for (auto bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
     {
         NS_LOG_LOGIC("checking building " << (*bit)->GetId() << " with boundaries "
                                           << (*bit)->GetBoundaries());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/mobility-building-info.h ns-3.40/src/buildings/model/mobility-building-info.h
--- ns-3.39/src/buildings/model/mobility-building-info.h	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/mobility-building-info.h	2023-09-27 13:30:37.618839000 -0700
@@ -20,8 +20,9 @@
 #ifndef MOBILITY_BUILDING_INFO_H
 #define MOBILITY_BUILDING_INFO_H
 
+#include "building.h"
+
 #include <ns3/box.h>
-#include <ns3/building.h>
 #include <ns3/constant-velocity-helper.h>
 #include <ns3/mobility-model.h>
 #include <ns3/object.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/oh-buildings-propagation-loss-model.cc ns-3.40/src/buildings/model/oh-buildings-propagation-loss-model.cc
--- ns-3.39/src/buildings/model/oh-buildings-propagation-loss-model.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/oh-buildings-propagation-loss-model.cc	2023-09-27 13:30:37.618839000 -0700
@@ -20,6 +20,8 @@
 
 #include "oh-buildings-propagation-loss-model.h"
 
+#include "mobility-building-info.h"
+
 #include "ns3/double.h"
 #include "ns3/enum.h"
 #include "ns3/log.h"
@@ -27,7 +29,6 @@
 #include "ns3/okumura-hata-propagation-loss-model.h"
 #include "ns3/pointer.h"
 #include "ns3/propagation-loss-model.h"
-#include <ns3/mobility-building-info.h>
 
 #include <cmath>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/oh-buildings-propagation-loss-model.h ns-3.40/src/buildings/model/oh-buildings-propagation-loss-model.h
--- ns-3.39/src/buildings/model/oh-buildings-propagation-loss-model.h	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/oh-buildings-propagation-loss-model.h	2023-09-27 13:30:37.618839000 -0700
@@ -21,7 +21,7 @@
 #ifndef OH_BUILDINGS_PROPAGATION_LOSS_MODEL_H_
 #define OH_BUILDINGS_PROPAGATION_LOSS_MODEL_H_
 
-#include <ns3/buildings-propagation-loss-model.h>
+#include "buildings-propagation-loss-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc ns-3.40/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc
--- ns-3.39/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc	2023-09-27 13:30:37.618839000 -0700
@@ -20,8 +20,9 @@
  */
 #include "random-walk-2d-outdoor-mobility-model.h"
 
-#include "ns3/building-list.h"
-#include "ns3/building.h"
+#include "building-list.h"
+#include "building.h"
+
 #include "ns3/double.h"
 #include "ns3/enum.h"
 #include "ns3/log.h"
@@ -31,6 +32,7 @@
 #include "ns3/uinteger.h"
 
 #include <cmath>
+#include <limits>
 
 namespace ns3
 {
@@ -132,6 +134,11 @@
 void
 RandomWalk2dOutdoorMobilityModel::DoWalk(Time delayLeft)
 {
+    if (delayLeft.IsNegative())
+    {
+        NS_LOG_INFO(this << " Ran out of time");
+        return;
+    }
     NS_LOG_FUNCTION(this << delayLeft.GetSeconds());
 
     Vector position = m_helper.GetCurrentPosition();
@@ -160,7 +167,18 @@
             NS_LOG_LOGIC("NextPosition would lead into a building");
             nextPosition =
                 CalculateIntersectionFromOutside(position, nextPosition, building->GetBoundaries());
-            Time delay = Seconds((nextPosition.x - position.x) / speed.x);
+
+            double delaySecondsX = std::numeric_limits<double>::max();
+            double delaySecondsY = std::numeric_limits<double>::max();
+            if (speed.x != 0)
+            {
+                delaySecondsX = std::abs((nextPosition.x - position.x) / speed.x);
+            }
+            if (speed.y != 0)
+            {
+                delaySecondsY = std::abs((nextPosition.y - position.y) / speed.y);
+            }
+            Time delay = Seconds(std::min(delaySecondsX, delaySecondsY));
             m_event = Simulator::Schedule(delay,
                                           &RandomWalk2dOutdoorMobilityModel::AvoidBuilding,
                                           this,
@@ -179,7 +197,24 @@
 
         if (outdoor)
         {
-            Time delay = Seconds((nextPosition.x - position.x) / speed.x);
+            double delaySeconds = std::numeric_limits<double>::max();
+            if (speed.x != 0)
+            {
+                delaySeconds =
+                    std::min(delaySeconds, std::abs((nextPosition.x - position.x) / speed.x));
+            }
+            else if (speed.y != 0)
+            {
+                delaySeconds =
+                    std::min(delaySeconds, std::abs((nextPosition.y - position.y) / speed.y));
+            }
+            else
+            {
+                NS_ABORT_MSG("RandomWalk2dOutdoorMobilityModel::DoWalk: unable to calculate the "
+                             "rebound time "
+                             "(the node is stationary).");
+            }
+            Time delay = Seconds(delaySeconds);
             m_event = Simulator::Schedule(delay,
                                           &RandomWalk2dOutdoorMobilityModel::Rebound,
                                           this,
@@ -190,7 +225,28 @@
             NS_LOG_LOGIC("NextPosition would lead into a building");
             nextPosition =
                 CalculateIntersectionFromOutside(position, nextPosition, building->GetBoundaries());
-            Time delay = Seconds((nextPosition.x - position.x) / speed.x);
+
+            double delaySecondsX = std::numeric_limits<double>::max();
+            double delaySecondsY = std::numeric_limits<double>::max();
+            if (speed.x != 0)
+            {
+                delaySecondsX =
+                    std::min(delaySecondsX, std::abs((nextPosition.x - position.x) / speed.x));
+            }
+            if (speed.y != 0)
+            {
+                delaySecondsY =
+                    std::min(delaySecondsY, std::abs((nextPosition.y - position.y) / speed.y));
+            }
+            if (delaySecondsX == std::numeric_limits<double>::max() &&
+                delaySecondsY == std::numeric_limits<double>::max())
+            {
+                NS_ABORT_MSG("RandomWalk2dOutdoorMobilityModel::DoWalk: unable to calculate the "
+                             "rebound time "
+                             "(the node is stationary).");
+            }
+
+            Time delay = Seconds(std::min(delaySecondsX, delaySecondsY));
             m_event = Simulator::Schedule(delay,
                                           &RandomWalk2dOutdoorMobilityModel::AvoidBuilding,
                                           this,
@@ -215,7 +271,7 @@
     double minIntersectionDistance = std::numeric_limits<double>::max();
     Ptr<Building> minIntersectionDistanceBuilding;
 
-    for (BuildingList::Iterator bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
+    for (auto bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
     {
         // check if this building intersects the line between the current and next positions
         // this checks also if the next position is inside the building
@@ -250,44 +306,72 @@
 
     // get the closest side
     Rectangle rect = Rectangle(boundaries.xMin, boundaries.xMax, boundaries.yMin, boundaries.yMax);
-    NS_LOG_INFO("rect " << rect);
-    Rectangle::Side closestSide = rect.GetClosestSide(current);
+    NS_LOG_DEBUG("rect " << rect);
+    Rectangle::Side closestSide = rect.GetClosestSideOrCorner(current);
 
     double xIntersect = 0;
     double yIntersect = 0;
 
     switch (closestSide)
     {
-    case Rectangle::RIGHT:
-        NS_LOG_INFO("The closest side is RIGHT");
-        NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
+    case Rectangle::RIGHTSIDE:
+        NS_LOG_DEBUG("The closest side is RIGHT");
         xIntersect = boundaries.xMax + m_epsilon;
+        NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
         yIntersect =
             (next.y - current.y) / (next.x - current.x) * (xIntersect - current.x) + current.y;
         break;
-    case Rectangle::LEFT:
-        NS_LOG_INFO("The closest side is LEFT");
+    case Rectangle::LEFTSIDE:
+        NS_LOG_DEBUG("The closest side is LEFT");
         xIntersect = boundaries.xMin - m_epsilon;
         NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
         yIntersect =
             (next.y - current.y) / (next.x - current.x) * (xIntersect - current.x) + current.y;
         break;
-    case Rectangle::TOP:
-        NS_LOG_INFO("The closest side is TOP");
+    case Rectangle::TOPSIDE:
+        NS_LOG_DEBUG("The closest side is TOP");
         yIntersect = boundaries.yMax + m_epsilon;
         NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
         xIntersect =
             (next.x - current.x) / (next.y - current.y) * (yIntersect - current.y) + current.x;
         break;
-    case Rectangle::BOTTOM:
-        NS_LOG_INFO("The closest side is BOTTOM");
+    case Rectangle::BOTTOMSIDE:
+        NS_LOG_DEBUG("The closest side is BOTTOM");
         yIntersect = boundaries.yMin - m_epsilon;
         NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
         xIntersect =
             (next.x - current.x) / (next.y - current.y) * (yIntersect - current.y) + current.x;
         break;
+    case Rectangle::TOPRIGHTCORNER:
+        NS_LOG_DEBUG("The closest side is TOPRIGHT");
+        xIntersect = boundaries.xMax + m_epsilon;
+        NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
+        yIntersect = boundaries.yMax + m_epsilon;
+        NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
+        break;
+    case Rectangle::TOPLEFTCORNER:
+        NS_LOG_DEBUG("The closest side is TOPLEFT");
+        xIntersect = boundaries.xMin - m_epsilon;
+        NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
+        yIntersect = boundaries.yMax + m_epsilon;
+        NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
+        break;
+    case Rectangle::BOTTOMRIGHTCORNER:
+        NS_LOG_DEBUG("The closest side is BOTTOMRIGHT");
+        xIntersect = boundaries.xMax + m_epsilon;
+        NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
+        yIntersect = boundaries.yMin - m_epsilon;
+        NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
+        break;
+    case Rectangle::BOTTOMLEFTCORNER:
+        NS_LOG_DEBUG("The closest side is BOTTOMLEFT");
+        xIntersect = boundaries.xMin - m_epsilon;
+        NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
+        yIntersect = boundaries.yMin - m_epsilon;
+        NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
+        break;
     }
-    NS_LOG_INFO("xIntersect " << xIntersect << " yIntersect " << yIntersect);
+    NS_LOG_DEBUG("xIntersect " << xIntersect << " yIntersect " << yIntersect);
     return Vector(xIntersect, yIntersect, 0);
 }
 
@@ -298,20 +382,27 @@
     m_helper.UpdateWithBounds(m_bounds);
     Vector position = m_helper.GetCurrentPosition();
     Vector speed = m_helper.GetVelocity();
-    switch (m_bounds.GetClosestSide(position))
+    switch (m_bounds.GetClosestSideOrCorner(position))
     {
-    case Rectangle::RIGHT:
-        NS_LOG_INFO("The closest side is RIGHT");
-    case Rectangle::LEFT:
-        NS_LOG_INFO("The closest side is LEFT");
+    case Rectangle::RIGHTSIDE:
+    case Rectangle::LEFTSIDE:
+        NS_LOG_DEBUG("The closest side is RIGHT or LEFT");
         speed.x = -speed.x;
         break;
-    case Rectangle::TOP:
-        NS_LOG_INFO("The closest side is TOP");
-    case Rectangle::BOTTOM:
-        NS_LOG_INFO("The closest side is BOTTOM");
+    case Rectangle::TOPSIDE:
+    case Rectangle::BOTTOMSIDE:
+        NS_LOG_DEBUG("The closest side is TOP or BOTTOM");
         speed.y = -speed.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;
+        break;
     }
     m_helper.SetVelocity(speed);
     m_helper.Unpause();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/random-walk-2d-outdoor-mobility-model.h ns-3.40/src/buildings/model/random-walk-2d-outdoor-mobility-model.h
--- ns-3.39/src/buildings/model/random-walk-2d-outdoor-mobility-model.h	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/random-walk-2d-outdoor-mobility-model.h	2023-09-27 13:30:37.618839000 -0700
@@ -22,7 +22,8 @@
 #ifndef RANDOM_WALK_2D_OUTDOOR_MOBILITY_MODEL_H
 #define RANDOM_WALK_2D_OUTDOOR_MOBILITY_MODEL_H
 
-#include "ns3/building.h"
+#include "building.h"
+
 #include "ns3/constant-velocity-helper.h"
 #include "ns3/event-id.h"
 #include "ns3/mobility-model.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/model/three-gpp-v2v-channel-condition-model.cc ns-3.40/src/buildings/model/three-gpp-v2v-channel-condition-model.cc
--- ns-3.39/src/buildings/model/three-gpp-v2v-channel-condition-model.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/model/three-gpp-v2v-channel-condition-model.cc	2023-09-27 13:30:37.618839000 -0700
@@ -19,9 +19,10 @@
 
 #include "three-gpp-v2v-channel-condition-model.h"
 
+#include "building-list.h"
+
 #include "ns3/log.h"
 #include "ns3/mobility-model.h"
-#include <ns3/building-list.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/test/building-position-allocator-test.cc ns-3.40/src/buildings/test/building-position-allocator-test.cc
--- ns-3.39/src/buildings/test/building-position-allocator-test.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/test/building-position-allocator-test.cc	2023-09-27 13:30:37.618839000 -0700
@@ -117,7 +117,7 @@
 
     std::map<Room, uint32_t> roomCounter;
 
-    for (NodeContainer::Iterator it = nodes.Begin(); it != nodes.End(); ++it)
+    for (auto it = nodes.Begin(); it != nodes.End(); ++it)
     {
         Ptr<MobilityModel> mm = (*it)->GetObject<MobilityModel>();
         NS_ASSERT_MSG(mm, "no mobility model aggregated to this node");
@@ -138,7 +138,7 @@
         NS_TEST_ASSERT_MSG_LT(p.z, bmm->GetFloorNumber() + 1, "wrong z value");
     }
 
-    for (std::map<Room, uint32_t>::iterator it = roomCounter.begin(); it != roomCounter.end(); ++it)
+    for (auto it = roomCounter.begin(); it != roomCounter.end(); ++it)
     {
         // random selection is done without replacement until the set of
         // eligible room is empty, at which point the set is filled
@@ -202,7 +202,7 @@
 
     std::map<Room, uint32_t> roomCounter;
 
-    for (NodeContainer::Iterator it = copyNodes.Begin(); it != copyNodes.End(); ++it)
+    for (auto it = copyNodes.Begin(); it != copyNodes.End(); ++it)
     {
         Ptr<MobilityModel> mm = (*it)->GetObject<MobilityModel>();
         NS_ASSERT_MSG(mm, "no mobility model aggregated to this node");
@@ -215,7 +215,7 @@
         ++(roomCounter[r]);
     }
 
-    for (std::map<Room, uint32_t>::iterator it = roomCounter.begin(); it != roomCounter.end(); ++it)
+    for (auto it = roomCounter.begin(); it != roomCounter.end(); ++it)
     {
         NS_TEST_ASSERT_MSG_EQ(it->second, 4, "expected 4 nodes per room");
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/buildings/test/outdoor-random-walk-test.cc ns-3.40/src/buildings/test/outdoor-random-walk-test.cc
--- ns-3.39/src/buildings/test/outdoor-random-walk-test.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/buildings/test/outdoor-random-walk-test.cc	2023-09-27 13:30:37.622839000 -0700
@@ -21,6 +21,7 @@
 #include "ns3/building.h"
 #include "ns3/config.h"
 #include "ns3/double.h"
+#include "ns3/enum.h"
 #include "ns3/log.h"
 #include "ns3/mobility-helper.h"
 #include "ns3/pointer.h"
@@ -82,6 +83,10 @@
 void
 OutdoorRandomWalkTestCase::DoRun()
 {
+    // Samples to test and time steps
+    constexpr double TEST_STEP_S = 10; // s
+    constexpr int MAX_CHECKS = 1000;
+
     // create a grid of buildings
     double buildingSizeX = 100; // m
     double buildingSizeY = 50;  // m
@@ -121,7 +126,11 @@
     mobility.SetMobilityModel(
         "ns3::RandomWalk2dOutdoorMobilityModel",
         "Bounds",
-        RectangleValue(Rectangle(-streetWidth, maxAxisX, -streetWidth, maxAxisY)));
+        RectangleValue(Rectangle(-streetWidth, maxAxisX, -streetWidth, maxAxisY)),
+        "Mode",
+        EnumValue(RandomWalk2dOutdoorMobilityModel::MODE_TIME),
+        "Time",
+        TimeValue(Seconds(TEST_STEP_S * MAX_CHECKS)));
     // create an OutdoorPositionAllocator and set its boundaries to match those of the mobility
     // model
     Ptr<OutdoorPositionAllocator> position = CreateObject<OutdoorPositionAllocator>();
@@ -139,18 +148,16 @@
 
     auto mobilityModel = nodes.Get(0)->GetObject<RandomWalk2dOutdoorMobilityModel>();
 
-    // get maxChecks positions, check if they are outdoors
-    double testStep = 10; // s
-    int maxChecks = 1000;
-    for (int i = 0; i < maxChecks; ++i)
+    // get MAX_CHECKS positions, check if they are outdoors
+    for (int i = 0; i < MAX_CHECKS; i++)
     {
-        Simulator::Schedule(Seconds(i * testStep),
+        Simulator::Schedule(Seconds(i * TEST_STEP_S),
                             &OutdoorRandomWalkTestCase::CheckPositionOutdoor,
                             this,
                             mobilityModel);
     }
 
-    Simulator::Stop(Seconds(maxChecks * testStep + 1));
+    Simulator::Stop(Seconds(MAX_CHECKS * TEST_STEP_S + 1));
     Simulator::Run();
     Simulator::Destroy();
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/examples/nsclick-defines.cc ns-3.40/src/click/examples/nsclick-defines.cc
--- ns-3.39/src/click/examples/nsclick-defines.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/click/examples/nsclick-defines.cc	2023-09-27 13:30:37.622839000 -0700
@@ -28,7 +28,6 @@
 int
 main(int argc, char* argv[])
 {
-#ifdef NS3_CLICK
     std::string clickConfigFolder = "src/click/examples";
 
     CommandLine cmd(__FILE__);
@@ -66,9 +65,6 @@
     Simulator::Run();
     Simulator::Destroy();
     NS_LOG_INFO("Done.");
-#else
-    NS_FATAL_ERROR("Can't use ns-3-click without NSCLICK compiled in");
-#endif
 
     return 0;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/examples/nsclick-raw-wlan.cc ns-3.40/src/click/examples/nsclick-raw-wlan.cc
--- ns-3.39/src/click/examples/nsclick-raw-wlan.cc	2023-07-05 14:23:47.717427000 -0700
+++ ns-3.40/src/click/examples/nsclick-raw-wlan.cc	2023-09-27 13:30:37.622839000 -0700
@@ -44,7 +44,6 @@
 int
 main(int argc, char* argv[])
 {
-#ifdef NS3_CLICK
     double rss = -80;
     std::string clickConfigFolder = "src/click/examples";
 
@@ -150,9 +149,6 @@
     Simulator::Run();
 
     Simulator::Destroy();
-#else
-    NS_FATAL_ERROR("Can't use ns-3-click without NSCLICK compiled in");
-#endif
 
     return 0;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/examples/nsclick-routing.cc ns-3.40/src/click/examples/nsclick-routing.cc
--- ns-3.39/src/click/examples/nsclick-routing.cc	2023-07-05 14:23:47.721427000 -0700
+++ ns-3.40/src/click/examples/nsclick-routing.cc	2023-09-27 13:30:37.622839000 -0700
@@ -45,7 +45,6 @@
 int
 main(int argc, char* argv[])
 {
-#ifdef NS3_CLICK
     std::string clickConfigFolder = "src/click/examples";
 
     CommandLine cmd(__FILE__);
@@ -131,9 +130,6 @@
     Simulator::Run();
     Simulator::Destroy();
     NS_LOG_INFO("Done.");
-#else
-    NS_FATAL_ERROR("Can't use ns-3-click without NSCLICK compiled in");
-#endif
 
     return 0;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/examples/nsclick-simple-lan.cc ns-3.40/src/click/examples/nsclick-simple-lan.cc
--- ns-3.39/src/click/examples/nsclick-simple-lan.cc	2023-07-05 14:23:47.721427000 -0700
+++ ns-3.40/src/click/examples/nsclick-simple-lan.cc	2023-09-27 13:30:37.622839000 -0700
@@ -43,7 +43,6 @@
 int
 main(int argc, char* argv[])
 {
-#ifdef NS3_CLICK
     std::string clickConfigFolder = "src/click/examples";
 
     CommandLine cmd(__FILE__);
@@ -104,9 +103,6 @@
     Simulator::Run();
 
     Simulator::Destroy();
-#else
-    NS_FATAL_ERROR("Can't use ns-3-click without NSCLICK compiled in");
-#endif
 
     return 0;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/examples/nsclick-udp-client-server-csma.cc ns-3.40/src/click/examples/nsclick-udp-client-server-csma.cc
--- ns-3.39/src/click/examples/nsclick-udp-client-server-csma.cc	2023-07-05 14:23:47.721427000 -0700
+++ ns-3.40/src/click/examples/nsclick-udp-client-server-csma.cc	2023-09-27 13:30:37.622839000 -0700
@@ -48,7 +48,6 @@
 int
 main(int argc, char* argv[])
 {
-#ifdef NS3_CLICK
     std::string clickConfigFolder = "src/click/examples";
 
     CommandLine cmd(__FILE__);
@@ -130,9 +129,6 @@
     Simulator::Run();
     Simulator::Destroy();
     NS_LOG_INFO("Done.");
-#else
-    NS_FATAL_ERROR("Can't use ns-3-click without NSCLICK compiled in");
-#endif
 
     return 0;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/examples/nsclick-udp-client-server-wifi.cc ns-3.40/src/click/examples/nsclick-udp-client-server-wifi.cc
--- ns-3.39/src/click/examples/nsclick-udp-client-server-wifi.cc	2023-07-05 14:23:47.721427000 -0700
+++ ns-3.40/src/click/examples/nsclick-udp-client-server-wifi.cc	2023-09-27 13:30:37.622839000 -0700
@@ -50,7 +50,6 @@
 
 NS_LOG_COMPONENT_DEFINE("NsclickUdpClientServerWifi");
 
-#ifdef NS3_CLICK
 void
 ReadArp(Ptr<Ipv4ClickRouting> clickRouter)
 {
@@ -66,12 +65,10 @@
     NS_LOG_INFO(
         clickRouter->WriteHandler("wifi/arpquerier", "insert", "172.16.1.2 00:00:00:00:00:02"));
 }
-#endif
 
 int
 main(int argc, char* argv[])
 {
-#ifdef NS3_CLICK
     std::string clickConfigFolder = "src/click/examples";
 
     CommandLine cmd(__FILE__);
@@ -216,9 +213,6 @@
     Simulator::Run();
     Simulator::Destroy();
     NS_LOG_INFO("Done.");
-#else
-    NS_FATAL_ERROR("Can't use ns-3-click without NSCLICK compiled in");
-#endif
 
     return 0;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/helper/click-internet-stack-helper.cc ns-3.40/src/click/helper/click-internet-stack-helper.cc
--- ns-3.39/src/click/helper/click-internet-stack-helper.cc	2023-07-05 14:23:47.721427000 -0700
+++ ns-3.40/src/click/helper/click-internet-stack-helper.cc	2023-09-27 13:30:37.622839000 -0700
@@ -19,8 +19,6 @@
  * Author: Lalith Suresh  <suresh.lalith@gmail.com>
  */
 
-#ifdef NS3_CLICK
-
 #include "click-internet-stack-helper.h"
 
 #include "ns3/arp-l3-protocol.h"
@@ -60,13 +58,121 @@
 static InterfaceStreamMapIpv4
     g_interfaceStreamMapIpv4; /**< A mapping of Ipv4/interface pairs to ascii streams */
 
+/**
+ * IPv4 Rx / Tx packet callback.
+ *
+ * \param p Packet.
+ * \param ipv4 IPv4 stack.
+ * \param interface Interface number.
+ */
+static void
+Ipv4L3ProtocolRxTxSink(Ptr<const Packet> p, Ptr<Ipv4> ipv4, uint32_t interface)
+{
+    NS_LOG_FUNCTION(p << ipv4 << interface);
+
+    //
+    // Since trace sources are independent of interface, if we hook a source
+    // on a particular protocol we will get traces for all of its interfaces.
+    // We need to filter this to only report interfaces for which the user
+    // has expressed interest.
+    //
+    InterfacePairIpv4 pair = std::make_pair(ipv4, interface);
+    if (g_interfaceFileMapIpv4.find(pair) == g_interfaceFileMapIpv4.end())
+    {
+        NS_LOG_INFO("Ignoring packet to/from interface " << interface);
+        return;
+    }
+
+    Ptr<PcapFileWrapper> file = g_interfaceFileMapIpv4[pair];
+    file->Write(Simulator::Now(), p);
+}
+
+/**
+ * Packet dropped callback without context.
+ *
+ * \param stream Output stream.
+ * \param header IPv4 header.
+ * \param packet Packet.
+ * \param reason Packet drop reason.
+ * \param ipv4 IPv4 stack.
+ * \param interface Interface number.
+ */
+static void
+Ipv4L3ProtocolDropSinkWithoutContext(Ptr<OutputStreamWrapper> stream,
+                                     const Ipv4Header& header,
+                                     Ptr<const Packet> packet,
+                                     Ipv4L3Protocol::DropReason reason,
+                                     Ptr<Ipv4> ipv4,
+                                     uint32_t interface)
+{
+    //
+    // Since trace sources are independent of interface, if we hook a source
+    // on a particular protocol we will get traces for all of its interfaces.
+    // We need to filter this to only report interfaces for which the user
+    // has expressed interest.
+    //
+    InterfacePairIpv4 pair = std::make_pair(ipv4, interface);
+    if (g_interfaceStreamMapIpv4.find(pair) == g_interfaceStreamMapIpv4.end())
+    {
+        NS_LOG_INFO("Ignoring packet to/from interface " << interface);
+        return;
+    }
+
+    Ptr<Packet> p = packet->Copy();
+    p->AddHeader(header);
+    *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << *p << std::endl;
+}
+
+/**
+ * Packet dropped callback with context.
+ *
+ * \param stream Output stream.
+ * \param context Context.
+ * \param header IPv4 header.
+ * \param packet Packet.
+ * \param reason Packet drop reason.
+ * \param ipv4 IPv4 stack.
+ * \param interface Interface number.
+ */
+static void
+Ipv4L3ProtocolDropSinkWithContext(Ptr<OutputStreamWrapper> stream,
+                                  std::string context,
+                                  const Ipv4Header& header,
+                                  Ptr<const Packet> packet,
+                                  Ipv4L3Protocol::DropReason reason,
+                                  Ptr<Ipv4> ipv4,
+                                  uint32_t interface)
+{
+    //
+    // Since trace sources are independent of interface, if we hook a source
+    // on a particular protocol we will get traces for all of its interfaces.
+    // We need to filter this to only report interfaces for which the user
+    // has expressed interest.
+    //
+    InterfacePairIpv4 pair = std::make_pair(ipv4, interface);
+    if (g_interfaceStreamMapIpv4.find(pair) == g_interfaceStreamMapIpv4.end())
+    {
+        NS_LOG_INFO("Ignoring packet to/from interface " << interface);
+        return;
+    }
+
+    Ptr<Packet> p = packet->Copy();
+    p->AddHeader(header);
+#ifdef INTERFACE_CONTEXT
+    *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << context << "("
+                         << interface << ") " << *p << std::endl;
+#else
+    *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << context << " " << *p
+                         << std::endl;
+#endif
+}
+
 ClickInternetStackHelper::ClickInternetStackHelper()
     : m_ipv4Enabled(true)
 {
     Initialize();
 }
 
-// private method called by both constructor and Reset ()
 void
 ClickInternetStackHelper::Initialize()
 {
@@ -84,9 +190,9 @@
 ClickInternetStackHelper&
 ClickInternetStackHelper::operator=(const ClickInternetStackHelper& o)
 {
-    if (this == &o)
+    if (this != &o)
     {
-        return *this;
+        m_ipv4Enabled = o.m_ipv4Enabled;
     }
     return *this;
 }
@@ -101,7 +207,7 @@
 void
 ClickInternetStackHelper::SetClickFile(NodeContainer c, std::string clickfile)
 {
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         SetClickFile(*i, clickfile);
     }
@@ -116,7 +222,7 @@
 void
 ClickInternetStackHelper::SetDefines(NodeContainer c, std::map<std::string, std::string> defines)
 {
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         SetDefines(*i, defines);
     }
@@ -131,7 +237,7 @@
 void
 ClickInternetStackHelper::SetRoutingTableElement(NodeContainer c, std::string rt)
 {
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         SetRoutingTableElement(*i, rt);
     }
@@ -146,7 +252,7 @@
 void
 ClickInternetStackHelper::Install(NodeContainer c) const
 {
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Install(*i);
     }
@@ -190,16 +296,14 @@
         // Set routing
         Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
         Ptr<Ipv4ClickRouting> ipv4Routing = CreateObject<Ipv4ClickRouting>();
-        std::map<Ptr<Node>, std::string>::const_iterator it;
-        it = m_nodeToClickFileMap.find(node);
+        auto it = m_nodeToClickFileMap.find(node);
 
         if (it != m_nodeToClickFileMap.end())
         {
             ipv4Routing->SetClickFile(it->second);
         }
 
-        std::map<Ptr<Node>, std::map<std::string, std::string>>::const_iterator definesIt;
-        definesIt = m_nodeToDefinesMap.find(node);
+        auto definesIt = m_nodeToDefinesMap.find(node);
         if (definesIt != m_nodeToDefinesMap.end())
         {
             ipv4Routing->SetDefines(definesIt->second);
@@ -222,34 +326,10 @@
     Install(node);
 }
 
-static void
-Ipv4L3ProtocolRxTxSink(Ptr<const Packet> p, Ptr<Ipv4> ipv4, uint32_t interface)
-{
-    NS_LOG_FUNCTION(p << ipv4 << interface);
-
-    //
-    // Since trace sources are independent of interface, if we hook a source
-    // on a particular protocol we will get traces for all of its interfaces.
-    // We need to filter this to only report interfaces for which the user
-    // has expressed interest.
-    //
-    InterfacePairIpv4 pair = std::make_pair(ipv4, interface);
-    if (g_interfaceFileMapIpv4.find(pair) == g_interfaceFileMapIpv4.end())
-    {
-        NS_LOG_INFO("Ignoring packet to/from interface " << interface);
-        return;
-    }
-
-    Ptr<PcapFileWrapper> file = g_interfaceFileMapIpv4[pair];
-    file->Write(Simulator::Now(), p);
-}
-
 bool
 ClickInternetStackHelper::PcapHooked(Ptr<Ipv4> ipv4)
 {
-    for (InterfaceFileMapIpv4::const_iterator i = g_interfaceFileMapIpv4.begin();
-         i != g_interfaceFileMapIpv4.end();
-         ++i)
+    for (auto i = g_interfaceFileMapIpv4.begin(); i != g_interfaceFileMapIpv4.end(); ++i)
     {
         if ((*i).first.first == ipv4)
         {
@@ -322,71 +402,10 @@
     g_interfaceFileMapIpv4[std::make_pair(ipv4, interface)] = file;
 }
 
-static void
-Ipv4L3ProtocolDropSinkWithoutContext(Ptr<OutputStreamWrapper> stream,
-                                     const Ipv4Header& header,
-                                     Ptr<const Packet> packet,
-                                     Ipv4L3Protocol::DropReason reason,
-                                     Ptr<Ipv4> ipv4,
-                                     uint32_t interface)
-{
-    //
-    // Since trace sources are independent of interface, if we hook a source
-    // on a particular protocol we will get traces for all of its interfaces.
-    // We need to filter this to only report interfaces for which the user
-    // has expressed interest.
-    //
-    InterfacePairIpv4 pair = std::make_pair(ipv4, interface);
-    if (g_interfaceStreamMapIpv4.find(pair) == g_interfaceStreamMapIpv4.end())
-    {
-        NS_LOG_INFO("Ignoring packet to/from interface " << interface);
-        return;
-    }
-
-    Ptr<Packet> p = packet->Copy();
-    p->AddHeader(header);
-    *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << *p << std::endl;
-}
-
-static void
-Ipv4L3ProtocolDropSinkWithContext(Ptr<OutputStreamWrapper> stream,
-                                  std::string context,
-                                  const Ipv4Header& header,
-                                  Ptr<const Packet> packet,
-                                  Ipv4L3Protocol::DropReason reason,
-                                  Ptr<Ipv4> ipv4,
-                                  uint32_t interface)
-{
-    //
-    // Since trace sources are independent of interface, if we hook a source
-    // on a particular protocol we will get traces for all of its interfaces.
-    // We need to filter this to only report interfaces for which the user
-    // has expressed interest.
-    //
-    InterfacePairIpv4 pair = std::make_pair(ipv4, interface);
-    if (g_interfaceStreamMapIpv4.find(pair) == g_interfaceStreamMapIpv4.end())
-    {
-        NS_LOG_INFO("Ignoring packet to/from interface " << interface);
-        return;
-    }
-
-    Ptr<Packet> p = packet->Copy();
-    p->AddHeader(header);
-#ifdef INTERFACE_CONTEXT
-    *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << context << "("
-                         << interface << ") " << *p << std::endl;
-#else
-    *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << context << " " << *p
-                         << std::endl;
-#endif
-}
-
 bool
 ClickInternetStackHelper::AsciiHooked(Ptr<Ipv4> ipv4)
 {
-    for (InterfaceStreamMapIpv4::const_iterator i = g_interfaceStreamMapIpv4.begin();
-         i != g_interfaceStreamMapIpv4.end();
-         ++i)
+    for (auto i = g_interfaceStreamMapIpv4.begin(); i != g_interfaceStreamMapIpv4.end(); ++i)
     {
         if ((*i).first.first == ipv4)
         {
@@ -521,5 +540,3 @@
 }
 
 } // namespace ns3
-
-#endif // NS3_CLICK
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/helper/click-internet-stack-helper.h ns-3.40/src/click/helper/click-internet-stack-helper.h
--- ns-3.39/src/click/helper/click-internet-stack-helper.h	2023-07-05 14:23:47.721427000 -0700
+++ ns-3.40/src/click/helper/click-internet-stack-helper.h	2023-09-27 13:30:37.622839000 -0700
@@ -18,8 +18,6 @@
  * Author: Lalith Suresh  <suresh.lalith@gmail.com>
  */
 
-#ifdef NS3_CLICK
-
 #ifndef CLICK_INTERNET_STACK_HELPER_H
 #define CLICK_INTERNET_STACK_HELPER_H
 
@@ -59,7 +57,20 @@
      * Destroy the ClickInternetStackHelper
      */
     ~ClickInternetStackHelper() override;
-    ClickInternetStackHelper(const ClickInternetStackHelper&);
+
+    /**
+     * Copy constructor.
+     *
+     * \param o Object to copy from.
+     */
+    ClickInternetStackHelper(const ClickInternetStackHelper& o);
+
+    /**
+     * Assignment operator.
+     *
+     * \param o Object to copy from.
+     * \return Reference to updated object.
+     */
     ClickInternetStackHelper& operator=(const ClickInternetStackHelper& o);
 
     /**
@@ -145,11 +156,12 @@
 
   private:
     /**
-     * @brief Enable pcap output the indicated Ipv4 and interface pair.
+     * \brief Enable pcap output the indicated Ipv4 and interface pair.
      *
-     * @param prefix Filename prefix to use for pcap files.
-     * @param ipv4 Ptr to the Ipv4 interface on which you want to enable tracing.
-     * @param interface Interface ID on the Ipv4 on which you want to enable tracing.
+     * \param prefix Filename prefix to use for pcap files.
+     * \param ipv4 Ptr to the Ipv4 interface on which you want to enable tracing.
+     * \param interface Interface ID on the Ipv4 on which you want to enable tracing.
+     * \param explicitFilename Whether the filename is explicit or not.
      */
     void EnablePcapIpv4Internal(std::string prefix,
                                 Ptr<Ipv4> ipv4,
@@ -157,13 +169,14 @@
                                 bool explicitFilename) override;
 
     /**
-     * @brief Enable ascii trace output on the indicated Ipv4 and interface pair.
+     * \brief Enable ascii trace output on the indicated Ipv4 and interface pair.
      *
-     * @param stream An OutputStreamWrapper representing an existing file to use
+     * \param stream An OutputStreamWrapper representing an existing file to use
      *               when writing trace data.
-     * @param prefix Filename prefix to use for ascii trace files.
-     * @param ipv4 Ptr to the Ipv4 interface on which you want to enable tracing.
-     * @param interface Interface ID on the Ipv4 on which you want to enable tracing.
+     * \param prefix Filename prefix to use for ascii trace files.
+     * \param ipv4 Ptr to the Ipv4 interface on which you want to enable tracing.
+     * \param interface Interface ID on the Ipv4 on which you want to enable tracing.
+     * \param explicitFilename Whether the filename is explicit or not.
      */
     void EnableAsciiIpv4Internal(Ptr<OutputStreamWrapper> stream,
                                  std::string prefix,
@@ -171,14 +184,34 @@
                                  uint32_t interface,
                                  bool explicitFilename) override;
 
+    /**
+     * Initialize stack helper.
+     * Called by both constructor and Reset().
+     */
     void Initialize();
 
+    /**
+     * Create and aggregate object from type ID.
+     *
+     * \param node Node.
+     * \param typeId Type ID.
+     */
     static void CreateAndAggregateObjectFromTypeId(Ptr<Node> node, const std::string typeId);
 
-    static void Cleanup();
-
+    /**
+     * Check if PCAP is hooked.
+     *
+     * \param ipv4 IPv4 stack.
+     * \return True if PCAP is hooked.
+     */
     bool PcapHooked(Ptr<Ipv4> ipv4);
 
+    /**
+     * Check if ASCII is hooked.
+     *
+     * \param ipv4 IPv4 stack.
+     * \return True if ASCII is hooked.
+     */
     bool AsciiHooked(Ptr<Ipv4> ipv4);
 
     /**
@@ -205,5 +238,3 @@
 } // namespace ns3
 
 #endif /* CLICK_INTERNET_STACK_HELPER_H */
-
-#endif /* NS3_CLICK */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/model/ipv4-click-routing.cc ns-3.40/src/click/model/ipv4-click-routing.cc
--- ns-3.39/src/click/model/ipv4-click-routing.cc	2023-07-05 14:23:47.721427000 -0700
+++ ns-3.40/src/click/model/ipv4-click-routing.cc	2023-09-27 13:30:37.622839000 -0700
@@ -17,12 +17,11 @@
  * Authors: Lalith Suresh <suresh.lalith@gmail.com>
  */
 
-#ifdef NS3_CLICK
-
 #include "ipv4-click-routing.h"
 
+#include "ipv4-l3-click-protocol.h"
+
 #include "ns3/ipv4-interface.h"
-#include "ns3/ipv4-l3-click-protocol.h"
 #include "ns3/log.h"
 #include "ns3/mac48-address.h"
 #include "ns3/node.h"
@@ -87,7 +86,7 @@
         m_nodeName = name.str();
     }
 
-    NS_ASSERT(m_clickFile.length() > 0);
+    NS_ASSERT(!m_clickFile.empty());
 
     // Even though simclick_click_create() will halt programme execution
     // if it is unable to initialise a Click router, we play safe
@@ -397,7 +396,7 @@
     }
 
     int len = p->GetSize();
-    uint8_t* buf = new uint8_t[len];
+    auto buf = new uint8_t[len];
     p->CopyData(buf, len);
 
     // ... and send the packet on the corresponding Click interface.
@@ -425,7 +424,7 @@
     }
 
     int len = p->GetSize();
-    uint8_t* buf = new uint8_t[len];
+    auto buf = new uint8_t[len];
     p->CopyData(buf, len);
 
     // ... and send the packet to the corresponding Click interface
@@ -817,8 +816,8 @@
 
         // Append key/value pair, separated by \0.
         std::map<std::string, std::string> defines = clickInstance->GetDefines();
-        std::map<std::string, std::string>::const_iterator it = defines.begin();
-        while (it != defines.end())
+
+        for (auto it = defines.begin(); it != defines.end(); it++)
         {
             size_t available = *size - required;
             if (it->first.length() + it->second.length() + 2 <= available)
@@ -833,7 +832,6 @@
             {
                 required += it->first.length() + it->second.length() + 2;
             }
-            it++;
         }
         if (required > *size)
         {
@@ -850,5 +848,3 @@
     va_end(val);
     return retval;
 }
-
-#endif // NS3_CLICK
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/model/ipv4-click-routing.h ns-3.40/src/click/model/ipv4-click-routing.h
--- ns-3.39/src/click/model/ipv4-click-routing.h	2023-07-05 14:23:47.721427000 -0700
+++ ns-3.40/src/click/model/ipv4-click-routing.h	2023-09-27 13:30:37.622839000 -0700
@@ -54,21 +54,30 @@
  * \ingroup click
  * \brief Class to allow a node to use Click for external routing
  */
-
 class Ipv4ClickRouting : public Ipv4RoutingProtocol
 {
-#ifdef NS3_CLICK
   public:
     // Allow test cases to access private members
     friend class ::ClickTrivialTest;
     friend class ::ClickIfidFromNameTest;
     friend class ::ClickIpMacAddressFromNameTest;
 
+    /**
+     * Get type ID.
+     *
+     * \return TypeId.
+     */
     static TypeId GetTypeId();
 
+    /** Constructor. */
     Ipv4ClickRouting();
     ~Ipv4ClickRouting() override;
 
+    /**
+     * Get the uniform random variable.
+     *
+     * \return Uniform random variable.
+     */
     Ptr<UniformRandomVariable> GetRandomVariable();
 
   protected:
@@ -104,27 +113,30 @@
     /**
      * \brief Read Handler interface for a node's Click Elements.
      *        Allows a user to read state information of a Click element.
-     * \param elementName name of the Click element
-     * \param handlerName name of the handler to be read
+     * \param elementName name of the Click element.
+     * \param handlerName name of the handler to be read.
+     * \return String read.
      */
     std::string ReadHandler(std::string elementName, std::string handlerName);
 
     /**
-     * \brief Write Handler interface for a node's Click Elements
+     * \brief Write Handler interface for a node's Click Elements.
      *        Allows a user to modify state information of a Click element.
-     * \param elementName name of the Click element
-     * \param handlerName name of the handler to be read
-     * \param writeString string to be written using the write handler
+     * \param elementName name of the Click element.
+     * \param handlerName name of the handler to be read.
+     * \param writeString string to be written using the write handler.
+     * \return Write operation status.
      */
     int WriteHandler(std::string elementName, std::string handlerName, std::string writeString);
 
     /**
-     *
      * \brief Sets an interface to run on promiscuous mode.
+     * \param ifid Interface ID.
      */
     void SetPromisc(int ifid);
 
   private:
+    /// Pointer to the simclick node
     simclick_node_t* m_simNode;
 
     /**
@@ -186,6 +198,7 @@
 
     /**
      * \brief Provides for SIMCLICK_IF_READY
+     * \param ifid Interface ID
      * \return Returns 1, if the interface is ready, -1 if ifid is invalid
      */
     bool IsInterfaceReady(int ifid);
@@ -204,7 +217,8 @@
     void AddSimNodeToClickMapping();
 
     /**
-     * \brief Get current simulation time as a timeval
+     * \brief Get current simulation time as a timeval.
+     * \return Current simulation time as a timeval.
      */
     struct timeval GetTimevalFromNow() const;
 
@@ -274,20 +288,16 @@
     void NotifyRemoveAddress(uint32_t interface, Ipv4InterfaceAddress address) override;
 
   private:
-    std::string m_clickFile;
-    std::map<std::string, std::string> m_defines;
-    std::string m_nodeName;
-    std::string m_clickRoutingTableElement;
-
-    std::map<std::string, uint32_t> m_ifaceIdFromName;
-    std::map<std::string, Address> m_ifaceMacFromName;
-    std::map<std::string, Ipv4Address> m_ifaceAddrFromName;
-    bool m_clickInitialised;
-    bool m_nonDefaultName;
-
-    Ptr<Ipv4> m_ipv4;
-    Ptr<UniformRandomVariable> m_random;
-#endif /* NS3_CLICK */
+    std::string m_clickFile;                      //!< Name of .click configuration file
+    std::map<std::string, std::string> m_defines; //!< Defines for .click configuration file parsing
+    std::string m_nodeName;                       //!< Name of the node
+    std::string m_clickRoutingTableElement;       //!< Name of the routing table element
+
+    bool m_clickInitialised; //!< Whether click has been initialized
+    bool m_nonDefaultName;   //!< Whether a non-default name has been set
+
+    Ptr<Ipv4> m_ipv4;                    //!< Pointer to the IPv4 object
+    Ptr<UniformRandomVariable> m_random; //!< Uniform random variable
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/model/ipv4-l3-click-protocol.cc ns-3.40/src/click/model/ipv4-l3-click-protocol.cc
--- ns-3.39/src/click/model/ipv4-l3-click-protocol.cc	2023-07-05 14:23:47.721427000 -0700
+++ ns-3.40/src/click/model/ipv4-l3-click-protocol.cc	2023-09-27 13:30:37.622839000 -0700
@@ -18,15 +18,14 @@
 // Author: Lalith Suresh <suresh.lalith@gmail.com>
 //
 
-#ifdef NS3_CLICK
-
 #include "ipv4-l3-click-protocol.h"
 
+#include "ipv4-click-routing.h"
+
 #include "ns3/arp-l3-protocol.h"
 #include "ns3/ethernet-header.h"
 #include "ns3/icmpv4-l4-protocol.h"
 #include "ns3/ip-l4-protocol.h"
-#include "ns3/ipv4-click-routing.h"
 #include "ns3/ipv4-raw-socket-impl.h"
 #include "ns3/llc-snap-header.h"
 #include "ns3/loopback-net-device.h"
@@ -80,13 +79,13 @@
 Ipv4L3ClickProtocol::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
+    for (auto i = m_protocols.begin(); i != m_protocols.end(); ++i)
     {
         i->second = nullptr;
     }
     m_protocols.clear();
 
-    for (Ipv4InterfaceList::iterator i = m_interfaces.begin(); i != m_interfaces.end(); ++i)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); ++i)
     {
         *i = nullptr;
     }
@@ -153,8 +152,7 @@
     NS_LOG_FUNCTION(this << address);
 
     int32_t interface = 0;
-    for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin(); i != m_interfaces.end();
-         i++, interface++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++, interface++)
     {
         for (uint32_t j = 0; j < (*i)->GetNAddresses(); j++)
         {
@@ -174,8 +172,7 @@
     NS_LOG_FUNCTION(this << address << mask);
 
     int32_t interface = 0;
-    for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin(); i != m_interfaces.end();
-         i++, interface++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++, interface++)
     {
         for (uint32_t j = 0; j < (*i)->GetNAddresses(); j++)
         {
@@ -194,7 +191,7 @@
 {
     NS_LOG_FUNCTION(this << device->GetIfIndex());
 
-    Ipv4InterfaceReverseContainer::const_iterator iter = m_reverseInterfacesContainer.find(device);
+    auto iter = m_reverseInterfacesContainer.find(device);
     if (iter != m_reverseInterfacesContainer.end())
     {
         return (*iter).second;
@@ -275,7 +272,7 @@
 {
     NS_LOG_FUNCTION(this << forward);
     m_ipForward = forward;
-    for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin(); i != m_interfaces.end(); i++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++)
     {
         (*i)->SetForwarding(forward);
     }
@@ -364,7 +361,7 @@
 Ipv4L3ClickProtocol::DeleteRawSocket(Ptr<Socket> socket)
 {
     NS_LOG_FUNCTION(this << socket);
-    for (SocketList::iterator i = m_sockets.begin(); i != m_sockets.end(); ++i)
+    for (auto i = m_sockets.begin(); i != m_sockets.end(); ++i)
     {
         if ((*i) == socket)
         {
@@ -805,7 +802,7 @@
         }
         packetForRawSocket->RemoveHeader(ipHeader);
 
-        for (SocketList::iterator i = m_sockets.begin(); i != m_sockets.end(); ++i)
+        for (auto i = m_sockets.begin(); i != m_sockets.end(); ++i)
         {
             NS_LOG_LOGIC("Forwarding to raw socket");
             Ptr<Ipv4RawSocketImpl> socket = *i;
@@ -923,7 +920,7 @@
     NS_LOG_FUNCTION(this << protocol);
 
     L4ListKey_t key = std::make_pair(protocol->GetProtocolNumber(), -1);
-    L4List_t::iterator iter = m_protocols.find(key);
+    auto iter = m_protocols.find(key);
     if (iter == m_protocols.end())
     {
         NS_LOG_WARN("Trying to remove an non-existent default protocol "
@@ -941,7 +938,7 @@
     NS_LOG_FUNCTION(this << protocol << interfaceIndex);
 
     L4ListKey_t key = std::make_pair(protocol->GetProtocolNumber(), interfaceIndex);
-    L4List_t::iterator iter = m_protocols.find(key);
+    auto iter = m_protocols.find(key);
     if (iter == m_protocols.end())
     {
         NS_LOG_WARN("Trying to remove an non-existent protocol "
@@ -968,12 +965,11 @@
     NS_LOG_FUNCTION(this << protocolNumber << interfaceIndex);
 
     L4ListKey_t key;
-    L4List_t::const_iterator i;
     if (interfaceIndex >= 0)
     {
         // try the interface-specific protocol.
         key = std::make_pair(protocolNumber, interfaceIndex);
-        i = m_protocols.find(key);
+        auto i = m_protocols.find(key);
         if (i != m_protocols.end())
         {
             return i->second;
@@ -981,7 +977,7 @@
     }
     // try the generic protocol.
     key = std::make_pair(protocolNumber, -1);
-    i = m_protocols.find(key);
+    auto i = m_protocols.find(key);
     if (i != m_protocols.end())
     {
         return i->second;
@@ -991,5 +987,3 @@
 }
 
 } // namespace ns3
-
-#endif // NS3_CLICK
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/model/ipv4-l3-click-protocol.h ns-3.40/src/click/model/ipv4-l3-click-protocol.h
--- ns-3.39/src/click/model/ipv4-l3-click-protocol.h	2023-07-05 14:23:47.721427000 -0700
+++ ns-3.40/src/click/model/ipv4-l3-click-protocol.h	2023-09-27 13:30:37.622839000 -0700
@@ -60,8 +60,12 @@
 
 class Ipv4L3ClickProtocol : public Ipv4
 {
-#ifdef NS3_CLICK
   public:
+    /**
+     * Get Type ID.
+     *
+     * \return The type ID.
+     */
     static TypeId GetTypeId();
 
     /**
@@ -224,6 +228,12 @@
     void SetDown(uint32_t i) override;
     bool IsForwarding(uint32_t i) const override;
     void SetForwarding(uint32_t i, bool val) override;
+
+    /**
+     * Sets an interface to run on promiscuous mode.
+     *
+     * \param i Interface ID.
+     */
     void SetPromisc(uint32_t i);
 
   protected:
@@ -236,6 +246,17 @@
     void NotifyNewAggregate() override;
 
   private:
+    /**
+     * Build IPv4 header.
+     *
+     * \param source IPv4 source address.
+     * \param destination IPv4 destination address.
+     * \param protocol Protocol.
+     * \param payloadSize Payload size.
+     * \param ttl Time To Live (TTL).
+     * \param mayFragment Whether the packet can be fragmented or not.
+     * \return The IPv4 header.
+     */
     Ipv4Header BuildHeader(Ipv4Address source,
                            Ipv4Address destination,
                            uint8_t protocol,
@@ -248,32 +269,42 @@
     void SetWeakEsModel(bool model) override;
     bool GetWeakEsModel() const override;
 
+    /**
+     * \brief List of IPv4 interfaces.
+     */
     typedef std::vector<Ptr<Ipv4Interface>> Ipv4InterfaceList;
+
     /**
      * \brief Container of NetDevices registered to IPv4 and their interface indexes.
      */
     typedef std::map<Ptr<const NetDevice>, uint32_t> Ipv4InterfaceReverseContainer;
+
+    /**
+     * \brief List of sockets.
+     */
     typedef std::list<Ptr<Ipv4RawSocketImpl>> SocketList;
+
     /**
      * \brief Container of the IPv4 L4 keys: protocol number, interface index
      */
     typedef std::pair<int, int32_t> L4ListKey_t;
+
     /**
      * \brief Container of the IPv4 L4 instances.
      */
     typedef std::map<L4ListKey_t, Ptr<IpL4Protocol>> L4List_t;
 
-    Ptr<Ipv4RoutingProtocol> m_routingProtocol;
-    bool m_ipForward;
-    bool m_weakEsModel;
-    L4List_t m_protocols;
-    Ipv4InterfaceList m_interfaces;
+    Ptr<Ipv4RoutingProtocol> m_routingProtocol; //!< IPv4 routing protocol
+    bool m_ipForward;                           //!< Whether IP forwarding is enabled
+    bool m_weakEsModel;                         //!< Whether to use weak Es model
+    L4List_t m_protocols;                       //!< List of IPv4 L4 protocols
+    Ipv4InterfaceList m_interfaces;             //!< List of interfaces
     Ipv4InterfaceReverseContainer
-        m_reverseInterfacesContainer; //!< Container of NetDevice / Interface index associations.
-    uint8_t m_defaultTtl;
-    uint16_t m_identification;
+        m_reverseInterfacesContainer; //!< Container of NetDevice / Interface index associations
+    uint8_t m_defaultTtl;             //!< Default TTL
+    uint16_t m_identification;        //!< Identification
 
-    Ptr<Node> m_node;
+    Ptr<Node> m_node; //!< Node
 
     /** \todo Remove; this TracedCallback is never invoked. */
     TracedCallback<const Ipv4Header&, Ptr<const Packet>, uint32_t> m_sendOutgoingTrace;
@@ -282,11 +313,9 @@
     /** \todo This TracedCallback is invoked but not accessible. */
     TracedCallback<const Ipv4Header&, Ptr<const Packet>, uint32_t> m_localDeliverTrace;
 
-    SocketList m_sockets;
-
-    std::vector<bool> m_promiscDeviceList;
+    SocketList m_sockets; //!< List of sockets
 
-#endif /* NS3_CLICK */
+    std::vector<bool> m_promiscDeviceList; //!< List of promiscuous devices
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/click/test/ipv4-click-routing-test.cc ns-3.40/src/click/test/ipv4-click-routing-test.cc
--- ns-3.39/src/click/test/ipv4-click-routing-test.cc	2023-07-05 14:23:47.737427000 -0700
+++ ns-3.40/src/click/test/ipv4-click-routing-test.cc	2023-09-27 13:30:37.622839000 -0700
@@ -17,8 +17,6 @@
  * Authors: Lalith Suresh <suresh.lalith@gmail.com>
  */
 
-#ifdef NS3_CLICK
-
 #include "ns3/click-internet-stack-helper.h"
 #include "ns3/ipv4-click-routing.h"
 #include "ns3/ipv4-l3-protocol.h"
@@ -32,6 +30,17 @@
 
 using namespace ns3;
 
+/**
+ * \file
+ * \ingroup click-tests
+ * Click test suite.
+ */
+
+/**
+ * Add Click Internet stack.
+ *
+ * \param node Node.
+ */
 static void
 AddClickInternetStack(Ptr<Node> node)
 {
@@ -40,6 +49,14 @@
     internet.Install(node);
 }
 
+/**
+ * Add network device.
+ *
+ * \param node Node.
+ * \param macaddr MAC address.
+ * \param ipv4addr IPv4 address.
+ * \param ipv4mask IPv4 mask.
+ */
 static void
 AddNetworkDevice(Ptr<Node> node, Mac48Address macaddr, Ipv4Address ipv4addr, Ipv4Mask ipv4mask)
 {
@@ -56,6 +73,10 @@
     ipv4->SetUp(netdev_idx);
 }
 
+/**
+ * \ingroup click-tests
+ * Click interface ID from name test.
+ */
 class ClickIfidFromNameTest : public TestCase
 {
   public:
@@ -102,6 +123,10 @@
     NS_TEST_EXPECT_MSG_EQ(ret, -1, "No eth1 on node");
 }
 
+/**
+ * \ingroup click-tests
+ * Click IP MAC address from name test.
+ */
 class ClickIpMacAddressFromNameTest : public TestCase
 {
   public:
@@ -162,6 +187,10 @@
     delete[] buf;
 }
 
+/**
+ * \ingroup click-tests
+ * Click trivial test.
+ */
 class ClickTrivialTest : public TestCase
 {
   public:
@@ -206,6 +235,10 @@
     delete[] buf;
 }
 
+/**
+ * \ingroup click-tests
+ * Click interface ID from name test.
+ */
 class ClickIfidFromNameTestSuite : public TestSuite
 {
   public:
@@ -216,6 +249,7 @@
         AddTestCase(new ClickIfidFromNameTest, TestCase::QUICK);
         AddTestCase(new ClickIpMacAddressFromNameTest, TestCase::QUICK);
     }
-} g_ipv4ClickRoutingTestSuite;
+};
 
-#endif // NS3_CLICK
+/// Static variable for test initialization
+static ClickIfidFromNameTestSuite g_ipv4ClickRoutingTestSuite;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/config-store/model/attribute-iterator.cc ns-3.40/src/config-store/model/attribute-iterator.cc
--- ns-3.39/src/config-store/model/attribute-iterator.cc	2023-07-05 14:23:47.741427200 -0700
+++ ns-3.40/src/config-store/model/attribute-iterator.cc	2023-09-27 13:30:37.622839000 -0700
@@ -227,8 +227,7 @@
         for (uint32_t i = 0; i < tid.GetAttributeN(); ++i)
         {
             TypeId::AttributeInformation info = tid.GetAttribute(i);
-            const PointerChecker* ptrChecker =
-                dynamic_cast<const PointerChecker*>(PeekPointer(info.checker));
+            const auto ptrChecker = dynamic_cast<const PointerChecker*>(PeekPointer(info.checker));
             if (ptrChecker != nullptr)
             {
                 NS_LOG_DEBUG("pointer attribute " << info.name);
@@ -246,7 +245,7 @@
                 continue;
             }
             // attempt to cast to an object container
-            const ObjectPtrContainerChecker* vectorChecker =
+            const auto vectorChecker =
                 dynamic_cast<const ObjectPtrContainerChecker*>(PeekPointer(info.checker));
             if (vectorChecker != nullptr)
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/config-store/model/model-node-creator.cc ns-3.40/src/config-store/model/model-node-creator.cc
--- ns-3.39/src/config-store/model/model-node-creator.cc	2023-07-05 14:23:47.741427200 -0700
+++ ns-3.40/src/config-store/model/model-node-creator.cc	2023-09-27 13:30:37.622839000 -0700
@@ -41,7 +41,7 @@
 ModelCreator::Add(ModelNode* node)
 {
     GtkTreeIter* parent = m_iters.back();
-    GtkTreeIter* current = g_new(GtkTreeIter, 1);
+    auto current = g_new(GtkTreeIter, 1);
     gtk_tree_store_append(m_treestore, current, parent);
     gtk_tree_store_set(m_treestore, current, COL_NODE, node, -1);
     m_iters.push_back(current);
@@ -58,7 +58,7 @@
 void
 ModelCreator::DoVisitAttribute(Ptr<Object> object, std::string name)
 {
-    ModelNode* node = new ModelNode();
+    auto node = new ModelNode();
     node->type = ModelNode::NODE_ATTRIBUTE;
     node->object = object;
     node->name = name;
@@ -69,7 +69,7 @@
 void
 ModelCreator::DoStartVisitObject(Ptr<Object> object)
 {
-    ModelNode* node = new ModelNode();
+    auto node = new ModelNode();
     node->type = ModelNode::NODE_OBJECT;
     node->object = object;
     Add(node);
@@ -84,7 +84,7 @@
 void
 ModelCreator::DoStartVisitPointerAttribute(Ptr<Object> object, std::string name, Ptr<Object> value)
 {
-    ModelNode* node = new ModelNode();
+    auto node = new ModelNode();
     node->type = ModelNode::NODE_POINTER;
     node->object = object;
     node->name = name;
@@ -102,7 +102,7 @@
                                          std::string name,
                                          const ObjectPtrContainerValue& vector)
 {
-    ModelNode* node = new ModelNode();
+    auto node = new ModelNode();
     node->type = ModelNode::NODE_VECTOR;
     node->object = object;
     node->name = name;
@@ -121,8 +121,8 @@
                                     Ptr<Object> item)
 {
     GtkTreeIter* parent = m_iters.back();
-    GtkTreeIter* current = g_new(GtkTreeIter, 1);
-    ModelNode* node = new ModelNode();
+    auto current = g_new(GtkTreeIter, 1);
+    auto node = new ModelNode();
     node->type = ModelNode::NODE_VECTOR_ITEM;
     node->object = item;
     node->index = index;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/config-store/model/model-typeid-creator.cc ns-3.40/src/config-store/model/model-typeid-creator.cc
--- ns-3.39/src/config-store/model/model-typeid-creator.cc	2023-07-05 14:23:47.741427200 -0700
+++ ns-3.40/src/config-store/model/model-typeid-creator.cc	2023-09-27 13:30:37.622839000 -0700
@@ -38,7 +38,7 @@
 ModelTypeidCreator::Add(ModelTypeid* node)
 {
     GtkTreeIter* parent = m_iters.back();
-    GtkTreeIter* current = g_new(GtkTreeIter, 1);
+    auto current = g_new(GtkTreeIter, 1);
     gtk_tree_store_append(m_treestore, current, parent);
     gtk_tree_store_set(m_treestore, current, COL_TYPEID, node, -1);
     m_iters.push_back(current);
@@ -58,7 +58,7 @@
                                    std::string defaultValue,
                                    uint32_t index)
 {
-    ModelTypeid* node = new ModelTypeid();
+    auto node = new ModelTypeid();
     node->type = ModelTypeid::NODE_ATTRIBUTE;
     node->tid = tid;
     node->name = name;
@@ -71,7 +71,7 @@
 void
 ModelTypeidCreator::StartVisitTypeId(std::string name)
 {
-    ModelTypeid* node = new ModelTypeid();
+    auto node = new ModelTypeid();
     node->type = ModelTypeid::NODE_TYPEID;
     node->tid = TypeId::LookupByName(name);
     Add(node);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/config-store/model/raw-text-config.cc ns-3.40/src/config-store/model/raw-text-config.cc
--- ns-3.39/src/config-store/model/raw-text-config.cc	2023-07-05 14:23:47.741427200 -0700
+++ ns-3.40/src/config-store/model/raw-text-config.cc	2023-09-27 13:30:37.622839000 -0700
@@ -131,7 +131,7 @@
 RawTextConfigSave::Global()
 {
     NS_LOG_FUNCTION(this);
-    for (GlobalValue::Iterator i = GlobalValue::Begin(); i != GlobalValue::End(); ++i)
+    for (auto i = GlobalValue::Begin(); i != GlobalValue::End(); ++i)
     {
         StringValue value;
         (*i)->GetValue(value);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/config-store/model/xml-config.cc ns-3.40/src/config-store/model/xml-config.cc
--- ns-3.39/src/config-store/model/xml-config.cc	2023-07-05 14:23:47.741427200 -0700
+++ ns-3.40/src/config-store/model/xml-config.cc	2023-09-27 13:30:37.622839000 -0700
@@ -271,7 +271,7 @@
 XmlConfigSave::Global()
 {
     int rc;
-    for (GlobalValue::Iterator i = GlobalValue::Begin(); i != GlobalValue::End(); ++i)
+    for (auto i = GlobalValue::Begin(); i != GlobalValue::End(); ++i)
     {
         StringValue value;
         (*i)->GetValue(value);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/CMakeLists.txt ns-3.40/src/core/CMakeLists.txt
--- ns-3.39/src/core/CMakeLists.txt	2023-07-05 14:23:47.741427200 -0700
+++ ns-3.40/src/core/CMakeLists.txt	2023-09-27 13:30:37.622839000 -0700
@@ -1,7 +1,5 @@
 # Set lib core link dependencies
-set(libraries_to_link
-    ${CMAKE_THREAD_LIBS_INIT}
-)
+set(libraries_to_link)
 
 set(gsl_test_sources)
 if(${GSL_FOUND})
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/examples/CMakeLists.txt ns-3.40/src/core/examples/CMakeLists.txt
--- ns-3.39/src/core/examples/CMakeLists.txt	2023-07-05 14:23:47.741427200 -0700
+++ ns-3.40/src/core/examples/CMakeLists.txt	2023-09-27 13:30:37.622839000 -0700
@@ -47,7 +47,6 @@
   NAME main-test-sync
   SOURCE_FILES main-test-sync.cc
   LIBRARIES_TO_LINK ${libnetwork}
-                    ${CMAKE_THREAD_LIBS_INIT}
 )
 
 build_lib_example(
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/examples/hash-example.cc ns-3.40/src/core/examples/hash-example.cc
--- ns-3.39/src/core/examples/hash-example.cc	2023-07-05 14:23:47.745427100 -0700
+++ ns-3.40/src/core/examples/hash-example.cc	2023-09-27 13:30:37.622839000 -0700
@@ -296,10 +296,10 @@
             return;
         }
 
-        int newPhrases = 0;
+        bool newPhrases = false;
         for (auto& collider : m_hashes)
         {
-            newPhrases += collider.Add(phrase);
+            newPhrases |= collider.Add(phrase);
         }
 
         if (newPhrases)
@@ -352,7 +352,7 @@
         //
         // Number of buckets = k = 2^bits
         long double k32 = 0xFFFFFFFF;
-        long double k64 = static_cast<long double>(0xFFFFFFFFFFFFFFFFULL);
+        auto k64 = static_cast<long double>(0xFFFFFFFFFFFFFFFFULL);
 
         long double n = m_nphrases;
         long double Ec32 = n * (n - 1) / (2 * k32) * (1 - (n - 2) / (3 * k32));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/examples/main-random-variable-stream.cc ns-3.40/src/core/examples/main-random-variable-stream.cc
--- ns-3.39/src/core/examples/main-random-variable-stream.cc	2023-07-05 14:23:47.745427100 -0700
+++ ns-3.40/src/core/examples/main-random-variable-stream.cc	2023-09-27 13:30:37.622839000 -0700
@@ -99,7 +99,7 @@
         data.SetStyle(Gnuplot2dDataset::IMPULSES);
     }
 
-    for (histogram_maptype::const_iterator hi = histogram.begin(); hi != histogram.end(); ++hi)
+    for (auto hi = histogram.begin(); hi != histogram.end(); ++hi)
     {
         data.Add(hi->first, (double)hi->second / (double)probes / precision);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/helper/event-garbage-collector.cc ns-3.40/src/core/helper/event-garbage-collector.cc
--- ns-3.39/src/core/helper/event-garbage-collector.cc	2023-07-05 14:23:47.745427100 -0700
+++ ns-3.40/src/core/helper/event-garbage-collector.cc	2023-09-27 13:30:37.622839000 -0700
@@ -65,7 +65,7 @@
 void
 EventGarbageCollector::Cleanup()
 {
-    for (EventList::iterator iter = m_events.begin(); iter != m_events.end();)
+    for (auto iter = m_events.begin(); iter != m_events.end();)
     {
         if ((*iter).IsExpired())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/ascii-test.h ns-3.40/src/core/model/ascii-test.h
--- ns-3.39/src/core/model/ascii-test.h	2023-07-05 14:23:47.749427000 -0700
+++ ns-3.40/src/core/model/ascii-test.h	2023-09-27 13:30:37.622839000 -0700
@@ -23,8 +23,7 @@
 #define ASCII_TEST_H
 
 #include "ascii-file.h"
-
-#include "ns3/test.h"
+#include "test.h"
 
 #include <stdint.h>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/attribute.cc ns-3.40/src/core/model/attribute.cc
--- ns-3.39/src/core/model/attribute.cc	2023-07-05 14:23:47.749427000 -0700
+++ ns-3.40/src/core/model/attribute.cc	2023-09-27 13:30:37.626839000 -0700
@@ -69,7 +69,7 @@
         return value.Copy();
     }
     // attempt to convert to string.
-    const StringValue* str = dynamic_cast<const StringValue*>(&value);
+    const auto str = dynamic_cast<const StringValue*>(&value);
     if (str == nullptr)
     {
         return nullptr;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/attribute-construction-list.cc ns-3.40/src/core/model/attribute-construction-list.cc
--- ns-3.39/src/core/model/attribute-construction-list.cc	2023-07-05 14:23:47.749427000 -0700
+++ ns-3.40/src/core/model/attribute-construction-list.cc	2023-09-27 13:30:37.626839000 -0700
@@ -45,7 +45,7 @@
     // vector of values.
     NS_LOG_FUNCTION(this << name << checker << value);
 
-    for (std::list<Item>::iterator k = m_list.begin(); k != m_list.end(); k++)
+    for (auto k = m_list.begin(); k != m_list.end(); k++)
     {
         if (k->checker == checker)
         {
@@ -65,7 +65,7 @@
 AttributeConstructionList::Find(Ptr<const AttributeChecker> checker) const
 {
     NS_LOG_FUNCTION(this << checker);
-    for (CIterator k = m_list.begin(); k != m_list.end(); k++)
+    for (auto k = m_list.begin(); k != m_list.end(); k++)
     {
         NS_LOG_DEBUG("Found " << k->name << " " << k->checker << " " << k->value);
         if (k->checker == checker)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/attribute-container.h ns-3.40/src/core/model/attribute-container.h
--- ns-3.39/src/core/model/attribute-container.h	2023-07-05 14:23:47.749427000 -0700
+++ ns-3.40/src/core/model/attribute-container.h	2023-09-27 13:30:37.626839000 -0700
@@ -20,8 +20,8 @@
 #ifndef ATTRIBUTE_CONTAINER_H
 #define ATTRIBUTE_CONTAINER_H
 
-#include <ns3/attribute-helper.h>
-#include <ns3/string.h>
+#include "attribute-helper.h"
+#include "string.h"
 
 #include <algorithm>
 #include <iterator>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/calendar-scheduler.cc ns-3.40/src/core/model/calendar-scheduler.cc
--- ns-3.39/src/core/model/calendar-scheduler.cc	2023-07-05 14:23:47.749427000 -0700
+++ ns-3.40/src/core/model/calendar-scheduler.cc	2023-09-27 13:30:37.626839000 -0700
@@ -137,8 +137,8 @@
     NS_LOG_LOGIC("insert in bucket=" << bucket);
 
     // insert in bucket list.
-    Bucket::iterator end = m_buckets[bucket].end();
-    for (Bucket::iterator i = m_buckets[bucket].begin(); i != end; ++i)
+    auto end = m_buckets[bucket].end();
+    for (auto i = m_buckets[bucket].begin(); i != end; ++i)
     {
         if (Order(ev.key, i->key))
         {
@@ -267,8 +267,8 @@
     // bucket index of event
     uint32_t bucket = Hash(ev.key.m_ts);
 
-    Bucket::iterator end = m_buckets[bucket].end();
-    for (Bucket::iterator i = m_buckets[bucket].begin(); i != end; ++i)
+    auto end = m_buckets[bucket].end();
+    for (auto i = m_buckets[bucket].begin(); i != end; ++i)
     {
         if (i->key.m_uid == ev.key.m_uid)
         {
@@ -341,7 +341,7 @@
         samples.push_back(DoRemoveNext());
     }
     // put them back
-    for (std::list<Scheduler::Event>::const_iterator i = samples.begin(); i != samples.end(); ++i)
+    for (auto i = samples.begin(); i != samples.end(); ++i)
     {
         DoInsert(*i);
     }
@@ -353,9 +353,9 @@
 
     // finally calculate inter-time average over samples.
     uint64_t totalSeparation = 0;
-    std::list<Scheduler::Event>::const_iterator end = samples.end();
-    std::list<Scheduler::Event>::const_iterator cur = samples.begin();
-    std::list<Scheduler::Event>::const_iterator next = cur;
+    auto end = samples.end();
+    auto cur = samples.begin();
+    auto next = cur;
     next++;
     while (next != end)
     {
@@ -395,8 +395,8 @@
 
     for (uint32_t i = 0; i < oldNBuckets; i++)
     {
-        Bucket::iterator end = oldBuckets[i].end();
-        for (Bucket::iterator j = oldBuckets[i].begin(); j != end; ++j)
+        auto end = oldBuckets[i].end();
+        for (auto j = oldBuckets[i].begin(); j != end; ++j)
         {
             DoInsert(*j);
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/callback.h ns-3.40/src/core/model/callback.h
--- ns-3.39/src/core/model/callback.h	2023-07-05 14:23:47.749427000 -0700
+++ ns-3.40/src/core/model/callback.h	2023-09-27 13:30:37.626839000 -0700
@@ -284,7 +284,7 @@
 
     bool IsEqual(Ptr<const CallbackImplBase> other) const override
     {
-        const CallbackImpl<R, UArgs...>* otherDerived =
+        const auto otherDerived =
             dynamic_cast<const CallbackImpl<R, UArgs...>*>(PeekPointer(other));
 
         if (otherDerived == nullptr)
@@ -324,7 +324,7 @@
         return DoGetTypeid();
     }
 
-    /** \copydoc GetTypeid(). */
+    /** \copydoc GetTypeid() */
     static std::string DoGetTypeid()
     {
         static std::vector<std::string> vec = {GetCppTypeid<R>(), GetCppTypeid<UArgs>()...};
@@ -467,7 +467,8 @@
         auto f = cb.DoPeekImpl()->GetFunction();
 
         CallbackComponentVector components(cb.DoPeekImpl()->GetComponents());
-        components.insert(components.end(), {std::make_shared<CallbackComponent<BArgs>>(bargs)...});
+        components.insert(components.end(),
+                          {std::make_shared<CallbackComponent<std::decay_t<BArgs>>>(bargs)...});
 
         m_impl = Create<CallbackImpl<R, UArgs...>>(
             [f, bargs...](auto&&... uargs) -> R {
@@ -501,8 +502,9 @@
         constexpr bool isComp =
             std::is_function_v<std::remove_pointer_t<T>> || std::is_member_pointer_v<T>;
 
-        CallbackComponentVector components({std::make_shared<CallbackComponent<T, isComp>>(func),
-                                            std::make_shared<CallbackComponent<BArgs>>(bargs)...});
+        CallbackComponentVector components(
+            {std::make_shared<CallbackComponent<T, isComp>>(func),
+             std::make_shared<CallbackComponent<std::decay_t<BArgs>>>(bargs)...});
 
         m_impl = Create<CallbackImpl<R, UArgs...>>(
             [f, bargs...](auto&&... uargs) -> R {
@@ -532,7 +534,7 @@
 
         CallbackComponentVector components(DoPeekImpl()->GetComponents());
         components.insert(components.end(),
-                          {std::make_shared<CallbackComponent<BoundArgs>>(bargs)...});
+                          {std::make_shared<CallbackComponent<std::decay_t<BoundArgs>>>(bargs)...});
 
         cb.m_impl = Create<std::remove_pointer_t<decltype(cb.DoPeekImpl())>>(
             [f, bargs...](auto&&... uargs) mutable {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/config.cc ns-3.40/src/core/model/config.cc
--- ns-3.39/src/core/model/config.cc	2023-07-05 14:23:47.753427000 -0700
+++ ns-3.40/src/core/model/config.cc	2023-09-27 13:30:37.626839000 -0700
@@ -103,7 +103,7 @@
 MatchContainer::Set(std::string name, const AttributeValue& value)
 {
     NS_LOG_FUNCTION(this << name << &value);
-    for (Iterator tmp = Begin(); tmp != End(); ++tmp)
+    for (auto tmp = Begin(); tmp != End(); ++tmp)
     {
         Ptr<Object> object = *tmp;
         // Let ObjectBase::SetAttribute raise any errors
@@ -116,7 +116,7 @@
 {
     NS_LOG_FUNCTION(this << name << &value);
     bool ok = false;
-    for (Iterator tmp = Begin(); tmp != End(); ++tmp)
+    for (auto tmp = Begin(); tmp != End(); ++tmp)
     {
         Ptr<Object> object = *tmp;
         ok |= object->SetAttributeFailSafe(name, value);
@@ -162,7 +162,7 @@
 {
     NS_LOG_FUNCTION(this << name << &cb);
     bool ok = false;
-    for (Iterator tmp = Begin(); tmp != End(); ++tmp)
+    for (auto tmp = Begin(); tmp != End(); ++tmp)
     {
         Ptr<Object> object = *tmp;
         ok |= object->TraceConnectWithoutContext(name, cb);
@@ -187,7 +187,7 @@
 MatchContainer::DisconnectWithoutContext(std::string name, const CallbackBase& cb)
 {
     NS_LOG_FUNCTION(this << name << &cb);
-    for (Iterator tmp = Begin(); tmp != End(); ++tmp)
+    for (auto tmp = Begin(); tmp != End(); ++tmp)
     {
         Ptr<Object> object = *tmp;
         object->TraceDisconnectWithoutContext(name, cb);
@@ -423,8 +423,7 @@
     NS_LOG_FUNCTION(this);
 
     std::string fullPath = "/";
-    for (std::vector<std::string>::const_iterator i = m_workStack.begin(); i != m_workStack.end();
-         i++)
+    for (auto i = m_workStack.begin(); i != m_workStack.end(); i++)
     {
         fullPath += *i + "/";
     }
@@ -549,7 +548,7 @@
                     continue;
                 }
                 // attempt to cast to a pointer checker.
-                const PointerChecker* pChecker =
+                const auto pChecker =
                     dynamic_cast<const PointerChecker*>(PeekPointer(info.checker));
                 if (pChecker != nullptr)
                 {
@@ -572,7 +571,7 @@
                     m_workStack.pop_back();
                 }
                 // attempt to cast to an object vector.
-                const ObjectPtrContainerChecker* vectorChecker =
+                const auto vectorChecker =
                     dynamic_cast<const ObjectPtrContainerChecker*>(PeekPointer(info.checker));
                 if (vectorChecker != nullptr)
                 {
@@ -801,7 +800,7 @@
         std::vector<std::string> m_contexts;
     } resolver = LookupMatchesResolver(path);
 
-    for (Roots::const_iterator i = m_roots.begin(); i != m_roots.end(); i++)
+    for (auto i = m_roots.begin(); i != m_roots.end(); i++)
     {
         resolver.Resolve(*i);
     }
@@ -828,7 +827,7 @@
 {
     NS_LOG_FUNCTION(this << obj);
 
-    for (std::vector<Ptr<Object>>::iterator i = m_roots.begin(); i != m_roots.end(); i++)
+    for (auto i = m_roots.begin(); i != m_roots.end(); i++)
     {
         if (*i == obj)
         {
@@ -867,7 +866,7 @@
         }
     }
     // now, let's reset the initial value of every global value.
-    for (GlobalValue::Iterator i = GlobalValue::Begin(); i != GlobalValue::End(); ++i)
+    for (auto i = GlobalValue::Begin(); i != GlobalValue::End(); ++i)
     {
         (*i)->ResetInitialValue();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/default-simulator-impl.cc ns-3.40/src/core/model/default-simulator-impl.cc
--- ns-3.39/src/core/model/default-simulator-impl.cc	2023-07-05 14:23:47.753427000 -0700
+++ ns-3.40/src/core/model/default-simulator-impl.cc	2023-09-27 13:30:37.626839000 -0700
@@ -319,7 +319,7 @@
     if (id.GetUid() == EventId::UID::DESTROY)
     {
         // destroy events.
-        for (DestroyEvents::iterator i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
+        for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
         {
             if (*i == id)
             {
@@ -365,8 +365,7 @@
             return true;
         }
         // destroy events.
-        for (DestroyEvents::const_iterator i = m_destroyEvents.begin(); i != m_destroyEvents.end();
-             i++)
+        for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
         {
             if (*i == id)
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/deprecated.h ns-3.40/src/core/model/deprecated.h
--- ns-3.39/src/core/model/deprecated.h	2023-07-05 14:23:47.753427000 -0700
+++ ns-3.40/src/core/model/deprecated.h	2023-09-27 13:30:37.626839000 -0700
@@ -76,6 +76,13 @@
 
 /**
  * \ingroup core
+ * \def NS_DEPRECATED_3_40
+ * Tag for things deprecated in version ns-3.40.
+ */
+#define NS_DEPRECATED_3_40(msg) NS_DEPRECATED(msg)
+
+/**
+ * \ingroup core
  * \def NS_DEPRECATED_3_39
  * Tag for things deprecated in version ns-3.39.
  */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/double.cc ns-3.40/src/core/model/double.cc
--- ns-3.39/src/core/model/double.cc	2023-07-05 14:23:47.753427000 -0700
+++ ns-3.40/src/core/model/double.cc	2023-09-27 13:30:37.626839000 -0700
@@ -66,7 +66,7 @@
         bool Check(const AttributeValue& value) const override
         {
             NS_LOG_FUNCTION(&value);
-            const DoubleValue* v = dynamic_cast<const DoubleValue*>(&value);
+            const auto v = dynamic_cast<const DoubleValue*>(&value);
             if (v == nullptr)
             {
                 return false;
@@ -103,8 +103,8 @@
         bool Copy(const AttributeValue& source, AttributeValue& destination) const override
         {
             NS_LOG_FUNCTION(&source << &destination);
-            const DoubleValue* src = dynamic_cast<const DoubleValue*>(&source);
-            DoubleValue* dst = dynamic_cast<DoubleValue*>(&destination);
+            const auto src = dynamic_cast<const DoubleValue*>(&source);
+            auto dst = dynamic_cast<DoubleValue*>(&destination);
             if (src == nullptr || dst == nullptr)
             {
                 return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/enum.cc ns-3.40/src/core/model/enum.cc
--- ns-3.39/src/core/model/enum.cc	2023-07-05 14:23:47.753427000 -0700
+++ ns-3.40/src/core/model/enum.cc	2023-09-27 13:30:37.626839000 -0700
@@ -73,7 +73,7 @@
 EnumValue::SerializeToString(Ptr<const AttributeChecker> checker) const
 {
     NS_LOG_FUNCTION(this << checker);
-    const EnumChecker* p = dynamic_cast<const EnumChecker*>(PeekPointer(checker));
+    const auto p = dynamic_cast<const EnumChecker*>(PeekPointer(checker));
     NS_ASSERT(p != nullptr);
     std::string name = p->GetName(m_value);
     return name;
@@ -83,7 +83,7 @@
 EnumValue::DeserializeFromString(std::string value, Ptr<const AttributeChecker> checker)
 {
     NS_LOG_FUNCTION(this << value << checker);
-    const EnumChecker* p = dynamic_cast<const EnumChecker*>(PeekPointer(checker));
+    const auto p = dynamic_cast<const EnumChecker*>(PeekPointer(checker));
     NS_ASSERT(p != nullptr);
     m_value = p->GetValue(value);
     return true;
@@ -150,7 +150,7 @@
 EnumChecker::Check(const AttributeValue& value) const
 {
     NS_LOG_FUNCTION(this << &value);
-    const EnumValue* p = dynamic_cast<const EnumValue*>(&value);
+    const auto p = dynamic_cast<const EnumValue*>(&value);
     if (p == nullptr)
     {
         return false;
@@ -201,8 +201,8 @@
 EnumChecker::Copy(const AttributeValue& source, AttributeValue& destination) const
 {
     NS_LOG_FUNCTION(this << &source << &destination);
-    const EnumValue* src = dynamic_cast<const EnumValue*>(&source);
-    EnumValue* dst = dynamic_cast<EnumValue*>(&destination);
+    const auto src = dynamic_cast<const EnumValue*>(&source);
+    auto dst = dynamic_cast<EnumValue*>(&destination);
     if (src == nullptr || dst == nullptr)
     {
         return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/environment-variable.cc ns-3.40/src/core/model/environment-variable.cc
--- ns-3.39/src/core/model/environment-variable.cc	2023-07-05 14:23:47.753427000 -0700
+++ ns-3.40/src/core/model/environment-variable.cc	2023-09-27 13:30:37.626839000 -0700
@@ -19,7 +19,7 @@
 
 #include "environment-variable.h"
 
-#include "ns3/string.h"
+#include "string.h"
 
 #include <cstdlib>  // std::getenv
 #include <cstring>  // strlen
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/example-as-test.h ns-3.40/src/core/model/example-as-test.h
--- ns-3.39/src/core/model/example-as-test.h	2023-07-05 14:23:47.753427000 -0700
+++ ns-3.40/src/core/model/example-as-test.h	2023-09-27 13:30:37.626839000 -0700
@@ -20,7 +20,7 @@
 #ifndef NS3_EXAMPLE_AS_TEST_SUITE_H
 #define NS3_EXAMPLE_AS_TEST_SUITE_H
 
-#include "ns3/test.h"
+#include "test.h"
 
 #include <string>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/global-value.cc ns-3.40/src/core/model/global-value.cc
--- ns-3.39/src/core/model/global-value.cc	2023-07-05 14:23:47.753427000 -0700
+++ ns-3.40/src/core/model/global-value.cc	2023-09-27 13:30:37.626839000 -0700
@@ -103,7 +103,7 @@
     {
         return;
     }
-    StringValue* str = dynamic_cast<StringValue*>(&value);
+    auto str = dynamic_cast<StringValue*>(&value);
     if (str == nullptr)
     {
         NS_FATAL_ERROR("GlobalValue name=" << m_name << ": input value is not a string");
@@ -127,7 +127,7 @@
     Ptr<AttributeValue> v = m_checker->CreateValidValue(value);
     if (!v)
     {
-        return 0;
+        return false;
     }
     m_currentValue = v;
     return true;
@@ -138,7 +138,7 @@
 {
     NS_LOG_FUNCTION(name << &value);
 
-    for (Iterator i = Begin(); i != End(); i++)
+    for (auto i = Begin(); i != End(); i++)
     {
         if ((*i)->GetName() == name)
         {
@@ -157,7 +157,7 @@
 {
     NS_LOG_FUNCTION(name << &value);
 
-    for (Iterator i = Begin(); i != End(); i++)
+    for (auto i = Begin(); i != End(); i++)
     {
         if ((*i)->GetName() == name)
         {
@@ -193,7 +193,7 @@
 GlobalValue::GetValueByNameFailSafe(std::string name, AttributeValue& value)
 {
     NS_LOG_FUNCTION(name << &value);
-    for (GlobalValue::Iterator gvit = GlobalValue::Begin(); gvit != GlobalValue::End(); ++gvit)
+    for (auto gvit = GlobalValue::Begin(); gvit != GlobalValue::End(); ++gvit)
     {
         if ((*gvit)->GetName() == name)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/int64x64.cc ns-3.40/src/core/model/int64x64.cc
--- ns-3.39/src/core/model/int64x64.cc	2023-07-05 14:23:47.757427200 -0700
+++ ns-3.40/src/core/model/int64x64.cc	2023-09-27 13:30:37.626839000 -0700
@@ -74,7 +74,7 @@
     int64_t hi = absVal.GetHigh();
 
     // Save stream format flags
-    std::size_t precision = static_cast<std::size_t>(os.precision());
+    auto precision = static_cast<std::size_t>(os.precision());
     std::ios_base::fmtflags ff = os.flags();
     const bool floatfield = os.flags() & std::ios_base::floatfield;
     os << std::setw(1) << std::noshowpos;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/integer.cc ns-3.40/src/core/model/integer.cc
--- ns-3.39/src/core/model/integer.cc	2023-07-05 14:23:47.757427200 -0700
+++ ns-3.40/src/core/model/integer.cc	2023-09-27 13:30:37.626839000 -0700
@@ -65,7 +65,7 @@
         bool Check(const AttributeValue& value) const override
         {
             NS_LOG_FUNCTION(&value);
-            const IntegerValue* v = dynamic_cast<const IntegerValue*>(&value);
+            const auto v = dynamic_cast<const IntegerValue*>(&value);
             if (v == nullptr)
             {
                 return false;
@@ -102,8 +102,8 @@
         bool Copy(const AttributeValue& src, AttributeValue& dst) const override
         {
             NS_LOG_FUNCTION(&src << &dst);
-            const IntegerValue* source = dynamic_cast<const IntegerValue*>(&src);
-            IntegerValue* destination = dynamic_cast<IntegerValue*>(&dst);
+            const auto source = dynamic_cast<const IntegerValue*>(&src);
+            auto destination = dynamic_cast<IntegerValue*>(&dst);
             if (source == nullptr || destination == nullptr)
             {
                 return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/length.cc ns-3.40/src/core/model/length.cc
--- ns-3.39/src/core/model/length.cc	2023-07-05 14:23:47.757427200 -0700
+++ ns-3.40/src/core/model/length.cc	2023-09-27 13:30:37.626839000 -0700
@@ -17,9 +17,9 @@
  * Author: Mathew Bielejeski <bielejeski1@llnl.gov>
  */
 
-#include "ns3/length.h"
+#include "length.h"
 
-#include "ns3/log.h"
+#include "log.h"
 
 #include <algorithm>
 #include <array>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/list-scheduler.cc ns-3.40/src/core/model/list-scheduler.cc
--- ns-3.39/src/core/model/list-scheduler.cc	2023-07-05 14:23:47.757427200 -0700
+++ ns-3.40/src/core/model/list-scheduler.cc	2023-09-27 13:30:37.630839000 -0700
@@ -62,7 +62,7 @@
 ListScheduler::Insert(const Event& ev)
 {
     NS_LOG_FUNCTION(this << &ev);
-    for (EventsI i = m_events.begin(); i != m_events.end(); i++)
+    for (auto i = m_events.begin(); i != m_events.end(); i++)
     {
         if (ev.key < i->key)
         {
@@ -100,7 +100,7 @@
 ListScheduler::Remove(const Event& ev)
 {
     NS_LOG_FUNCTION(this << &ev);
-    for (EventsI i = m_events.begin(); i != m_events.end(); i++)
+    for (auto i = m_events.begin(); i != m_events.end(); i++)
     {
         if (i->key.m_uid == ev.key.m_uid)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/log.cc ns-3.40/src/core/model/log.cc
--- ns-3.39/src/core/model/log.cc	2023-07-05 14:23:47.757427200 -0700
+++ ns-3.40/src/core/model/log.cc	2023-09-27 13:30:37.630839000 -0700
@@ -247,7 +247,7 @@
 LogComponent::IsEnabled(const LogLevel level) const
 {
     //  LogComponentEnableEnvVar ();
-    return (level & m_levels) ? 1 : 0;
+    return level & m_levels;
 }
 
 bool
@@ -320,9 +320,7 @@
 LogComponentEnableAll(LogLevel level)
 {
     LogComponent::ComponentList* components = LogComponent::GetComponentList();
-    for (LogComponent::ComponentList::const_iterator i = components->begin();
-         i != components->end();
-         i++)
+    for (auto i = components->begin(); i != components->end(); i++)
     {
         i->second->Enable(level);
     }
@@ -344,9 +342,7 @@
 LogComponentDisableAll(LogLevel level)
 {
     LogComponent::ComponentList* components = LogComponent::GetComponentList();
-    for (LogComponent::ComponentList::const_iterator i = components->begin();
-         i != components->end();
-         i++)
+    for (auto i = components->begin(); i != components->end(); i++)
     {
         i->second->Disable(level);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/map-scheduler.cc ns-3.40/src/core/model/map-scheduler.cc
--- ns-3.39/src/core/model/map-scheduler.cc	2023-07-05 14:23:47.757427200 -0700
+++ ns-3.40/src/core/model/map-scheduler.cc	2023-09-27 13:30:37.630839000 -0700
@@ -79,7 +79,7 @@
 MapScheduler::PeekNext() const
 {
     NS_LOG_FUNCTION(this);
-    EventMapCI i = m_list.begin();
+    auto i = m_list.begin();
     NS_ASSERT(i != m_list.end());
 
     Event ev;
@@ -93,7 +93,7 @@
 MapScheduler::RemoveNext()
 {
     NS_LOG_FUNCTION(this);
-    EventMapI i = m_list.begin();
+    auto i = m_list.begin();
     NS_ASSERT(i != m_list.end());
     Event ev;
     ev.impl = i->second;
@@ -107,7 +107,7 @@
 MapScheduler::Remove(const Event& ev)
 {
     NS_LOG_FUNCTION(this << ev.impl << ev.key.m_ts << ev.key.m_uid);
-    EventMapI i = m_list.find(ev.key);
+    auto i = m_list.find(ev.key);
     NS_ASSERT(i->second == ev.impl);
     m_list.erase(i);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/matrix-array.h ns-3.40/src/core/model/matrix-array.h
--- ns-3.39/src/core/model/matrix-array.h	2023-07-05 14:23:47.757427200 -0700
+++ ns-3.40/src/core/model/matrix-array.h	2023-09-27 13:30:37.630839000 -0700
@@ -243,8 +243,7 @@
      * \return Returns a new matrix that is the result of the Hermitian transpose
      */
     template <bool EnableBool = true,
-              typename = typename std::enable_if<(std::is_same<T, std::complex<double>>::value &&
-                                                  EnableBool)>::type>
+              typename = std::enable_if_t<(std::is_same_v<T, std::complex<double>> && EnableBool)>>
     MatrixArray<T> HermitianTranspose() const;
 
   protected:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/names.cc ns-3.40/src/core/model/names.cc
--- ns-3.39/src/core/model/names.cc	2023-07-05 14:23:47.757427200 -0700
+++ ns-3.40/src/core/model/names.cc	2023-09-27 13:30:37.630839000 -0700
@@ -303,8 +303,7 @@
     // Every name is associated with an object in the object map, so freeing the
     // NameNodes in this map will free all of the memory allocated for the NameNodes
     //
-    for (std::map<Ptr<Object>, NameNode*>::iterator i = m_objectMap.begin(); i != m_objectMap.end();
-         ++i)
+    for (auto i = m_objectMap.begin(); i != m_objectMap.end(); ++i)
     {
         delete i->second;
         i->second = nullptr;
@@ -420,7 +419,7 @@
         return false;
     }
 
-    NameNode* newNode = new NameNode(node, name, object);
+    auto newNode = new NameNode(node, name, object);
     node->m_nameMap[name] = newNode;
     m_objectMap[object] = newNode;
 
@@ -525,7 +524,7 @@
         return false;
     }
 
-    std::map<std::string, NameNode*>::iterator i = node->m_nameMap.find(oldname);
+    auto i = node->m_nameMap.find(oldname);
     if (i == node->m_nameMap.end())
     {
         NS_LOG_LOGIC("Old name does not exist in name map");
@@ -555,7 +554,7 @@
 {
     NS_LOG_FUNCTION(this << object);
 
-    std::map<Ptr<Object>, NameNode*>::iterator i = m_objectMap.find(object);
+    auto i = m_objectMap.find(object);
     if (i == m_objectMap.end())
     {
         NS_LOG_LOGIC("Object does not exist in object map");
@@ -573,7 +572,7 @@
 {
     NS_LOG_FUNCTION(this << object);
 
-    std::map<Ptr<Object>, NameNode*>::iterator i = m_objectMap.find(object);
+    auto i = m_objectMap.find(object);
     if (i == m_objectMap.end())
     {
         NS_LOG_LOGIC("Object does not exist in object map");
@@ -648,7 +647,7 @@
             // There are no remaining slashes so this is the last segment of the
             // specified name.  We're done when we find it
             //
-            std::map<std::string, NameNode*>::iterator i = node->m_nameMap.find(remaining);
+            auto i = node->m_nameMap.find(remaining);
             if (i == node->m_nameMap.end())
             {
                 NS_LOG_LOGIC("Name does not exist in name map");
@@ -669,7 +668,7 @@
             offset = remaining.find('/');
             std::string segment = remaining.substr(0, offset);
 
-            std::map<std::string, NameNode*>::iterator i = node->m_nameMap.find(segment);
+            auto i = node->m_nameMap.find(segment);
             if (i == node->m_nameMap.end())
             {
                 NS_LOG_LOGIC("Name does not exist in name map");
@@ -723,7 +722,7 @@
         }
     }
 
-    std::map<std::string, NameNode*>::iterator i = node->m_nameMap.find(name);
+    auto i = node->m_nameMap.find(name);
     if (i == node->m_nameMap.end())
     {
         NS_LOG_LOGIC("Name does not exist in name map");
@@ -741,7 +740,7 @@
 {
     NS_LOG_FUNCTION(this << object);
 
-    std::map<Ptr<Object>, NameNode*>::iterator i = m_objectMap.find(object);
+    auto i = m_objectMap.find(object);
     if (i == m_objectMap.end())
     {
         NS_LOG_LOGIC("Object does not exist in object map, returning NameNode 0");
@@ -759,7 +758,7 @@
 {
     NS_LOG_FUNCTION(this << node << name);
 
-    std::map<std::string, NameNode*>::iterator i = node->m_nameMap.find(name);
+    auto i = node->m_nameMap.find(name);
     if (i == node->m_nameMap.end())
     {
         NS_LOG_LOGIC("Name does not exist in name map");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/nstime.h ns-3.40/src/core/model/nstime.h
--- ns-3.39/src/core/model/nstime.h	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/nstime.h	2023-09-27 13:30:37.630839000 -0700
@@ -580,7 +580,7 @@
 
         NS_ASSERT_MSG(info->isValid, "Attempted a conversion to an unavailable unit.");
 
-        int64x64_t retval = int64x64_t(m_data);
+        int64x64_t retval(m_data);
         if (info->toMul)
         {
             retval *= info->timeTo;
@@ -792,21 +792,15 @@
     friend Time Rem(const Time& lhs, const Time& rhs);
 
     template <class T>
-    friend typename std::enable_if<std::is_integral<T>::value, Time>::type operator*(
-        const Time& lhs,
-        T rhs);
+    friend std::enable_if_t<std::is_integral_v<T>, Time> operator*(const Time& lhs, T rhs);
 
     // Reversed arg version (forwards to `rhs * lhs`)
     // Accepts both integers and decimal types
     template <class T>
-    friend typename std::enable_if<std::is_arithmetic<T>::value, Time>::type operator*(
-        T lhs,
-        const Time& rhs);
+    friend std::enable_if_t<std::is_arithmetic_v<T>, Time> operator*(T lhs, const Time& rhs);
 
     template <class T>
-    friend typename std::enable_if<std::is_integral<T>::value, Time>::type operator/(
-        const Time& lhs,
-        T rhs);
+    friend std::enable_if_t<std::is_integral_v<T>, Time> operator/(const Time& lhs, T rhs);
 
     friend Time Abs(const Time& time);
     friend Time Max(const Time& timeA, const Time& timeB);
@@ -816,13 +810,9 @@
 
     // Leave undocumented
     template <class T>
-    friend typename std::enable_if<std::is_floating_point<T>::value, Time>::type operator*(
-        const Time& lhs,
-        T rhs);
+    friend std::enable_if_t<std::is_floating_point_v<T>, Time> operator*(const Time& lhs, T rhs);
     template <class T>
-    friend typename std::enable_if<std::is_floating_point<T>::value, Time>::type operator/(
-        const Time& lhs,
-        T rhs);
+    friend std::enable_if_t<std::is_floating_point_v<T>, Time> operator/(const Time& lhs, T rhs);
 
     /**
      * \name Compound assignment operators
@@ -1017,18 +1007,17 @@
  * \returns A new Time instance containing the scaled value
  */
 template <class T>
-typename std::enable_if<std::is_integral<T>::value, Time>::type
+std::enable_if_t<std::is_integral_v<T>, Time>
 operator*(const Time& lhs, T rhs)
 {
-    static_assert(!std::is_same<T, bool>::value,
-                  "Multiplying a Time by a boolean is not supported");
+    static_assert(!std::is_same_v<T, bool>, "Multiplying a Time by a boolean is not supported");
 
     return Time(lhs.m_data * rhs);
 }
 
 // Leave undocumented
 template <class T>
-typename std::enable_if<std::is_floating_point<T>::value, Time>::type
+std::enable_if_t<std::is_floating_point_v<T>, Time>
 operator*(const Time& lhs, T rhs)
 {
     return lhs * int64x64_t(rhs);
@@ -1048,7 +1037,7 @@
  * \returns A new Time instance containing the scaled value
  */
 template <class T>
-typename std::enable_if<std::is_arithmetic<T>::value, Time>::type
+std::enable_if_t<std::is_arithmetic_v<T>, Time>
 operator*(T lhs, const Time& rhs)
 {
     return rhs * lhs;
@@ -1104,17 +1093,17 @@
  * \returns A new Time instance containing the scaled value
  */
 template <class T>
-typename std::enable_if<std::is_integral<T>::value, Time>::type
+std::enable_if_t<std::is_integral_v<T>, Time>
 operator/(const Time& lhs, T rhs)
 {
-    static_assert(!std::is_same<T, bool>::value, "Dividing a Time by a boolean is not supported");
+    static_assert(!std::is_same_v<T, bool>, "Dividing a Time by a boolean is not supported");
 
     return Time(lhs.m_data / rhs);
 }
 
 // Leave undocumented
 template <class T>
-typename std::enable_if<std::is_floating_point<T>::value, Time>::type
+std::enable_if_t<std::is_floating_point_v<T>, Time>
 operator/(const Time& lhs, T rhs)
 {
     return lhs / int64x64_t(rhs);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/object-base.cc ns-3.40/src/core/model/object-base.cc
--- ns-3.39/src/core/model/object-base.cc	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/object-base.cc	2023-09-27 13:30:37.630839000 -0700
@@ -35,6 +35,10 @@
 
 namespace ns3
 {
+// Explicit instantiation declaration
+template Callback<ObjectBase*> MakeCallback<ObjectBase*>(ObjectBase* (*)());
+template Callback<ObjectBase*>::Callback();
+template class CallbackImpl<ObjectBase*>;
 
 NS_LOG_COMPONENT_DEFINE("ObjectBase");
 
@@ -257,7 +261,7 @@
     {
         return;
     }
-    StringValue* str = dynamic_cast<StringValue*>(&value);
+    auto str = dynamic_cast<StringValue*>(&value);
     if (str == nullptr)
     {
         NS_FATAL_ERROR("Attribute name=" << name << " tid=" << tid.GetName()
@@ -292,7 +296,7 @@
     {
         return true;
     }
-    StringValue* str = dynamic_cast<StringValue*>(&value);
+    auto str = dynamic_cast<StringValue*>(&value);
     if (str == nullptr)
     {
         return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/object-base.h ns-3.40/src/core/model/object-base.h
--- ns-3.39/src/core/model/object-base.h	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/object-base.h	2023-09-27 13:30:37.630839000 -0700
@@ -335,6 +335,15 @@
                const AttributeValue& value);
 };
 
+// The following explicit template instantiation declarations prevent all the translation
+// units including this header file to implicitly instantiate the callbacks class and
+// function templates having ObjectBase as template type parameter that are required to be
+// instantiated more often (accorging to the ClangBuildAnalyzer tool).
+// These classes and functions are explicitly instantiated in object-base.cc
+extern template Callback<ObjectBase*> MakeCallback<ObjectBase*>(ObjectBase* (*)());
+extern template Callback<ObjectBase*>::Callback();
+extern template class CallbackImpl<ObjectBase*>;
+
 } // namespace ns3
 
 #endif /* OBJECT_BASE_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/object.cc ns-3.40/src/core/model/object.cc
--- ns-3.39/src/core/model/object.cc	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/object.cc	2023-09-27 13:30:37.630839000 -0700
@@ -267,8 +267,7 @@
     Object* other = PeekPointer(o);
     // first create the new aggregate buffer.
     uint32_t total = m_aggregates->n + other->m_aggregates->n;
-    Aggregates* aggregates =
-        (Aggregates*)std::malloc(sizeof(Aggregates) + (total - 1) * sizeof(Object*));
+    auto aggregates = (Aggregates*)std::malloc(sizeof(Aggregates) + (total - 1) * sizeof(Object*));
     aggregates->n = total;
 
     // copy our buffer to the new buffer
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/object-factory.cc ns-3.40/src/core/model/object-factory.cc
--- ns-3.39/src/core/model/object-factory.cc	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/object-factory.cc	2023-09-27 13:30:37.630839000 -0700
@@ -95,7 +95,7 @@
     NS_LOG_FUNCTION(this);
     Callback<ObjectBase*> cb = m_tid.GetConstructor();
     ObjectBase* base = cb();
-    Object* derived = dynamic_cast<Object*>(base);
+    auto derived = dynamic_cast<Object*>(base);
     NS_ASSERT(derived != nullptr);
     derived->SetTypeId(m_tid);
     derived->Construct(m_parameters);
@@ -108,9 +108,7 @@
 {
     os << factory.m_tid.GetName() << "[";
     bool first = true;
-    for (AttributeConstructionList::CIterator i = factory.m_parameters.Begin();
-         i != factory.m_parameters.End();
-         ++i)
+    for (auto i = factory.m_parameters.Begin(); i != factory.m_parameters.End(); ++i)
     {
         os << i->name << "=" << i->value->SerializeToString(i->checker);
         if (first)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/object-map.h ns-3.40/src/core/model/object-map.h
--- ns-3.39/src/core/model/object-map.h	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/object-map.h	2023-09-27 13:30:37.630839000 -0700
@@ -93,10 +93,10 @@
                           std::size_t* index) const override
         {
             const T* obj = static_cast<const T*>(object);
-            typename U::const_iterator begin = (obj->*m_memberVector).begin();
-            typename U::const_iterator end = (obj->*m_memberVector).end();
+            auto begin = (obj->*m_memberVector).begin();
+            auto end = (obj->*m_memberVector).end();
             uint32_t k = 0;
-            for (typename U::const_iterator j = begin; j != end; j++, k++)
+            for (auto j = begin; j != end; j++, k++)
             {
                 if (k == i)
                 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/object-ptr-container.cc ns-3.40/src/core/model/object-ptr-container.cc
--- ns-3.39/src/core/model/object-ptr-container.cc	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/object-ptr-container.cc	2023-09-27 13:30:37.630839000 -0700
@@ -61,7 +61,7 @@
 ObjectPtrContainerValue::Get(std::size_t i) const
 {
     NS_LOG_FUNCTION(this << i);
-    Iterator it = m_objects.find(i);
+    auto it = m_objects.find(i);
     Ptr<Object> value = nullptr;
     if (it != m_objects.end())
     {
@@ -115,7 +115,7 @@
 ObjectPtrContainerAccessor::Get(const ObjectBase* object, AttributeValue& value) const
 {
     NS_LOG_FUNCTION(this << object << &value);
-    ObjectPtrContainerValue* v = dynamic_cast<ObjectPtrContainerValue*>(&value);
+    auto v = dynamic_cast<ObjectPtrContainerValue*>(&value);
     if (v == nullptr)
     {
         return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/object-ptr-container.h ns-3.40/src/core/model/object-ptr-container.h
--- ns-3.39/src/core/model/object-ptr-container.h	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/object-ptr-container.h	2023-09-27 13:30:37.630839000 -0700
@@ -208,8 +208,8 @@
 
     bool Copy(const AttributeValue& source, AttributeValue& destination) const override
     {
-        const ObjectPtrContainerValue* src = dynamic_cast<const ObjectPtrContainerValue*>(&source);
-        ObjectPtrContainerValue* dst = dynamic_cast<ObjectPtrContainerValue*>(&destination);
+        const auto src = dynamic_cast<const ObjectPtrContainerValue*>(&source);
+        auto dst = dynamic_cast<ObjectPtrContainerValue*>(&destination);
         if (src == nullptr || dst == nullptr)
         {
             return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/object-vector.h ns-3.40/src/core/model/object-vector.h
--- ns-3.39/src/core/model/object-vector.h	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/object-vector.h	2023-09-27 13:30:37.630839000 -0700
@@ -93,10 +93,10 @@
                           std::size_t* index) const override
         {
             const T* obj = static_cast<const T*>(object);
-            typename U::const_iterator begin = (obj->*m_memberVector).begin();
-            typename U::const_iterator end = (obj->*m_memberVector).end();
+            auto begin = (obj->*m_memberVector).begin();
+            auto end = (obj->*m_memberVector).end();
             std::size_t k = 0;
-            for (typename U::const_iterator j = begin; j != end; j++, k++)
+            for (auto j = begin; j != end; j++, k++)
             {
                 if (k == i)
                 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/pair.h ns-3.40/src/core/model/pair.h
--- ns-3.39/src/core/model/pair.h	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/pair.h	2023-09-27 13:30:37.630839000 -0700
@@ -20,8 +20,8 @@
 #ifndef PAIR_H
 #define PAIR_H
 
-#include <ns3/attribute-helper.h>
-#include <ns3/string.h>
+#include "attribute-helper.h"
+#include "string.h"
 
 #include <sstream>
 #include <type_traits>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/pointer.h ns-3.40/src/core/model/pointer.h
--- ns-3.39/src/core/model/pointer.h	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/pointer.h	2023-09-27 13:30:37.630839000 -0700
@@ -129,7 +129,7 @@
 {
     bool Check(const AttributeValue& val) const override
     {
-        const PointerValue* value = dynamic_cast<const PointerValue*>(&val);
+        const auto value = dynamic_cast<const PointerValue*>(&val);
         if (value == nullptr)
         {
             return false;
@@ -166,8 +166,8 @@
 
     bool Copy(const AttributeValue& source, AttributeValue& destination) const override
     {
-        const PointerValue* src = dynamic_cast<const PointerValue*>(&source);
-        PointerValue* dst = dynamic_cast<PointerValue*>(&destination);
+        const auto src = dynamic_cast<const PointerValue*>(&source);
+        auto dst = dynamic_cast<PointerValue*>(&destination);
         if (src == nullptr || dst == nullptr)
         {
             return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/priority-queue-scheduler.h ns-3.40/src/core/model/priority-queue-scheduler.h
--- ns-3.39/src/core/model/priority-queue-scheduler.h	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/priority-queue-scheduler.h	2023-09-27 13:30:37.630839000 -0700
@@ -90,7 +90,7 @@
      */
     class EventPriorityQueue : public std::priority_queue<Scheduler::Event,
                                                           std::vector<Scheduler::Event>,
-                                                          std::greater<Scheduler::Event>>
+                                                          std::greater<>>
     {
       public:
         /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/ptr.h ns-3.40/src/core/model/ptr.h
--- ns-3.39/src/core/model/ptr.h	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/ptr.h	2023-09-27 13:30:37.630839000 -0700
@@ -332,9 +332,7 @@
  * \copydoc operator==(Ptr<T1>const&,Ptr<T2>const&)
  */
 template <typename T1, typename T2>
-typename std::enable_if<std::is_same<T2, std::nullptr_t>::value, bool>::type operator==(
-    const Ptr<T1>& lhs,
-    T2 rhs);
+std::enable_if_t<std::is_same_v<T2, std::nullptr_t>, bool> operator==(const Ptr<T1>& lhs, T2 rhs);
 
 /**
  * \ingroup ptr
@@ -373,9 +371,7 @@
  * \copydoc operator==(Ptr<T1>const&,Ptr<T2>const&)
  */
 template <typename T1, typename T2>
-typename std::enable_if<std::is_same<T2, std::nullptr_t>::value, bool>::type operator!=(
-    const Ptr<T1>& lhs,
-    T2 rhs);
+std::enable_if_t<std::is_same_v<T2, std::nullptr_t>, bool> operator!=(const Ptr<T1>& lhs, T2 rhs);
 
 /**
  * \ingroup ptr
@@ -549,14 +545,14 @@
 }
 
 template <typename T1, typename T2>
-typename std::enable_if<std::is_same<T2, std::nullptr_t>::value, bool>::type
+std::enable_if_t<std::is_same_v<T2, std::nullptr_t>, bool>
 operator==(const Ptr<T1>& lhs, T2 rhs)
 {
     return PeekPointer(lhs) == nullptr;
 }
 
 template <typename T1, typename T2>
-typename std::enable_if<std::is_same<T2, std::nullptr_t>::value, bool>::type
+std::enable_if_t<std::is_same_v<T2, std::nullptr_t>, bool>
 operator!=(const Ptr<T1>& lhs, T2 rhs)
 {
     return PeekPointer(lhs) != nullptr;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/random-variable-stream.cc ns-3.40/src/core/model/random-variable-stream.cc
--- ns-3.39/src/core/model/random-variable-stream.cc	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/random-variable-stream.cc	2023-09-27 13:30:37.630839000 -0700
@@ -421,7 +421,7 @@
 ExponentialRandomVariable::GetValue(double mean, double bound)
 {
     NS_LOG_FUNCTION(this << mean << bound);
-    while (1)
+    while (true)
     {
         // Get a uniform random variable in [0,1].
         double v = Peek()->RandU01();
@@ -520,7 +520,7 @@
     // Calculate the scale parameter.
     NS_LOG_FUNCTION(this << scale << shape << bound);
 
-    while (1)
+    while (true)
     {
         // Get a uniform random variable in [0,1].
         double v = Peek()->RandU01();
@@ -617,7 +617,7 @@
 {
     NS_LOG_FUNCTION(this << scale << shape << bound);
     double exponent = 1.0 / shape;
-    while (1)
+    while (true)
     {
         // Get a uniform random variable in [0,1].
         double v = Peek()->RandU01();
@@ -724,7 +724,7 @@
             return x2;
         }
     }
-    while (1)
+    while (true)
     { // See Simulation Modeling and Analysis p. 466 (Averill Law)
         // for algorithm; basically a Box-Muller transform:
         // http://en.wikipedia.org/wiki/Box-Muller_transform
@@ -992,7 +992,7 @@
     double d = alpha - 1.0 / 3.0;
     double c = (1.0 / 3.0) / std::sqrt(d);
 
-    while (1)
+    while (true)
     {
         do
         {
@@ -1045,7 +1045,7 @@
             return x2;
         }
     }
-    while (1)
+    while (true)
     { // See Simulation Modeling and Analysis p. 466 (Averill Law)
         // for algorithm; basically a Box-Muller transform:
         // http://en.wikipedia.org/wiki/Box-Muller_transform
@@ -1173,7 +1173,7 @@
 ErlangRandomVariable::GetExponentialValue(double mean, double bound)
 {
     NS_LOG_FUNCTION(this << mean << bound);
-    while (1)
+    while (true)
     {
         // Get a uniform random variable in [0,1].
         double v = Peek()->RandU01();
@@ -1534,28 +1534,6 @@
 
 NS_OBJECT_ENSURE_REGISTERED(EmpiricalRandomVariable);
 
-// ValueCDF methods
-EmpiricalRandomVariable::ValueCDF::ValueCDF()
-    : value(0.0),
-      cdf(0.0)
-{
-    NS_LOG_FUNCTION(this);
-}
-
-EmpiricalRandomVariable::ValueCDF::ValueCDF(double v, double c)
-    : value(v),
-      cdf(c)
-{
-    NS_LOG_FUNCTION(this << v << c);
-    NS_ASSERT(c >= 0.0 && c <= 1.0);
-}
-
-bool
-operator<(EmpiricalRandomVariable::ValueCDF a, EmpiricalRandomVariable::ValueCDF b)
-{
-    return a.cdf < b.cdf;
-}
-
 TypeId
 EmpiricalRandomVariable::GetTypeId()
 {
@@ -1608,14 +1586,14 @@
     value = r;
     bool valid = false;
     // check extrema
-    if (r <= m_emp.front().cdf)
+    if (r <= m_empCdf.begin()->first)
     {
-        value = m_emp.front().value; // Less than first
+        value = m_empCdf.begin()->second; // Less than first
         valid = true;
     }
-    else if (r >= m_emp.back().cdf)
+    else if (r >= m_empCdf.rbegin()->first)
     {
-        value = m_emp.back().value; // Greater than last
+        value = m_empCdf.rbegin()->second; // Greater than last
         valid = true;
     }
     return valid;
@@ -1649,10 +1627,10 @@
 {
     NS_LOG_FUNCTION(this << r);
 
-    ValueCDF selector(0, r);
-    auto bound = std::upper_bound(m_emp.begin(), m_emp.end(), selector);
+    // Find first CDF that is greater than r
+    auto bound = m_empCdf.upper_bound(r);
 
-    return bound->value;
+    return bound->second;
 }
 
 double
@@ -1680,19 +1658,19 @@
     // This code based (loosely) on code by Bruce Mah (Thanks Bruce!)
 
     // search
-    ValueCDF selector(0, r);
-    auto upper = std::upper_bound(m_emp.begin(), m_emp.end(), selector);
+    auto upper = m_empCdf.upper_bound(r);
     auto lower = std::prev(upper, 1);
-    if (upper == m_emp.begin())
+
+    if (upper == m_empCdf.begin())
     {
         lower = upper;
     }
 
     // Interpolate random value in range [v1..v2) based on [c1 .. r .. c2)
-    double c1 = lower->cdf;
-    double c2 = upper->cdf;
-    double v1 = lower->value;
-    double v2 = upper->value;
+    double c1 = lower->first;
+    double c2 = upper->first;
+    double v1 = lower->second;
+    double v2 = upper->second;
 
     double value = (v1 + ((v2 - v1) / (c2 - c1)) * (r - c1));
     return value;
@@ -1701,36 +1679,62 @@
 void
 EmpiricalRandomVariable::CDF(double v, double c)
 {
-    // Add a new empirical datapoint to the empirical cdf
-    // NOTE.   These MUST be inserted in non-decreasing order
     NS_LOG_FUNCTION(this << v << c);
-    m_emp.emplace_back(v, c);
+
+    auto vPrevious = m_empCdf.find(c);
+
+    if (vPrevious != m_empCdf.end())
+    {
+        NS_LOG_WARN("Empirical CDF already has a value " << vPrevious->second << " for CDF " << c
+                                                         << ". Overwriting it with value " << v
+                                                         << ".");
+    }
+
+    m_empCdf[c] = v;
 }
 
 void
 EmpiricalRandomVariable::Validate()
 {
     NS_LOG_FUNCTION(this);
-    if (m_emp.empty())
+
+    if (m_empCdf.empty())
     {
         NS_FATAL_ERROR("CDF is not initialized");
     }
-    ValueCDF prior = m_emp[0];
-    for (auto current : m_emp)
+
+    double vPrev = m_empCdf.begin()->second;
+
+    // Check if values are non-decreasing
+    for (const auto& cdfPair : m_empCdf)
     {
-        if (current.value < prior.value || current.cdf < prior.cdf)
-        { // Error
-            std::cerr << "Empirical Dist error,"
-                      << " current value " << current.value << " prior value " << prior.value
-                      << " current cdf " << current.cdf << " prior cdf " << prior.cdf << std::endl;
-            NS_FATAL_ERROR("Empirical Dist error");
+        const auto& vCurr = cdfPair.second;
+
+        if (vCurr < vPrev)
+        {
+            NS_FATAL_ERROR("Empirical distribution has decreasing CDF values. Current CDF: "
+                           << vCurr << ", prior CDF: " << vPrev);
         }
-        prior = current;
+
+        vPrev = vCurr;
     }
-    if (prior.cdf != 1.0)
+
+    // Bounds check on CDF endpoints
+    auto firstCdfPair = m_empCdf.begin();
+    auto lastCdfPair = m_empCdf.rbegin();
+
+    if (firstCdfPair->first < 0.0)
     {
-        NS_FATAL_ERROR("CDF does not cover the whole distribution");
+        NS_FATAL_ERROR("Empirical distribution has invalid first CDF value. CDF: "
+                       << firstCdfPair->first << ", Value: " << firstCdfPair->second);
     }
+
+    if (lastCdfPair->first > 1.0)
+    {
+        NS_FATAL_ERROR("Empirical distribution has invalid last CDF value. CDF: "
+                       << lastCdfPair->first << ", Value: " << lastCdfPair->second);
+    }
+
     m_validated = true;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/random-variable-stream.h ns-3.40/src/core/model/random-variable-stream.h
--- ns-3.39/src/core/model/random-variable-stream.h	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/random-variable-stream.h	2023-09-27 13:30:37.630839000 -0700
@@ -29,6 +29,7 @@
 #include "object.h"
 #include "type-id.h"
 
+#include <map>
 #include <stdint.h>
 
 /**
@@ -1983,7 +1984,6 @@
 
     /**
      * \brief Specifies a point in the empirical distribution
-     * \note These *MUST* be inserted in ascending order of \p c
      *
      * \param [in] v The function value for this point
      * \param [in] c Probability that the function is less than or equal to \p v
@@ -2018,26 +2018,6 @@
     bool SetInterpolate(bool interpolate);
 
   private:
-    /** \brief Helper to hold one point of the CDF. */
-    class ValueCDF
-    {
-      public:
-        /** \brief Constructor. */
-        ValueCDF();
-        /**
-         * \brief Construct from values.
-         *
-         * \param [in] v The argument value.
-         * \param [in] c The CDF at the argument value \pname{v}
-         */
-        ValueCDF(double v, double c);
-
-        /** The argument value. */
-        double value;
-        /** The CDF at \pname{value}  */
-        double cdf;
-    }; // class ValueCDF
-
     /**
      * \brief Check that the CDF is valid.
      *
@@ -2078,18 +2058,14 @@
      */
     double DoInterpolate(double r);
 
-    /**
-     * \brief Comparison operator, for use by std::upper_bound
-     * \param a [in] the first value
-     * \param b [in] the second value
-     * \returns \c true if \c a.cdf < \c b.cdf
-     */
-    friend bool operator<(ValueCDF a, ValueCDF b);
-
     /** \c true once the CDF has been validated. */
     bool m_validated;
-    /** The vector of CDF points. */
-    std::vector<ValueCDF> m_emp;
+    /**
+     * The map of CDF points (x, F(x)).
+     * The CDF points are stored in the std::map in reverse order, as follows:
+     * Key: CDF F(x) [0, 1] | Value: domain value (x) [-inf, inf].
+     */
+    std::map<double, double> m_empCdf;
     /**
      * If \c true GetValue will interpolate,
      * otherwise treat CDF as normal histogram.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/realtime-simulator-impl.cc ns-3.40/src/core/model/realtime-simulator-impl.cc
--- ns-3.39/src/core/model/realtime-simulator-impl.cc	2023-07-05 14:23:47.761427200 -0700
+++ ns-3.40/src/core/model/realtime-simulator-impl.cc	2023-09-27 13:30:37.630839000 -0700
@@ -704,7 +704,7 @@
     if (id.GetUid() == EventId::UID::DESTROY)
     {
         // destroy events.
-        for (DestroyEvents::iterator i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
+        for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
         {
             if (*i == id)
             {
@@ -754,8 +754,7 @@
             return true;
         }
         // destroy events.
-        for (DestroyEvents::const_iterator i = m_destroyEvents.begin(); i != m_destroyEvents.end();
-             i++)
+        for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
         {
             if (*i == id)
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/simulator.h ns-3.40/src/core/model/simulator.h
--- ns-3.39/src/core/model/simulator.h	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/simulator.h	2023-09-27 13:30:37.630839000 -0700
@@ -228,12 +228,10 @@
      * @param [in] args Arguments to pass to MakeEvent.
      * @returns The id for the scheduled event.
      */
-    template <
-        typename FUNC,
-        typename std::enable_if<!std::is_convertible<FUNC, Ptr<EventImpl>>::value, int>::type = 0,
-        typename std::enable_if<!std::is_function<typename std::remove_pointer<FUNC>::type>::value,
-                                int>::type = 0,
-        typename... Ts>
+    template <typename FUNC,
+              std::enable_if_t<!std::is_convertible_v<FUNC, Ptr<EventImpl>>, int> = 0,
+              std::enable_if_t<!std::is_function_v<std::remove_pointer_t<FUNC>>, int> = 0,
+              typename... Ts>
     static EventId Schedule(const Time& delay, FUNC f, Ts&&... args);
 
     /**
@@ -276,12 +274,10 @@
      * @param [in] f The function to invoke.
      * @param [in] args Arguments to pass to MakeEvent.
      */
-    template <
-        typename FUNC,
-        typename std::enable_if<!std::is_convertible<FUNC, Ptr<EventImpl>>::value, int>::type = 0,
-        typename std::enable_if<!std::is_function<typename std::remove_pointer<FUNC>::type>::value,
-                                int>::type = 0,
-        typename... Ts>
+    template <typename FUNC,
+              std::enable_if_t<!std::is_convertible_v<FUNC, Ptr<EventImpl>>, int> = 0,
+              std::enable_if_t<!std::is_function_v<std::remove_pointer_t<FUNC>>, int> = 0,
+              typename... Ts>
     static void ScheduleWithContext(uint32_t context, const Time& delay, FUNC f, Ts&&... args);
 
     /**
@@ -321,12 +317,10 @@
      * @param [in] args Arguments to pass to the invoked function.
      * @return The EventId of the scheduled event.
      */
-    template <
-        typename FUNC,
-        typename std::enable_if<!std::is_convertible<FUNC, Ptr<EventImpl>>::value, int>::type = 0,
-        typename std::enable_if<!std::is_function<typename std::remove_pointer<FUNC>::type>::value,
-                                int>::type = 0,
-        typename... Ts>
+    template <typename FUNC,
+              std::enable_if_t<!std::is_convertible_v<FUNC, Ptr<EventImpl>>, int> = 0,
+              std::enable_if_t<!std::is_function_v<std::remove_pointer_t<FUNC>>, int> = 0,
+              typename... Ts>
     static EventId ScheduleNow(FUNC f, Ts&&... args);
 
     /**
@@ -365,12 +359,10 @@
      * @param [in] args Arguments to pass to MakeEvent.
      * @return The EventId of the scheduled event.
      */
-    template <
-        typename FUNC,
-        typename std::enable_if<!std::is_convertible<FUNC, Ptr<EventImpl>>::value, int>::type = 0,
-        typename std::enable_if<!std::is_function<typename std::remove_pointer<FUNC>::type>::value,
-                                int>::type = 0,
-        typename... Ts>
+    template <typename FUNC,
+              std::enable_if_t<!std::is_convertible_v<FUNC, Ptr<EventImpl>>, int> = 0,
+              std::enable_if_t<!std::is_function_v<std::remove_pointer_t<FUNC>>, int> = 0,
+              typename... Ts>
     static EventId ScheduleDestroy(FUNC f, Ts&&... args);
 
     /**
@@ -558,12 +550,10 @@
 // it treats the in-class declaration as different from the
 // out of class definition, so makes two entries in the member list.  Ugh
 
-template <
-    typename FUNC,
-    typename std::enable_if<!std::is_convertible<FUNC, Ptr<EventImpl>>::value, int>::type,
-    typename std::enable_if<!std::is_function<typename std::remove_pointer<FUNC>::type>::value,
-                            int>::type,
-    typename... Ts>
+template <typename FUNC,
+          std::enable_if_t<!std::is_convertible_v<FUNC, Ptr<EventImpl>>, int>,
+          std::enable_if_t<!std::is_function_v<std::remove_pointer_t<FUNC>>, int>,
+          typename... Ts>
 EventId
 Simulator::Schedule(const Time& delay, FUNC f, Ts&&... args)
 {
@@ -577,12 +567,10 @@
     return DoSchedule(delay, MakeEvent(f, std::forward<Ts>(args)...));
 }
 
-template <
-    typename FUNC,
-    typename std::enable_if<!std::is_convertible<FUNC, Ptr<EventImpl>>::value, int>::type,
-    typename std::enable_if<!std::is_function<typename std::remove_pointer<FUNC>::type>::value,
-                            int>::type,
-    typename... Ts>
+template <typename FUNC,
+          std::enable_if_t<!std::is_convertible_v<FUNC, Ptr<EventImpl>>, int>,
+          std::enable_if_t<!std::is_function_v<std::remove_pointer_t<FUNC>>, int>,
+          typename... Ts>
 void
 Simulator::ScheduleWithContext(uint32_t context, const Time& delay, FUNC f, Ts&&... args)
 {
@@ -596,12 +584,10 @@
     return ScheduleWithContext(context, delay, MakeEvent(f, std::forward<Ts>(args)...));
 }
 
-template <
-    typename FUNC,
-    typename std::enable_if<!std::is_convertible<FUNC, Ptr<EventImpl>>::value, int>::type,
-    typename std::enable_if<!std::is_function<typename std::remove_pointer<FUNC>::type>::value,
-                            int>::type,
-    typename... Ts>
+template <typename FUNC,
+          std::enable_if_t<!std::is_convertible_v<FUNC, Ptr<EventImpl>>, int>,
+          std::enable_if_t<!std::is_function_v<std::remove_pointer_t<FUNC>>, int>,
+          typename... Ts>
 EventId
 Simulator::ScheduleNow(FUNC f, Ts&&... args)
 {
@@ -615,12 +601,10 @@
     return DoScheduleNow(MakeEvent(f, std::forward<Ts>(args)...));
 }
 
-template <
-    typename FUNC,
-    typename std::enable_if<!std::is_convertible<FUNC, Ptr<EventImpl>>::value, int>::type,
-    typename std::enable_if<!std::is_function<typename std::remove_pointer<FUNC>::type>::value,
-                            int>::type,
-    typename... Ts>
+template <typename FUNC,
+          std::enable_if_t<!std::is_convertible_v<FUNC, Ptr<EventImpl>>, int>,
+          std::enable_if_t<!std::is_function_v<std::remove_pointer_t<FUNC>>, int>,
+          typename... Ts>
 EventId
 Simulator::ScheduleDestroy(FUNC f, Ts&&... args)
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/system-path.cc ns-3.40/src/core/model/system-path.cc
--- ns-3.39/src/core/model/system-path.cc	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/system-path.cc	2023-09-27 13:30:37.630839000 -0700
@@ -141,7 +141,7 @@
 {
     NS_LOG_FUNCTION(path);
     std::list<std::string> elements = Split(path);
-    std::list<std::string>::const_iterator last = elements.end();
+    auto last = elements.end();
     last--;
     return Join(elements.begin(), last);
 }
@@ -268,7 +268,7 @@
 {
     NS_LOG_FUNCTION(*begin << *end);
     std::string retval = "";
-    for (std::list<std::string>::const_iterator i = begin; i != end; i++)
+    for (auto i = begin; i != end; i++)
     {
         if ((*i).empty())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/test.cc ns-3.40/src/core/model/test.cc
--- ns-3.39/src/core/model/test.cc	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/test.cc	2023-09-27 13:30:37.630839000 -0700
@@ -290,7 +290,7 @@
     NS_ASSERT(m_runner == nullptr);
     m_parent = nullptr;
     delete m_result;
-    for (std::vector<TestCase*>::const_iterator i = m_children.begin(); i != m_children.end(); ++i)
+    for (auto i = m_children.begin(); i != m_children.end(); ++i)
     {
         delete *i;
     }
@@ -353,7 +353,7 @@
     m_runner = runner;
     DoSetup();
     m_result->clock.Start();
-    for (std::vector<TestCase*>::const_iterator i = m_children.begin(); i != m_children.end(); ++i)
+    for (auto i = m_children.begin(); i != m_children.end(); ++i)
     {
         TestCase* test = *i;
         test->Run(runner);
@@ -571,7 +571,7 @@
     //
 
     std::list<std::string> files = SystemPath::ReadFiles(path);
-    for (std::list<std::string>::const_iterator i = files.begin(); i != files.end(); ++i)
+    for (auto i = files.begin(); i != files.end(); ++i)
     {
         if (*i == "VERSION")
         {
@@ -629,7 +629,7 @@
     {
         char character = xml[i];
 
-        specials_map::const_iterator it = specials.find(character);
+        auto it = specials.find(character);
 
         if (it == specials.end())
         {
@@ -802,9 +802,9 @@
     label[TestSuite::EXAMPLE] = "example      ";
     label[TestSuite::PERFORMANCE] = "performance  ";
 
-    for (std::list<TestCase*>::const_iterator i = begin; i != end; ++i)
+    for (auto i = begin; i != end; ++i)
     {
-        TestSuite* test = dynamic_cast<TestSuite*>(*i);
+        auto test = dynamic_cast<TestSuite*>(*i);
         NS_ASSERT(test != nullptr);
         if (printTestType)
         {
@@ -852,8 +852,7 @@
         }
 
         // Remove any test cases that should be skipped.
-        std::vector<TestCase*>::iterator j;
-        for (j = test->m_children.begin(); j != test->m_children.end();)
+        for (auto j = test->m_children.begin(); j != test->m_children.end();)
         {
             TestCase* testCase = *j;
 
@@ -1090,7 +1089,7 @@
         return 1;
     }
 
-    for (std::list<TestCase*>::const_iterator i = tests.begin(); i != tests.end(); ++i)
+    for (auto i = tests.begin(); i != tests.end(); ++i)
     {
         TestCase* test = *i;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/time.cc ns-3.40/src/core/model/time.cc
--- ns-3.39/src/core/model/time.cc	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/time.cc	2023-09-27 13:30:37.630839000 -0700
@@ -255,7 +255,7 @@
             info->isValid = false;
             continue;
         }
-        int64_t factor = static_cast<int64_t>(std::pow(10, std::fabs(shift)) * quotient);
+        auto factor = static_cast<int64_t>(std::pow(10, std::fabs(shift)) * quotient);
         double realFactor = std::pow(10, (double)shift) * static_cast<double>(UNIT_COEFF[i]) /
                             UNIT_COEFF[(int)unit];
         NS_LOG_DEBUG("SetResolution factor " << factor << " real factor " << realFactor);
@@ -333,9 +333,7 @@
     // since earlier test was outside and might be stale.
     if (g_markingTimes)
     {
-        std::pair<MarkedTimes::iterator, bool> ret;
-
-        ret = g_markingTimes->insert(time);
+        auto ret = g_markingTimes->insert(time);
         NS_LOG_LOGIC("\t[" << g_markingTimes->size() << "] recording " << time);
 
         if (!ret.second)
@@ -385,7 +383,7 @@
                   "No MarkedTimes registry. "
                   "Time::SetResolution () called more than once?");
 
-    for (MarkedTimes::iterator it = g_markingTimes->begin(); it != g_markingTimes->end(); it++)
+    for (auto it = g_markingTimes->begin(); it != g_markingTimes->end(); it++)
     {
         Time* const tp = *it;
         if (!(tp->m_data == std::numeric_limits<int64_t>::min() ||
@@ -434,7 +432,7 @@
 
     if (unit == Time::AUTO)
     {
-        long double value = static_cast<long double>(timeU.m_time.GetTimeStep());
+        auto value = static_cast<long double>(timeU.m_time.GetTimeStep());
         // convert to finest scale (fs)
         value *= Scale(Time::GetResolution());
         // find the best unit
@@ -547,7 +545,7 @@
         bool Check(const AttributeValue& value) const override
         {
             NS_LOG_FUNCTION(&value);
-            const TimeValue* v = dynamic_cast<const TimeValue*>(&value);
+            const auto v = dynamic_cast<const TimeValue*>(&value);
             if (v == nullptr)
             {
                 return false;
@@ -585,8 +583,8 @@
         bool Copy(const AttributeValue& source, AttributeValue& destination) const override
         {
             NS_LOG_FUNCTION(&source << &destination);
-            const TimeValue* src = dynamic_cast<const TimeValue*>(&source);
-            TimeValue* dst = dynamic_cast<TimeValue*>(&destination);
+            const auto src = dynamic_cast<const TimeValue*>(&source);
+            auto dst = dynamic_cast<TimeValue*>(&destination);
             if (src == nullptr || dst == nullptr)
             {
                 return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/timer-impl.h ns-3.40/src/core/model/timer-impl.h
--- ns-3.39/src/core/model/timer-impl.h	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/timer-impl.h	2023-09-27 13:30:37.630839000 -0700
@@ -1085,7 +1085,7 @@
 TimerImpl::SetArgs(T1 a1)
 {
     typedef TimerImplOne<typename TimerTraits<T1>::ParameterType> TimerImplBase;
-    TimerImplBase* impl = dynamic_cast<TimerImplBase*>(this);
+    auto impl = dynamic_cast<TimerImplBase*>(this);
     if (impl == nullptr)
     {
         NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
@@ -1101,7 +1101,7 @@
     typedef TimerImplTwo<typename TimerTraits<T1>::ParameterType,
                          typename TimerTraits<T2>::ParameterType>
         TimerImplBase;
-    TimerImplBase* impl = dynamic_cast<TimerImplBase*>(this);
+    auto impl = dynamic_cast<TimerImplBase*>(this);
     if (impl == nullptr)
     {
         NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
@@ -1118,7 +1118,7 @@
                            typename TimerTraits<T2>::ParameterType,
                            typename TimerTraits<T3>::ParameterType>
         TimerImplBase;
-    TimerImplBase* impl = dynamic_cast<TimerImplBase*>(this);
+    auto impl = dynamic_cast<TimerImplBase*>(this);
     if (impl == nullptr)
     {
         NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
@@ -1136,7 +1136,7 @@
                           typename TimerTraits<T3>::ParameterType,
                           typename TimerTraits<T4>::ParameterType>
         TimerImplBase;
-    TimerImplBase* impl = dynamic_cast<TimerImplBase*>(this);
+    auto impl = dynamic_cast<TimerImplBase*>(this);
     if (impl == nullptr)
     {
         NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
@@ -1155,7 +1155,7 @@
                           typename TimerTraits<T4>::ParameterType,
                           typename TimerTraits<T5>::ParameterType>
         TimerImplBase;
-    TimerImplBase* impl = dynamic_cast<TimerImplBase*>(this);
+    auto impl = dynamic_cast<TimerImplBase*>(this);
     if (impl == nullptr)
     {
         NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
@@ -1175,7 +1175,7 @@
                          typename TimerTraits<T5>::ParameterType,
                          typename TimerTraits<T6>::ParameterType>
         TimerImplBase;
-    TimerImplBase* impl = dynamic_cast<TimerImplBase*>(this);
+    auto impl = dynamic_cast<TimerImplBase*>(this);
     if (impl == 0)
     {
         NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/traced-callback.h ns-3.40/src/core/model/traced-callback.h
--- ns-3.39/src/core/model/traced-callback.h	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/traced-callback.h	2023-09-27 13:30:37.634839000 -0700
@@ -162,8 +162,7 @@
 void
 TracedCallback<Ts...>::DisconnectWithoutContext(const CallbackBase& callback)
 {
-    for (typename CallbackList::iterator i = m_callbackList.begin(); i != m_callbackList.end();
-         /* empty */)
+    for (auto i = m_callbackList.begin(); i != m_callbackList.end(); /* empty */)
     {
         if ((*i).IsEqual(callback))
         {
@@ -193,9 +192,7 @@
 void
 TracedCallback<Ts...>::operator()(Ts... args) const
 {
-    for (typename CallbackList::const_iterator i = m_callbackList.begin();
-         i != m_callbackList.end();
-         i++)
+    for (auto i = m_callbackList.begin(); i != m_callbackList.end(); i++)
     {
         (*i)(args...);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/tuple.h ns-3.40/src/core/model/tuple.h
--- ns-3.39/src/core/model/tuple.h	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/tuple.h	2023-09-27 13:30:37.634839000 -0700
@@ -20,8 +20,8 @@
 #ifndef TUPLE_H
 #define TUPLE_H
 
-#include <ns3/attribute-helper.h>
-#include <ns3/string.h>
+#include "attribute-helper.h"
+#include "string.h"
 
 #include <algorithm>
 #include <sstream>
@@ -368,7 +368,7 @@
 
     bool Check(const AttributeValue& value) const override
     {
-        const TupleValue<Args...>* v = dynamic_cast<const TupleValue<Args...>*>(&value);
+        const auto v = dynamic_cast<const TupleValue<Args...>*>(&value);
         if (v == nullptr)
         {
             return false;
@@ -403,8 +403,8 @@
 
     bool Copy(const AttributeValue& source, AttributeValue& destination) const override
     {
-        const TupleValue<Args...>* src = dynamic_cast<const TupleValue<Args...>*>(&source);
-        TupleValue<Args...>* dst = dynamic_cast<TupleValue<Args...>*>(&destination);
+        const auto src = dynamic_cast<const TupleValue<Args...>*>(&source);
+        auto dst = dynamic_cast<TupleValue<Args...>*>(&destination);
         if (src == nullptr || dst == nullptr)
         {
             return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/type-id.cc ns-3.40/src/core/model/type-id.cc
--- ns-3.39/src/core/model/type-id.cc	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/type-id.cc	2023-09-27 13:30:37.634839000 -0700
@@ -443,7 +443,7 @@
     m_information.push_back(information);
     std::size_t tuid = m_information.size();
     NS_ASSERT(tuid <= 0xffff);
-    uint16_t uid = static_cast<uint16_t>(tuid);
+    auto uid = static_cast<uint16_t>(tuid);
 
     // Add to both maps:
     m_namemap.insert(std::make_pair(name, uid));
@@ -512,7 +512,7 @@
 {
     NS_LOG_FUNCTION(IID << name);
     uint16_t uid = 0;
-    namemap_t::const_iterator it = m_namemap.find(name);
+    auto it = m_namemap.find(name);
     if (it != m_namemap.end())
     {
         uid = it->second;
@@ -525,7 +525,7 @@
 IidManager::GetUid(TypeId::hash_t hash) const
 {
     NS_LOG_FUNCTION(IID << hash);
-    hashmap_t::const_iterator it = m_hashmap.find(hash);
+    auto it = m_hashmap.find(hash);
     uint16_t uid = 0;
     if (it != m_hashmap.end())
     {
@@ -627,10 +627,7 @@
     IidInformation* information = LookupInformation(uid);
     while (true)
     {
-        for (std::vector<TypeId::AttributeInformation>::const_iterator i =
-                 information->attributes.begin();
-             i != information->attributes.end();
-             ++i)
+        for (auto i = information->attributes.begin(); i != information->attributes.end(); ++i)
         {
             if (i->name == name)
             {
@@ -729,10 +726,7 @@
     IidInformation* information = LookupInformation(uid);
     while (true)
     {
-        for (std::vector<TypeId::TraceSourceInformation>::const_iterator i =
-                 information->traceSources.begin();
-             i != information->traceSources.end();
-             ++i)
+        for (auto i = information->traceSources.begin(); i != information->traceSources.end(); ++i)
         {
             if (i->name == name)
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/uinteger.cc ns-3.40/src/core/model/uinteger.cc
--- ns-3.39/src/core/model/uinteger.cc	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/uinteger.cc	2023-09-27 13:30:37.634839000 -0700
@@ -65,7 +65,7 @@
         bool Check(const AttributeValue& value) const override
         {
             NS_LOG_FUNCTION(&value);
-            const UintegerValue* v = dynamic_cast<const UintegerValue*>(&value);
+            const auto v = dynamic_cast<const UintegerValue*>(&value);
             if (v == nullptr)
             {
                 return false;
@@ -102,8 +102,8 @@
         bool Copy(const AttributeValue& source, AttributeValue& destination) const override
         {
             NS_LOG_FUNCTION(&source << &destination);
-            const UintegerValue* src = dynamic_cast<const UintegerValue*>(&source);
-            UintegerValue* dst = dynamic_cast<UintegerValue*>(&destination);
+            const auto src = dynamic_cast<const UintegerValue*>(&source);
+            auto dst = dynamic_cast<UintegerValue*>(&destination);
             if (src == nullptr || dst == nullptr)
             {
                 return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/unused.h ns-3.40/src/core/model/unused.h
--- ns-3.39/src/core/model/unused.h	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/unused.h	2023-09-27 13:30:37.634839000 -0700
@@ -20,7 +20,7 @@
 #ifndef UNUSED_H
 #define UNUSED_H
 
-#include "ns3/deprecated.h"
+#include "deprecated.h"
 
 /**
  * \file
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/val-array.h ns-3.40/src/core/model/val-array.h
--- ns-3.39/src/core/model/val-array.h	2023-07-05 14:23:47.765427000 -0700
+++ ns-3.40/src/core/model/val-array.h	2023-09-27 13:30:37.634839000 -0700
@@ -19,8 +19,8 @@
 #ifndef VAL_ARRAY_H
 #define VAL_ARRAY_H
 
-#include <ns3/assert.h>
-#include <ns3/simple-ref-count.h>
+#include "assert.h"
+#include "simple-ref-count.h"
 
 #include <complex>
 #include <valarray>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/version.cache ns-3.40/src/core/model/version.cache
--- ns-3.39/src/core/model/version.cache	2023-07-05 14:24:26.185557800 -0700
+++ ns-3.40/src/core/model/version.cache	2023-09-27 13:31:04.826903800 -0700
@@ -1,10 +1,10 @@
-CLOSEST_TAG = '"ns-3.39"'
-VERSION_COMMIT_HASH = '"g10b9bc1af"'
+CLOSEST_TAG = '"ns-3.40"'
+VERSION_COMMIT_HASH = '"g4fdc985b5"'
 VERSION_DIRTY_FLAG = '0'
 VERSION_MAJOR = '3'
-VERSION_MINOR = '39'
+VERSION_MINOR = '40'
 VERSION_PATCH = '0'
 VERSION_RELEASE_CANDIDATE = '""'
-VERSION_TAG = '"ns-3.39"'
+VERSION_TAG = '"ns-3.40"'
 VERSION_TAG_DISTANCE = '0'
 VERSION_BUILD_PROFILE = 'default'
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/version.h ns-3.40/src/core/model/version.h
--- ns-3.39/src/core/model/version.h	2023-07-05 14:23:47.769427300 -0700
+++ ns-3.40/src/core/model/version.h	2023-09-27 13:30:37.634839000 -0700
@@ -20,7 +20,7 @@
 #ifndef BUILD_VERSION_H_
 #define BUILD_VERSION_H_
 
-#include "ns3/int64x64.h"
+#include "int64x64.h"
 
 #include <string>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/model/wall-clock-synchronizer.cc ns-3.40/src/core/model/wall-clock-synchronizer.cc
--- ns-3.39/src/core/model/wall-clock-synchronizer.cc	2023-07-05 14:23:47.769427300 -0700
+++ ns-3.40/src/core/model/wall-clock-synchronizer.cc	2023-09-27 13:30:37.634839000 -0700
@@ -363,7 +363,7 @@
     // have more drift than delay, then we just play catch up as fast as possible
     // by not delaying at all.
     //
-    uint64_t correction = (uint64_t)drift;
+    auto correction = (uint64_t)drift;
     if (correction <= nsDelay)
     {
         return nsDelay - correction;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/test/global-value-test-suite.cc ns-3.40/src/core/test/global-value-test-suite.cc
--- ns-3.39/src/core/test/global-value-test-suite.cc	2023-07-05 14:23:47.769427300 -0700
+++ ns-3.40/src/core/test/global-value-test-suite.cc	2023-09-27 13:30:37.634839000 -0700
@@ -84,7 +84,7 @@
     // Remove the global value for a valgrind clean run
     //
     GlobalValue::Vector* vector = GlobalValue::GetVector();
-    for (GlobalValue::Vector::iterator i = vector->begin(); i != vector->end(); ++i)
+    for (auto i = vector->begin(); i != vector->end(); ++i)
     {
         if ((*i) == &uint)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/test/int64x64-test-suite.cc ns-3.40/src/core/test/int64x64-test-suite.cc
--- ns-3.39/src/core/test/int64x64-test-suite.cc	2023-07-05 14:23:47.769427300 -0700
+++ ns-3.40/src/core/test/int64x64-test-suite.cc	2023-09-27 13:30:37.634839000 -0700
@@ -620,7 +620,7 @@
     std::cout << std::endl;
     std::cout << GetParent()->GetName() << " Bug 455: " << GetName() << std::endl;
 
-    int64x64_t a = int64x64_t(0.1);
+    int64x64_t a(0.1);
     a /= int64x64_t(1.25);
     Check(a.GetDouble(), 0.08, "The original testcase");
 
@@ -684,7 +684,7 @@
     std::cout << std::endl;
     std::cout << GetParent()->GetName() << " Bug 863: " << GetName() << std::endl;
 
-    int64x64_t a = int64x64_t(0.9);
+    int64x64_t a(0.9);
     a /= int64x64_t(1);
     Check(a.GetDouble(), 0.9, "The original testcase");
 
@@ -1033,7 +1033,7 @@
     const int64x64_t factorI = one / int64x64_t(factor);
 
     const int64x64_t a = int64x64_t::Invert(factor);
-    int64x64_t b = int64x64_t(factor);
+    int64x64_t b(factor);
 
     double tolerance = 0;
     if (int64x64_t::implementation == int64x64_t::ld_impl)
@@ -1045,15 +1045,15 @@
     b.MulByInvert(a);
     CheckCase(factor, b, one, "x * x^-1 == 1", tolerance);
 
-    int64x64_t c = int64x64_t(1);
+    int64x64_t c(1);
     c.MulByInvert(a);
     CheckCase(factor, c, factorI, "1 * x^-1 == 1 / x");
 
-    int64x64_t d = int64x64_t(1);
+    int64x64_t d(1);
     d /= (int64x64_t(factor));
     CheckCase(factor, d, c, "1/x == x^-1");
 
-    int64x64_t e = int64x64_t(-factor);
+    int64x64_t e(-factor);
     e.MulByInvert(a);
     CheckCase(factor, e, -one, "-x * x^-1 == -1", tolerance);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/core/test/ptr-test-suite.cc ns-3.40/src/core/test/ptr-test-suite.cc
--- ns-3.39/src/core/test/ptr-test-suite.cc	2023-07-05 14:23:47.769427300 -0700
+++ ns-3.40/src/core/test/ptr-test-suite.cc	2023-09-27 13:30:37.634839000 -0700
@@ -178,7 +178,7 @@
 void
 PtrTestCase::DoRun()
 {
-    m_nDestroyed = false;
+    m_nDestroyed = 0;
     {
         Ptr<NoCount> p = Create<NoCount>(this);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/csma/examples/csma-ping.cc ns-3.40/src/csma/examples/csma-ping.cc
--- ns-3.39/src/csma/examples/csma-ping.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/csma/examples/csma-ping.cc	2023-09-27 13:30:37.638839000 -0700
@@ -100,7 +100,7 @@
 
     NS_LOG_INFO("Create Source");
     Config::SetDefault("ns3::Ipv4RawSocketImpl::Protocol", StringValue("2"));
-    InetSocketAddress dst = InetSocketAddress(addresses.GetAddress(3));
+    InetSocketAddress dst(addresses.GetAddress(3));
     OnOffHelper onoff = OnOffHelper("ns3::Ipv4RawSocketFactory", dst);
     onoff.SetConstantRate(DataRate(15000));
     onoff.SetAttribute("PacketSize", UintegerValue(1200));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/csma/examples/csma-raw-ip-socket.cc ns-3.40/src/csma/examples/csma-raw-ip-socket.cc
--- ns-3.39/src/csma/examples/csma-raw-ip-socket.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/csma/examples/csma-raw-ip-socket.cc	2023-09-27 13:30:37.638839000 -0700
@@ -93,7 +93,7 @@
     NS_LOG_INFO("Create Source");
     // IP protocol configuration
     Config::SetDefault("ns3::Ipv4RawSocketImpl::Protocol", StringValue("2"));
-    InetSocketAddress dst = InetSocketAddress(addresses.GetAddress(3));
+    InetSocketAddress dst(addresses.GetAddress(3));
     OnOffHelper onoff = OnOffHelper("ns3::Ipv4RawSocketFactory", dst);
     onoff.SetConstantRate(DataRate(dataRate * 1000));
     onoff.SetAttribute("PacketSize", UintegerValue(1250));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/csma/helper/csma-helper.cc ns-3.40/src/csma/helper/csma-helper.cc
--- ns-3.39/src/csma/helper/csma-helper.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/csma/helper/csma-helper.cc	2023-09-27 13:30:37.638839000 -0700
@@ -277,7 +277,7 @@
 {
     NetDeviceContainer devs;
 
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); i++)
+    for (auto i = c.Begin(); i != c.End(); i++)
     {
         devs.Add(InstallPriv(*i, channel));
     }
@@ -297,7 +297,7 @@
 {
     int64_t currentStream = stream;
     Ptr<NetDevice> netDevice;
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         netDevice = (*i);
         Ptr<CsmaNetDevice> csma = DynamicCast<CsmaNetDevice>(netDevice);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/csma/model/backoff.cc ns-3.40/src/csma/model/backoff.cc
--- ns-3.39/src/csma/model/backoff.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/csma/model/backoff.cc	2023-09-27 13:30:37.638839000 -0700
@@ -75,7 +75,7 @@
         maxSlot = m_maxSlots;
     }
 
-    uint32_t backoffSlots = (uint32_t)m_rng->GetValue(minSlot, maxSlot);
+    auto backoffSlots = (uint32_t)m_rng->GetValue(minSlot, maxSlot);
 
     Time backoff = Time(backoffSlots * m_slotTime);
     return backoff;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/csma/model/csma-channel.cc ns-3.40/src/csma/model/csma-channel.cc
--- ns-3.39/src/csma/model/csma-channel.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/csma/model/csma-channel.cc	2023-09-27 13:30:37.638839000 -0700
@@ -86,8 +86,7 @@
     NS_LOG_FUNCTION(this << device);
     NS_ASSERT(device);
 
-    std::vector<CsmaDeviceRec>::iterator it;
-    for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+    for (auto it = m_deviceList.begin(); it < m_deviceList.end(); it++)
     {
         if (it->devicePtr == device)
         {
@@ -161,8 +160,7 @@
     NS_LOG_FUNCTION(this << device);
     NS_ASSERT(device);
 
-    std::vector<CsmaDeviceRec>::iterator it;
-    for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+    for (auto it = m_deviceList.begin(); it < m_deviceList.end(); it++)
     {
         if ((it->devicePtr == device) && (it->active))
         {
@@ -227,8 +225,7 @@
 
     NS_LOG_LOGIC("Receive");
 
-    std::vector<CsmaDeviceRec>::iterator it;
-    for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+    for (auto it = m_deviceList.begin(); it < m_deviceList.end(); it++)
     {
         if (it->IsActive() && it->devicePtr != m_deviceList[m_currentSrc].devicePtr)
         {
@@ -261,8 +258,7 @@
 CsmaChannel::GetNumActDevices()
 {
     int numActDevices = 0;
-    std::vector<CsmaDeviceRec>::iterator it;
-    for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+    for (auto it = m_deviceList.begin(); it < m_deviceList.end(); it++)
     {
         if (it->active)
         {
@@ -287,9 +283,8 @@
 int32_t
 CsmaChannel::GetDeviceNum(Ptr<CsmaNetDevice> device)
 {
-    std::vector<CsmaDeviceRec>::iterator it;
     int i = 0;
-    for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+    for (auto it = m_deviceList.begin(); it < m_deviceList.end(); it++)
     {
         if (it->devicePtr == device)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/csma/model/csma-net-device.h ns-3.40/src/csma/model/csma-net-device.h
--- ns-3.39/src/csma/model/csma-net-device.h	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/csma/model/csma-net-device.h	2023-09-27 13:30:37.638839000 -0700
@@ -20,8 +20,9 @@
 #ifndef CSMA_NET_DEVICE_H
 #define CSMA_NET_DEVICE_H
 
+#include "backoff.h"
+
 #include "ns3/address.h"
-#include "ns3/backoff.h"
 #include "ns3/callback.h"
 #include "ns3/data-rate.h"
 #include "ns3/mac48-address.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/csma-layout/model/csma-star-helper.cc ns-3.40/src/csma-layout/model/csma-star-helper.cc
--- ns-3.39/src/csma-layout/model/csma-star-helper.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/csma-layout/model/csma-star-helper.cc	2023-09-27 13:30:37.638839000 -0700
@@ -13,16 +13,16 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <iostream>
-#include <sstream>
+#include "csma-star-helper.h"
 
-// ns3 includes
-#include "ns3/csma-star-helper.h"
 #include "ns3/log.h"
 #include "ns3/node-list.h"
 #include "ns3/point-to-point-net-device.h"
 #include "ns3/vector.h"
 
+#include <iostream>
+#include <sstream>
+
 namespace ns3
 {
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsdv/model/dsdv-packet-queue.cc ns-3.40/src/dsdv/model/dsdv-packet-queue.cc
--- ns-3.39/src/dsdv/model/dsdv-packet-queue.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/dsdv/model/dsdv-packet-queue.cc	2023-09-27 13:30:37.638839000 -0700
@@ -56,7 +56,7 @@
     NS_LOG_FUNCTION("Enqueuing packet destined for" << entry.GetIpv4Header().GetDestination());
     Purge();
     uint32_t numPacketswithdst;
-    for (std::vector<QueueEntry>::const_iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if ((i->GetPacket()->GetUid() == entry.GetPacket()->GetUid()) &&
             (i->GetIpv4Header().GetDestination() == entry.GetIpv4Header().GetDestination()))
@@ -86,7 +86,7 @@
 {
     NS_LOG_FUNCTION("Dropping packet to " << dst);
     Purge();
-    for (std::vector<QueueEntry>::iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if (i->GetIpv4Header().GetDestination() == dst)
         {
@@ -104,7 +104,7 @@
 {
     NS_LOG_FUNCTION("Dequeueing packet destined for" << dst);
     Purge();
-    for (std::vector<QueueEntry>::iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if (i->GetIpv4Header().GetDestination() == dst)
         {
@@ -119,7 +119,7 @@
 bool
 PacketQueue::Find(Ipv4Address dst)
 {
-    for (std::vector<QueueEntry>::const_iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if (i->GetIpv4Header().GetDestination() == dst)
         {
@@ -134,7 +134,7 @@
 PacketQueue::GetCountForPacketsWithDst(Ipv4Address dst)
 {
     uint32_t count = 0;
-    for (std::vector<QueueEntry>::const_iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if (i->GetIpv4Header().GetDestination() == dst)
         {
@@ -166,7 +166,7 @@
 {
     // NS_LOG_DEBUG("Purging Queue");
     IsExpired pred;
-    for (std::vector<QueueEntry>::iterator i = m_queue.begin(); i != m_queue.end(); ++i)
+    for (auto i = m_queue.begin(); i != m_queue.end(); ++i)
     {
         if (pred(*i))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsdv/model/dsdv-routing-protocol.cc ns-3.40/src/dsdv/model/dsdv-routing-protocol.cc
--- ns-3.39/src/dsdv/model/dsdv-routing-protocol.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/dsdv/model/dsdv-routing-protocol.cc	2023-09-27 13:30:37.638839000 -0700
@@ -241,9 +241,7 @@
 RoutingProtocol::DoDispose()
 {
     m_ipv4 = nullptr;
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::iterator iter = m_socketAddresses.begin();
-         iter != m_socketAddresses.end();
-         iter++)
+    for (auto iter = m_socketAddresses.begin(); iter != m_socketAddresses.end(); iter++)
     {
         iter->first->Close();
     }
@@ -304,9 +302,7 @@
                                  << ", Destination address in Packet: " << dst);
     RoutingTableEntry rt;
     m_routingTable.Purge(removedAddresses);
-    for (std::map<Ipv4Address, RoutingTableEntry>::iterator rmItr = removedAddresses.begin();
-         rmItr != removedAddresses.end();
-         ++rmItr)
+    for (auto rmItr = removedAddresses.begin(); rmItr != removedAddresses.end(); ++rmItr)
     {
         rmItr->second.SetEntriesChanged(true);
         rmItr->second.SetSeqNo(rmItr->second.GetSeqNo() + 1);
@@ -428,9 +424,7 @@
             return true;
         }
     }
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         Ipv4InterfaceAddress iface = j->second;
         if (origin == iface.GetLocal())
@@ -439,9 +433,7 @@
         }
     }
     // LOCAL DELIVARY TO DSDV INTERFACES
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         Ipv4InterfaceAddress iface = j->second;
         if (m_ipv4->GetInterfaceForAddress(iface.GetLocal()) == iif)
@@ -545,7 +537,7 @@
     // If RouteOutput() caller specified an outgoing interface, that
     // further constrains the selection of source address
     //
-    std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
+    auto j = m_socketAddresses.begin();
     if (oif)
     {
         // Iterate to find an address on the oif device
@@ -592,10 +584,7 @@
         packet->RemoveHeader(dsdvHeader);
         NS_LOG_DEBUG("Processing new update for " << dsdvHeader.GetDst());
         /*Verifying if the packets sent by me were returned back to me. If yes, discarding them!*/
-        for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j =
-                 m_socketAddresses.begin();
-             j != m_socketAddresses.end();
-             ++j)
+        for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
         {
             Ipv4InterfaceAddress interface = j->second;
             if (dsdvHeader.GetDst() == interface.GetLocal())
@@ -661,9 +650,7 @@
                 RoutingTableEntry tr;
                 std::map<Ipv4Address, RoutingTableEntry> allRoutes;
                 m_advRoutingTable.GetListOfAllRoutes(allRoutes);
-                for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = allRoutes.begin();
-                     i != allRoutes.end();
-                     ++i)
+                for (auto i = allRoutes.begin(); i != allRoutes.end(); ++i)
                 {
                     NS_LOG_DEBUG("ADV table routes are:" << i->second.GetDestination());
                 }
@@ -800,10 +787,7 @@
                     advTableEntry.SetSeqNo(dsdvHeader.GetDstSeqno());
                     advTableEntry.SetEntriesChanged(true);
                     m_advRoutingTable.Update(advTableEntry);
-                    for (std::map<Ipv4Address, RoutingTableEntry>::iterator i =
-                             dstsWithNextHopSrc.begin();
-                         i != dstsWithNextHopSrc.end();
-                         ++i)
+                    for (auto i = dstsWithNextHopSrc.begin(); i != dstsWithNextHopSrc.end(); ++i)
                     {
                         i->second.SetSeqNo(i->second.GetSeqNo() + 1);
                         i->second.SetEntriesChanged(true);
@@ -844,17 +828,13 @@
     NS_LOG_FUNCTION(m_mainAddress << " is sending a triggered update");
     std::map<Ipv4Address, RoutingTableEntry> allRoutes;
     m_advRoutingTable.GetListOfAllRoutes(allRoutes);
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         DsdvHeader dsdvHeader;
         Ptr<Socket> socket = j->first;
         Ipv4InterfaceAddress iface = j->second;
         Ptr<Packet> packet = Create<Packet>();
-        for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = allRoutes.begin();
-             i != allRoutes.end();
-             ++i)
+        for (auto i = allRoutes.begin(); i != allRoutes.end(); ++i)
         {
             NS_LOG_LOGIC("Destination: " << i->second.GetDestination()
                                          << " SeqNo:" << i->second.GetSeqNo()
@@ -930,16 +910,12 @@
         return;
     }
     NS_LOG_FUNCTION(m_mainAddress << " is sending out its periodic update");
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         Ptr<Socket> socket = j->first;
         Ipv4InterfaceAddress iface = j->second;
         Ptr<Packet> packet = Create<Packet>();
-        for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = allRoutes.begin();
-             i != allRoutes.end();
-             ++i)
+        for (auto i = allRoutes.begin(); i != allRoutes.end(); ++i)
         {
             DsdvHeader dsdvHeader;
             if (i->second.GetHop() == 0)
@@ -966,10 +942,7 @@
                          << ", HopCount:" << dsdvHeader.GetHopCount()
                          << ", LifeTime: " << i->second.GetLifeTime().As(Time::S));
         }
-        for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator rmItr =
-                 removedAddresses.begin();
-             rmItr != removedAddresses.end();
-             ++rmItr)
+        for (auto rmItr = removedAddresses.begin(); rmItr != removedAddresses.end(); ++rmItr)
         {
             DsdvHeader removedHeader;
             removedHeader.SetDst(rmItr->second.GetDestination());
@@ -1143,9 +1116,7 @@
 Ptr<Socket>
 RoutingProtocol::FindSocketWithInterfaceAddress(Ipv4InterfaceAddress addr) const
 {
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin();
-         j != m_socketAddresses.end();
-         ++j)
+    for (auto j = m_socketAddresses.begin(); j != m_socketAddresses.end(); ++j)
     {
         Ptr<Socket> socket = j->first;
         Ipv4InterfaceAddress iface = j->second;
@@ -1181,9 +1152,7 @@
     Ptr<Ipv4Route> route;
     std::map<Ipv4Address, RoutingTableEntry> allRoutes;
     m_routingTable.GetListOfAllRoutes(allRoutes);
-    for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = allRoutes.begin();
-         i != allRoutes.end();
-         ++i)
+    for (auto i = allRoutes.begin(); i != allRoutes.end(); ++i)
     {
         RoutingTableEntry rt;
         rt = i->second;
@@ -1192,20 +1161,20 @@
             if (rt.GetHop() == 1)
             {
                 route = rt.GetRoute();
+                NS_ASSERT(route);
                 NS_LOG_LOGIC("A route exists from " << route->GetSource()
                                                     << " to neighboring destination "
                                                     << route->GetDestination());
-                NS_ASSERT(route);
             }
             else
             {
                 RoutingTableEntry newrt;
                 m_routingTable.LookupRoute(rt.GetNextHop(), newrt);
                 route = newrt.GetRoute();
+                NS_ASSERT(route);
                 NS_LOG_LOGIC("A route exists from " << route->GetSource() << " to destination "
                                                     << route->GetDestination() << " via "
                                                     << rt.GetNextHop());
-                NS_ASSERT(route);
             }
             SendPacketFromQueue(rt.GetDestination(), route);
         }
@@ -1282,9 +1251,7 @@
     m_advRoutingTable.GetListOfAllRoutes(allRoutes);
     if (!allRoutes.empty())
     {
-        for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = allRoutes.begin();
-             i != allRoutes.end();
-             ++i)
+        for (auto i = allRoutes.begin(); i != allRoutes.end(); ++i)
         {
             RoutingTableEntry advEntry = i->second;
             if (advEntry.GetEntriesChanged() &&
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsdv/model/dsdv-rtable.cc ns-3.40/src/dsdv/model/dsdv-rtable.cc
--- ns-3.39/src/dsdv/model/dsdv-rtable.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/dsdv/model/dsdv-rtable.cc	2023-09-27 13:30:37.638839000 -0700
@@ -80,7 +80,7 @@
     {
         return false;
     }
-    std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = m_ipv4AddressEntry.find(id);
+    auto i = m_ipv4AddressEntry.find(id);
     if (i == m_ipv4AddressEntry.end())
     {
         return false;
@@ -96,7 +96,7 @@
     {
         return false;
     }
-    std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = m_ipv4AddressEntry.find(id);
+    auto i = m_ipv4AddressEntry.find(id);
     if (i == m_ipv4AddressEntry.end())
     {
         return false;
@@ -124,16 +124,14 @@
 bool
 RoutingTable::AddRoute(RoutingTableEntry& rt)
 {
-    std::pair<std::map<Ipv4Address, RoutingTableEntry>::iterator, bool> result =
-        m_ipv4AddressEntry.insert(std::make_pair(rt.GetDestination(), rt));
+    auto result = m_ipv4AddressEntry.insert(std::make_pair(rt.GetDestination(), rt));
     return result.second;
 }
 
 bool
 RoutingTable::Update(RoutingTableEntry& rt)
 {
-    std::map<Ipv4Address, RoutingTableEntry>::iterator i =
-        m_ipv4AddressEntry.find(rt.GetDestination());
+    auto i = m_ipv4AddressEntry.find(rt.GetDestination());
     if (i == m_ipv4AddressEntry.end())
     {
         return false;
@@ -149,12 +147,11 @@
     {
         return;
     }
-    for (std::map<Ipv4Address, RoutingTableEntry>::iterator i = m_ipv4AddressEntry.begin();
-         i != m_ipv4AddressEntry.end();)
+    for (auto i = m_ipv4AddressEntry.begin(); i != m_ipv4AddressEntry.end();)
     {
         if (i->second.GetInterface() == iface)
         {
-            std::map<Ipv4Address, RoutingTableEntry>::iterator tmp = i;
+            auto tmp = i;
             ++i;
             m_ipv4AddressEntry.erase(tmp);
         }
@@ -168,9 +165,7 @@
 void
 RoutingTable::GetListOfAllRoutes(std::map<Ipv4Address, RoutingTableEntry>& allRoutes)
 {
-    for (std::map<Ipv4Address, RoutingTableEntry>::iterator i = m_ipv4AddressEntry.begin();
-         i != m_ipv4AddressEntry.end();
-         ++i)
+    for (auto i = m_ipv4AddressEntry.begin(); i != m_ipv4AddressEntry.end(); ++i)
     {
         if (i->second.GetDestination() != Ipv4Address("127.0.0.1") && i->second.GetFlag() == VALID)
         {
@@ -184,9 +179,7 @@
                                               std::map<Ipv4Address, RoutingTableEntry>& unreachable)
 {
     unreachable.clear();
-    for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = m_ipv4AddressEntry.begin();
-         i != m_ipv4AddressEntry.end();
-         ++i)
+    for (auto i = m_ipv4AddressEntry.begin(); i != m_ipv4AddressEntry.end(); ++i)
     {
         if (i->second.GetNextHop() == nextHop)
         {
@@ -234,19 +227,17 @@
     {
         return;
     }
-    for (std::map<Ipv4Address, RoutingTableEntry>::iterator i = m_ipv4AddressEntry.begin();
-         i != m_ipv4AddressEntry.end();)
+    for (auto i = m_ipv4AddressEntry.begin(); i != m_ipv4AddressEntry.end();)
     {
-        std::map<Ipv4Address, RoutingTableEntry>::iterator itmp = i;
+        auto itmp = i;
         if (i->second.GetLifeTime() > m_holddownTime && (i->second.GetHop() > 0))
         {
-            for (std::map<Ipv4Address, RoutingTableEntry>::iterator j = m_ipv4AddressEntry.begin();
-                 j != m_ipv4AddressEntry.end();)
+            for (auto j = m_ipv4AddressEntry.begin(); j != m_ipv4AddressEntry.end();)
             {
                 if ((j->second.GetNextHop() == i->second.GetDestination()) &&
                     (i->second.GetHop() != j->second.GetHop()))
                 {
-                    std::map<Ipv4Address, RoutingTableEntry>::iterator jtmp = j;
+                    auto jtmp = j;
                     removedAddresses.insert(std::make_pair(j->first, j->second));
                     ++j;
                     m_ipv4AddressEntry.erase(jtmp);
@@ -291,9 +282,7 @@
     *os << std::setw(16) << "SeqNum";
     *os << std::setw(16) << "LifeTime";
     *os << "SettlingTime" << std::endl;
-    for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i = m_ipv4AddressEntry.begin();
-         i != m_ipv4AddressEntry.end();
-         ++i)
+    for (auto i = m_ipv4AddressEntry.begin(); i != m_ipv4AddressEntry.end(); ++i)
     {
         i->second.Print(stream, unit);
     }
@@ -305,8 +294,7 @@
 bool
 RoutingTable::AddIpv4Event(Ipv4Address address, EventId id)
 {
-    std::pair<std::map<Ipv4Address, EventId>::iterator, bool> result =
-        m_ipv4Events.insert(std::make_pair(address, id));
+    auto result = m_ipv4Events.insert(std::make_pair(address, id));
     return result.second;
 }
 
@@ -314,7 +302,7 @@
 RoutingTable::AnyRunningEvent(Ipv4Address address)
 {
     EventId event;
-    std::map<Ipv4Address, EventId>::const_iterator i = m_ipv4Events.find(address);
+    auto i = m_ipv4Events.find(address);
     if (m_ipv4Events.empty())
     {
         return false;
@@ -331,7 +319,7 @@
 RoutingTable::ForceDeleteIpv4Event(Ipv4Address address)
 {
     EventId event;
-    std::map<Ipv4Address, EventId>::const_iterator i = m_ipv4Events.find(address);
+    auto i = m_ipv4Events.find(address);
     if (m_ipv4Events.empty() || i == m_ipv4Events.end())
     {
         return false;
@@ -346,7 +334,7 @@
 RoutingTable::DeleteIpv4Event(Ipv4Address address)
 {
     EventId event;
-    std::map<Ipv4Address, EventId>::const_iterator i = m_ipv4Events.find(address);
+    auto i = m_ipv4Events.find(address);
     if (m_ipv4Events.empty() || i == m_ipv4Events.end())
     {
         return false;
@@ -372,7 +360,7 @@
 EventId
 RoutingTable::GetEventId(Ipv4Address address)
 {
-    std::map<Ipv4Address, EventId>::const_iterator i = m_ipv4Events.find(address);
+    auto i = m_ipv4Events.find(address);
     if (m_ipv4Events.empty() || i == m_ipv4Events.end())
     {
         return EventId();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsdv/model/dsdv-rtable.h ns-3.40/src/dsdv/model/dsdv-rtable.h
--- ns-3.39/src/dsdv/model/dsdv-rtable.h	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/dsdv/model/dsdv-rtable.h	2023-09-27 13:30:37.638839000 -0700
@@ -317,7 +317,7 @@
     /// A node does that in hope of receiving a better update.
     Time m_settlingTime;
     /// Flag to show if any of the routing table entries were changed with the routing update.
-    uint32_t m_entriesChanged;
+    bool m_entriesChanged;
 };
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/helper/dsr-main-helper.cc ns-3.40/src/dsr/helper/dsr-main-helper.cc
--- ns-3.39/src/dsr/helper/dsr-main-helper.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/dsr/helper/dsr-main-helper.cc	2023-09-27 13:30:37.638839000 -0700
@@ -30,7 +30,8 @@
 
 #include "dsr-main-helper.h"
 
-#include "ns3/dsr-helper.h"
+#include "dsr-helper.h"
+
 #include "ns3/dsr-rcache.h"
 #include "ns3/dsr-routing.h"
 #include "ns3/dsr-rreq-table.h"
@@ -80,7 +81,7 @@
     NS_LOG_DEBUG("Passed node container");
     delete m_dsrHelper;
     m_dsrHelper = dsrHelper.Copy();
-    for (NodeContainer::Iterator i = nodes.Begin(); i != nodes.End(); ++i)
+    for (auto i = nodes.Begin(); i != nodes.End(); ++i)
     {
         Install(*i);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/helper/dsr-main-helper.h ns-3.40/src/dsr/helper/dsr-main-helper.h
--- ns-3.39/src/dsr/helper/dsr-main-helper.h	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/dsr/helper/dsr-main-helper.h	2023-09-27 13:30:37.638839000 -0700
@@ -31,7 +31,8 @@
 #ifndef DSR_MAIN_HELPER_H
 #define DSR_MAIN_HELPER_H
 
-#include "ns3/dsr-helper.h"
+#include "dsr-helper.h"
+
 #include "ns3/dsr-routing.h"
 #include "ns3/node-container.h"
 #include "ns3/node.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-errorbuff.cc ns-3.40/src/dsr/model/dsr-errorbuff.cc
--- ns-3.39/src/dsr/model/dsr-errorbuff.cc	2023-07-05 14:23:47.773427200 -0700
+++ ns-3.40/src/dsr/model/dsr-errorbuff.cc	2023-09-27 13:30:37.638839000 -0700
@@ -56,9 +56,7 @@
 DsrErrorBuffer::Enqueue(DsrErrorBuffEntry& entry)
 {
     Purge();
-    for (std::vector<DsrErrorBuffEntry>::const_iterator i = m_errorBuffer.begin();
-         i != m_errorBuffer.end();
-         ++i)
+    for (auto i = m_errorBuffer.begin(); i != m_errorBuffer.end(); ++i)
     {
         NS_LOG_INFO("packet id " << i->GetPacket()->GetUid() << " " << entry.GetPacket()->GetUid()
                                  << " source " << i->GetSource() << " " << entry.GetSource()
@@ -101,9 +99,7 @@
     /*
      * Drop the packet with the error link source----------nextHop
      */
-    for (std::vector<DsrErrorBuffEntry>::iterator i = m_errorBuffer.begin();
-         i != m_errorBuffer.end();
-         ++i)
+    for (auto i = m_errorBuffer.begin(); i != m_errorBuffer.end(); ++i)
     {
         if ((i->GetSource() == link[0]) && (i->GetNextHop() == link[1]))
         {
@@ -127,9 +123,7 @@
     /*
      * Dequeue the entry with destination address dst
      */
-    for (std::vector<DsrErrorBuffEntry>::iterator i = m_errorBuffer.begin();
-         i != m_errorBuffer.end();
-         ++i)
+    for (auto i = m_errorBuffer.begin(); i != m_errorBuffer.end(); ++i)
     {
         if (i->GetDestination() == dst)
         {
@@ -148,9 +142,7 @@
     /*
      * Make sure if the send buffer contains entry with certain dst
      */
-    for (std::vector<DsrErrorBuffEntry>::const_iterator i = m_errorBuffer.begin();
-         i != m_errorBuffer.end();
-         ++i)
+    for (auto i = m_errorBuffer.begin(); i != m_errorBuffer.end(); ++i)
     {
         if (i->GetDestination() == dst)
         {
@@ -184,9 +176,7 @@
      */
     NS_LOG_DEBUG("The error buffer size " << m_errorBuffer.size());
     IsExpired pred;
-    for (std::vector<DsrErrorBuffEntry>::iterator i = m_errorBuffer.begin();
-         i != m_errorBuffer.end();
-         ++i)
+    for (auto i = m_errorBuffer.begin(); i != m_errorBuffer.end(); ++i)
     {
         if (pred(*i))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-gratuitous-reply-table.cc ns-3.40/src/dsr/model/dsr-gratuitous-reply-table.cc
--- ns-3.39/src/dsr/model/dsr-gratuitous-reply-table.cc	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-gratuitous-reply-table.cc	2023-09-27 13:30:37.638839000 -0700
@@ -67,7 +67,7 @@
 DsrGraReply::FindAndUpdate(Ipv4Address replyTo, Ipv4Address replyFrom, Time gratReplyHoldoff)
 {
     Purge(); // purge the gratuitous reply table
-    for (std::vector<GraReplyEntry>::iterator i = m_graReply.begin(); i != m_graReply.end(); ++i)
+    for (auto i = m_graReply.begin(); i != m_graReply.end(); ++i)
     {
         if ((i->m_replyTo == replyTo) && (i->m_hearFrom == replyFrom))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-maintain-buff.cc ns-3.40/src/dsr/model/dsr-maintain-buff.cc
--- ns-3.39/src/dsr/model/dsr-maintain-buff.cc	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-maintain-buff.cc	2023-09-27 13:30:37.638839000 -0700
@@ -56,9 +56,7 @@
 DsrMaintainBuffer::Enqueue(DsrMaintainBuffEntry& entry)
 {
     Purge();
-    for (std::vector<DsrMaintainBuffEntry>::const_iterator i = m_maintainBuffer.begin();
-         i != m_maintainBuffer.end();
-         ++i)
+    for (auto i = m_maintainBuffer.begin(); i != m_maintainBuffer.end(); ++i)
     {
         //      NS_LOG_INFO ("nexthop " << i->GetNextHop () << " " << entry.GetNextHop () << " our
         //      add " << i->GetOurAdd () << " " << entry.GetOurAdd ()
@@ -106,9 +104,7 @@
 DsrMaintainBuffer::Dequeue(Ipv4Address nextHop, DsrMaintainBuffEntry& entry)
 {
     Purge();
-    for (std::vector<DsrMaintainBuffEntry>::iterator i = m_maintainBuffer.begin();
-         i != m_maintainBuffer.end();
-         ++i)
+    for (auto i = m_maintainBuffer.begin(); i != m_maintainBuffer.end(); ++i)
     {
         if (i->GetNextHop() == nextHop)
         {
@@ -124,9 +120,7 @@
 bool
 DsrMaintainBuffer::Find(Ipv4Address nextHop)
 {
-    for (std::vector<DsrMaintainBuffEntry>::const_iterator i = m_maintainBuffer.begin();
-         i != m_maintainBuffer.end();
-         ++i)
+    for (auto i = m_maintainBuffer.begin(); i != m_maintainBuffer.end(); ++i)
     {
         if (i->GetNextHop() == nextHop)
         {
@@ -140,9 +134,7 @@
 bool
 DsrMaintainBuffer::AllEqual(DsrMaintainBuffEntry& entry)
 {
-    for (std::vector<DsrMaintainBuffEntry>::iterator i = m_maintainBuffer.begin();
-         i != m_maintainBuffer.end();
-         ++i)
+    for (auto i = m_maintainBuffer.begin(); i != m_maintainBuffer.end(); ++i)
     {
         //      NS_LOG_DEBUG ("nexthop " << i->GetNextHop () << " " << entry.GetNextHop () << " our
         //      address " << i->GetOurAdd () << " " << entry.GetOurAdd ()
@@ -166,9 +158,7 @@
 bool
 DsrMaintainBuffer::NetworkEqual(DsrMaintainBuffEntry& entry)
 {
-    for (std::vector<DsrMaintainBuffEntry>::iterator i = m_maintainBuffer.begin();
-         i != m_maintainBuffer.end();
-         ++i)
+    for (auto i = m_maintainBuffer.begin(); i != m_maintainBuffer.end(); ++i)
     {
         //      NS_LOG_DEBUG ("nexthop " << i->GetNextHop () << " " << entry.GetNextHop () << " our
         //      address " << i->GetOurAdd () << " " << entry.GetOurAdd ()
@@ -193,9 +183,7 @@
 DsrMaintainBuffer::PromiscEqual(DsrMaintainBuffEntry& entry)
 {
     NS_LOG_DEBUG("The maintenance buffer size " << m_maintainBuffer.size());
-    for (std::vector<DsrMaintainBuffEntry>::iterator i = m_maintainBuffer.begin();
-         i != m_maintainBuffer.end();
-         ++i)
+    for (auto i = m_maintainBuffer.begin(); i != m_maintainBuffer.end(); ++i)
     {
         //      NS_LOG_DEBUG ("src " << i->GetSrc () << " " << entry.GetSrc () << " dst " <<
         //      i->GetDst () << " " << entry.GetDst ()
@@ -220,9 +208,7 @@
 DsrMaintainBuffer::LinkEqual(DsrMaintainBuffEntry& entry)
 {
     NS_LOG_DEBUG("The maintenance buffer size " << m_maintainBuffer.size());
-    for (std::vector<DsrMaintainBuffEntry>::iterator i = m_maintainBuffer.begin();
-         i != m_maintainBuffer.end();
-         ++i)
+    for (auto i = m_maintainBuffer.begin(); i != m_maintainBuffer.end(); ++i)
     {
         //      NS_LOG_DEBUG ("src " << i->GetSrc () << " " << entry.GetSrc () << " dst " <<
         //      i->GetDst () << " " << entry.GetDst ()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-network-queue.cc ns-3.40/src/dsr/model/dsr-network-queue.cc
--- ns-3.39/src/dsr/model/dsr-network-queue.cc	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-network-queue.cc	2023-09-27 13:30:37.638839000 -0700
@@ -107,9 +107,7 @@
 DsrNetworkQueue::FindPacketWithNexthop(Ipv4Address nextHop, DsrNetworkQueueEntry& entry)
 {
     Cleanup();
-    for (std::vector<DsrNetworkQueueEntry>::iterator i = m_dsrNetworkQueue.begin();
-         i != m_dsrNetworkQueue.end();
-         ++i)
+    for (auto i = m_dsrNetworkQueue.begin(); i != m_dsrNetworkQueue.end(); ++i)
     {
         if (i->GetNextHopAddress() == nextHop)
         {
@@ -125,9 +123,7 @@
 DsrNetworkQueue::Find(Ipv4Address nextHop)
 {
     Cleanup();
-    for (std::vector<DsrNetworkQueueEntry>::iterator i = m_dsrNetworkQueue.begin();
-         i != m_dsrNetworkQueue.end();
-         ++i)
+    for (auto i = m_dsrNetworkQueue.begin(); i != m_dsrNetworkQueue.end(); ++i)
     {
         if (i->GetNextHopAddress() == nextHop)
         {
@@ -158,7 +154,7 @@
 {
     NS_LOG_FUNCTION(this);
     Cleanup();
-    std::vector<DsrNetworkQueueEntry>::iterator i = m_dsrNetworkQueue.begin();
+    auto i = m_dsrNetworkQueue.begin();
     if (i == m_dsrNetworkQueue.end())
     {
         // no elements in array
@@ -182,8 +178,7 @@
 
     Time now = Simulator::Now();
     uint32_t n = 0;
-    for (std::vector<DsrNetworkQueueEntry>::iterator i = m_dsrNetworkQueue.begin();
-         i != m_dsrNetworkQueue.end();)
+    for (auto i = m_dsrNetworkQueue.begin(); i != m_dsrNetworkQueue.end();)
     {
         if (i->GetInsertedTimeStamp() + m_maxDelay > now)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-option-header.cc ns-3.40/src/dsr/model/dsr-option-header.cc
--- ns-3.39/src/dsr/model/dsr-option-header.cc	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-option-header.cc	2023-09-27 13:30:37.638839000 -0700
@@ -371,9 +371,7 @@
 {
     os << "( type = " << (uint32_t)GetType() << " length = " << (uint32_t)GetLength() << "";
 
-    for (std::vector<Ipv4Address>::const_iterator it = m_ipv4Address.begin();
-         it != m_ipv4Address.end();
-         it++)
+    for (auto it = m_ipv4Address.begin(); it != m_ipv4Address.end(); it++)
     {
         os << *it << " ";
     }
@@ -398,8 +396,7 @@
     i.WriteHtonU16(m_identification);
     WriteTo(i, m_target);
 
-    for (VectorIpv4Address_t::const_iterator it = m_ipv4Address.begin(); it != m_ipv4Address.end();
-         it++)
+    for (auto it = m_ipv4Address.begin(); it != m_ipv4Address.end(); it++)
     {
         it->Serialize(buff);
         i.Write(buff, 4);
@@ -506,9 +503,7 @@
 {
     os << "( type = " << (uint32_t)GetType() << " length = " << (uint32_t)GetLength() << "";
 
-    for (std::vector<Ipv4Address>::const_iterator it = m_ipv4Address.begin();
-         it != m_ipv4Address.end();
-         it++)
+    for (auto it = m_ipv4Address.begin(); it != m_ipv4Address.end(); it++)
     {
         os << *it << " ";
     }
@@ -533,8 +528,7 @@
     i.WriteU8(0);
     i.WriteU8(0);
 
-    for (VectorIpv4Address_t::const_iterator it = m_ipv4Address.begin(); it != m_ipv4Address.end();
-         it++)
+    for (auto it = m_ipv4Address.begin(); it != m_ipv4Address.end(); it++)
     {
         it->Serialize(buff);
         i.Write(buff, 4);
@@ -666,9 +660,7 @@
 {
     os << "( type = " << (uint32_t)GetType() << " length = " << (uint32_t)GetLength() << "";
 
-    for (std::vector<Ipv4Address>::const_iterator it = m_ipv4Address.begin();
-         it != m_ipv4Address.end();
-         it++)
+    for (auto it = m_ipv4Address.begin(); it != m_ipv4Address.end(); it++)
     {
         os << *it << " ";
     }
@@ -693,8 +685,7 @@
     i.WriteU8(m_salvage);
     i.WriteU8(m_segmentsLeft);
 
-    for (VectorIpv4Address_t::const_iterator it = m_ipv4Address.begin(); it != m_ipv4Address.end();
-         it++)
+    for (auto it = m_ipv4Address.begin(); it != m_ipv4Address.end(); it++)
     {
         it->Serialize(buff);
         i.Write(buff, 4);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-options.cc ns-3.40/src/dsr/model/dsr-options.cc
--- ns-3.39/src/dsr/model/dsr-options.cc	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-options.cc	2023-09-27 13:30:37.638839000 -0700
@@ -125,9 +125,9 @@
                                 std::vector<Ipv4Address>& nodeList)
 {
     NS_LOG_FUNCTION(this << ipv4Address << destAddress);
-    std::vector<Ipv4Address>::iterator it = find(nodeList.begin(), nodeList.end(), destAddress);
+    auto it = find(nodeList.begin(), nodeList.end(), destAddress);
 
-    for (std::vector<Ipv4Address>::iterator i = it; i != nodeList.end(); ++i)
+    for (auto i = it; i != nodeList.end(); ++i)
     {
         if ((ipv4Address == (*i)) && ((*i) != nodeList.back()))
         {
@@ -141,9 +141,9 @@
 DsrOptions::CutRoute(Ipv4Address ipv4Address, std::vector<Ipv4Address>& nodeList)
 {
     NS_LOG_FUNCTION(this << ipv4Address);
-    std::vector<Ipv4Address>::iterator it = find(nodeList.begin(), nodeList.end(), ipv4Address);
+    auto it = find(nodeList.begin(), nodeList.end(), ipv4Address);
     std::vector<Ipv4Address> cutRoute;
-    for (std::vector<Ipv4Address>::iterator i = it; i != nodeList.end(); ++i)
+    for (auto i = it; i != nodeList.end(); ++i)
     {
         cutRoute.push_back(*i);
     }
@@ -190,7 +190,7 @@
                                                                  << vec.back());
         return ipv4Address;
     }
-    for (std::vector<Ipv4Address>::const_iterator i = vec.begin(); i != vec.end(); ++i)
+    for (auto i = vec.begin(); i != vec.end(); ++i)
     {
         if (ipv4Address == (*i))
         {
@@ -216,7 +216,7 @@
         return nextHop;
     }
 
-    for (std::vector<Ipv4Address>::reverse_iterator ri = vec.rbegin(); ri != vec.rend(); ++ri)
+    for (auto ri = vec.rbegin(); ri != vec.rend(); ++ri)
     {
         if (ipv4Address == (*ri))
         {
@@ -237,7 +237,7 @@
     Ipv4Address nextTwoHop;
     NS_LOG_DEBUG("The vector size " << vec.size());
     NS_ASSERT(vec.size() > 2);
-    for (std::vector<Ipv4Address>::reverse_iterator ri = vec.rbegin(); ri != vec.rend(); ++ri)
+    for (auto ri = vec.rbegin(); ri != vec.rend(); ++ri)
     {
         if (ipv4Address == (*ri))
         {
@@ -264,7 +264,7 @@
     else
     {
         NS_LOG_DEBUG("Print all the elements in a vector");
-        for (std::vector<Ipv4Address>::const_iterator i = vec.begin(); i != vec.end(); ++i)
+        for (auto i = vec.begin(); i != vec.end(); ++i)
         {
             NS_LOG_DEBUG("The ip address " << *i);
         }
@@ -275,9 +275,9 @@
 DsrOptions::IfDuplicates(std::vector<Ipv4Address>& vec, std::vector<Ipv4Address>& vec2)
 {
     NS_LOG_FUNCTION(this);
-    for (std::vector<Ipv4Address>::const_iterator i = vec.begin(); i != vec.end(); ++i)
+    for (auto i = vec.begin(); i != vec.end(); ++i)
     {
-        for (std::vector<Ipv4Address>::const_iterator j = vec2.begin(); j != vec2.end(); ++j)
+        for (auto j = vec2.begin(); j != vec2.end(); ++j)
         {
             if ((*i) == (*j))
             {
@@ -292,7 +292,7 @@
 DsrOptions::CheckDuplicates(Ipv4Address ipv4Address, std::vector<Ipv4Address>& vec)
 {
     NS_LOG_FUNCTION(this << ipv4Address);
-    for (std::vector<Ipv4Address>::const_iterator i = vec.begin(); i != vec.end(); ++i)
+    for (auto i = vec.begin(); i != vec.end(); ++i)
     {
         if ((*i) == ipv4Address)
         {
@@ -311,7 +311,7 @@
     std::vector<Ipv4Address> vec2(vec); // declare vec2 as a copy of the vec
     PrintVector(vec2);                  // Print all the ip address in the route
     vec.clear();                        // clear vec
-    for (std::vector<Ipv4Address>::const_iterator i = vec2.begin(); i != vec2.end(); ++i)
+    for (auto i = vec2.begin(); i != vec2.end(); ++i)
     {
         if (vec.empty())
         {
@@ -319,7 +319,7 @@
             continue;
         }
 
-        for (std::vector<Ipv4Address>::iterator j = vec.begin(); j != vec.end(); ++j)
+        for (auto j = vec.begin(); j != vec.end(); ++j)
         {
             if ((*i) == (*j))
             {
@@ -679,9 +679,7 @@
                 std::vector<Ipv4Address> changeRoute(nodeList);
                 changeRoute.push_back(ipv4Address); // push back our own address
                 m_finalRoute.clear();               // get a clear route vector
-                for (std::vector<Ipv4Address>::iterator i = changeRoute.begin();
-                     i != changeRoute.end();
-                     ++i)
+                for (auto i = changeRoute.begin(); i != changeRoute.end(); ++i)
                 {
                     m_finalRoute.push_back(*i); // Get the full route from source to destination
                 }
@@ -805,8 +803,7 @@
             /**
              * push back the intermediate node address from the source to this node
              */
-            for (std::vector<Ipv4Address>::iterator i = saveRoute.begin(); i != saveRoute.end();
-                 ++i)
+            for (auto i = saveRoute.begin(); i != saveRoute.end(); ++i)
             {
                 m_finalRoute.push_back(*i);
             }
@@ -814,7 +811,7 @@
              * push back the route vector we found in our route cache to destination, including this
              * node's address
              */
-            for (std::vector<Ipv4Address>::iterator j = ip.begin(); j != ip.end(); ++j)
+            for (auto j = ip.begin(); j != ip.end(); ++j)
             {
                 m_finalRoute.push_back(*j);
             }
@@ -1389,7 +1386,7 @@
 
         // Get the option type value
         uint32_t size = p->GetSize();
-        uint8_t* data = new uint8_t[size];
+        auto data = new uint8_t[size];
         p->CopyData(data, size);
         uint8_t optionType = 0;
         optionType = *(data);
@@ -1560,7 +1557,7 @@
                          << (uint32_t)protocol << isPromisc);
     Ptr<Packet> p = packet->Copy();
     uint32_t size = p->GetSize();
-    uint8_t* data = new uint8_t[size];
+    auto data = new uint8_t[size];
     p->CopyData(data, size);
     uint8_t errorType = *(data + 2);
     /*
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-passive-buff.cc ns-3.40/src/dsr/model/dsr-passive-buff.cc
--- ns-3.39/src/dsr/model/dsr-passive-buff.cc	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-passive-buff.cc	2023-09-27 13:30:37.638839000 -0700
@@ -76,9 +76,7 @@
 DsrPassiveBuffer::Enqueue(DsrPassiveBuffEntry& entry)
 {
     Purge();
-    for (std::vector<DsrPassiveBuffEntry>::const_iterator i = m_passiveBuffer.begin();
-         i != m_passiveBuffer.end();
-         ++i)
+    for (auto i = m_passiveBuffer.begin(); i != m_passiveBuffer.end(); ++i)
     {
         //      NS_LOG_INFO ("packet id " << i->GetPacket ()->GetUid () << " " << entry.GetPacket
         //      ()->GetUid () << " source " << i->GetSource () << " " << entry.GetSource ()
@@ -119,9 +117,7 @@
 bool
 DsrPassiveBuffer::AllEqual(DsrPassiveBuffEntry& entry)
 {
-    for (std::vector<DsrPassiveBuffEntry>::iterator i = m_passiveBuffer.begin();
-         i != m_passiveBuffer.end();
-         ++i)
+    for (auto i = m_passiveBuffer.begin(); i != m_passiveBuffer.end(); ++i)
     {
         //      NS_LOG_INFO ("packet id " << i->GetPacket ()->GetUid () << " " << entry.GetPacket
         //      ()->GetUid () << " source " << i->GetSource () << " " << entry.GetSource ()
@@ -156,9 +152,7 @@
     /*
      * Dequeue the entry with destination address dst
      */
-    for (std::vector<DsrPassiveBuffEntry>::iterator i = m_passiveBuffer.begin();
-         i != m_passiveBuffer.end();
-         ++i)
+    for (auto i = m_passiveBuffer.begin(); i != m_passiveBuffer.end(); ++i)
     {
         if (i->GetDestination() == dst)
         {
@@ -177,9 +171,7 @@
     /*
      * Make sure if the send buffer contains entry with certain dst
      */
-    for (std::vector<DsrPassiveBuffEntry>::const_iterator i = m_passiveBuffer.begin();
-         i != m_passiveBuffer.end();
-         ++i)
+    for (auto i = m_passiveBuffer.begin(); i != m_passiveBuffer.end(); ++i)
     {
         if (i->GetDestination() == dst)
         {
@@ -213,9 +205,7 @@
      */
     NS_LOG_DEBUG("The passive buffer size " << m_passiveBuffer.size());
     IsExpired pred;
-    for (std::vector<DsrPassiveBuffEntry>::iterator i = m_passiveBuffer.begin();
-         i != m_passiveBuffer.end();
-         ++i)
+    for (auto i = m_passiveBuffer.begin(); i != m_passiveBuffer.end(); ++i)
     {
         if (pred(*i))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-rcache.cc ns-3.40/src/dsr/model/dsr-rcache.cc
--- ns-3.39/src/dsr/model/dsr-rcache.cc	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-rcache.cc	2023-09-27 13:30:37.638839000 -0700
@@ -185,8 +185,7 @@
 DsrRouteCache::UpdateRouteEntry(Ipv4Address dst)
 {
     NS_LOG_FUNCTION(this << dst);
-    std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::const_iterator i =
-        m_sortedRoutes.find(dst);
+    auto i = m_sortedRoutes.find(dst);
     if (i == m_sortedRoutes.end())
     {
         NS_LOG_LOGIC("Failed to find the route entry for the destination " << dst);
@@ -204,8 +203,7 @@
         /*
          * Save the new route cache along with the destination address in map
          */
-        std::pair<std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::iterator, bool> result =
-            m_sortedRoutes.insert(std::make_pair(dst, rtVector));
+        auto result = m_sortedRoutes.insert(std::make_pair(dst, rtVector));
         return result.second;
     }
     return false;
@@ -226,32 +224,24 @@
         NS_LOG_LOGIC("Route to " << id << " not found; m_sortedRoutes is empty");
         return false;
     }
-    std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::const_iterator i =
-        m_sortedRoutes.find(id);
+    auto i = m_sortedRoutes.find(id);
     if (i == m_sortedRoutes.end())
     {
         NS_LOG_LOGIC("No Direct Route to " << id << " found");
-        for (std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::const_iterator j =
-                 m_sortedRoutes.begin();
-             j != m_sortedRoutes.end();
-             ++j)
+        for (auto j = m_sortedRoutes.begin(); j != m_sortedRoutes.end(); ++j)
         {
             std::list<DsrRouteCacheEntry> rtVector =
                 j->second; // The route cache vector linked with destination address
             /*
              * Loop through the possibly multiple routes within the route vector
              */
-            for (std::list<DsrRouteCacheEntry>::const_iterator k = rtVector.begin();
-                 k != rtVector.end();
-                 ++k)
+            for (auto k = rtVector.begin(); k != rtVector.end(); ++k)
             {
                 // return the first route in the route vector
                 DsrRouteCacheEntry::IP_VECTOR routeVector = k->GetVector();
                 DsrRouteCacheEntry::IP_VECTOR changeVector;
 
-                for (DsrRouteCacheEntry::IP_VECTOR::iterator l = routeVector.begin();
-                     l != routeVector.end();
-                     ++l)
+                for (auto l = routeVector.begin(); l != routeVector.end(); ++l)
                 {
                     changeVector.push_back(*l);
 
@@ -283,8 +273,7 @@
         }
     }
     NS_LOG_INFO("Here we check the route cache again after updated the sub routes");
-    std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::const_iterator m =
-        m_sortedRoutes.find(id);
+    auto m = m_sortedRoutes.find(id);
     if (m == m_sortedRoutes.end())
     {
         NS_LOG_LOGIC("No updated route till last time");
@@ -336,9 +325,7 @@
     std::map<Ipv4Address, uint32_t> d;
     // @pre preceding node
     std::map<Ipv4Address, Ipv4Address> pre;
-    for (std::map<Ipv4Address, std::map<Ipv4Address, uint32_t>>::iterator i = m_netGraph.begin();
-         i != m_netGraph.end();
-         ++i)
+    for (auto i = m_netGraph.begin(); i != m_netGraph.end(); ++i)
     {
         if (i->second.find(source) != i->second.end())
         {
@@ -358,11 +345,11 @@
     // the node set which shortest distance has been calculated, if true calculated
     std::map<Ipv4Address, bool> s;
     double temp = MAXWEIGHT;
-    Ipv4Address tempip = Ipv4Address("255.255.255.255");
+    Ipv4Address tempip("255.255.255.255");
     for (uint32_t i = 0; i < m_netGraph.size(); i++)
     {
         temp = MAXWEIGHT;
-        for (std::map<Ipv4Address, uint32_t>::const_iterator j = d.begin(); j != d.end(); ++j)
+        for (auto j = d.begin(); j != d.end(); ++j)
         {
             Ipv4Address ip = j->first;
             if (s.find(ip) == s.end())
@@ -380,9 +367,7 @@
         if (!tempip.IsBroadcast())
         {
             s[tempip] = true;
-            for (std::map<Ipv4Address, uint32_t>::const_iterator k = m_netGraph[tempip].begin();
-                 k != m_netGraph[tempip].end();
-                 ++k)
+            for (auto k = m_netGraph[tempip].begin(); k != m_netGraph[tempip].end(); ++k)
             {
                 if (s.find(k->first) == s.end() && d[k->first] > d[tempip] + k->second)
                 {
@@ -398,10 +383,8 @@
                  */
                 else if (d[k->first] == d[tempip] + k->second)
                 {
-                    std::map<Link, DsrLinkStab>::iterator oldlink =
-                        m_linkCache.find(Link(k->first, pre[k->first]));
-                    std::map<Link, DsrLinkStab>::iterator newlink =
-                        m_linkCache.find(Link(k->first, tempip));
+                    auto oldlink = m_linkCache.find(Link(k->first, pre[k->first]));
+                    auto newlink = m_linkCache.find(Link(k->first, tempip));
                     if (oldlink != m_linkCache.end() && newlink != m_linkCache.end())
                     {
                         if (oldlink->second.GetLinkStability() < newlink->second.GetLinkStability())
@@ -421,7 +404,7 @@
     }
     // clean the best route table
     m_bestRoutesTable_link.clear();
-    for (std::map<Ipv4Address, Ipv4Address>::iterator i = pre.begin(); i != pre.end(); ++i)
+    for (auto i = pre.begin(); i != pre.end(); ++i)
     {
         // loop for all vertices
         DsrRouteCacheEntry::IP_VECTOR route;
@@ -450,8 +433,7 @@
     NS_LOG_FUNCTION(this << id);
     /// We need to purge the link node cache
     PurgeLinkNode();
-    std::map<Ipv4Address, DsrRouteCacheEntry::IP_VECTOR>::const_iterator i =
-        m_bestRoutesTable_link.find(id);
+    auto i = m_bestRoutesTable_link.find(id);
     if (i == m_bestRoutesTable_link.end())
     {
         NS_LOG_INFO("No route find to " << id);
@@ -479,10 +461,10 @@
 DsrRouteCache::PurgeLinkNode()
 {
     NS_LOG_FUNCTION(this);
-    for (std::map<Link, DsrLinkStab>::iterator i = m_linkCache.begin(); i != m_linkCache.end();)
+    for (auto i = m_linkCache.begin(); i != m_linkCache.end();)
     {
         NS_LOG_DEBUG("The link stability " << i->second.GetLinkStability().As(Time::S));
-        std::map<Link, DsrLinkStab>::iterator itmp = i;
+        auto itmp = i;
         if (i->second.GetLinkStability() <= Seconds(0))
         {
             ++i;
@@ -494,11 +476,10 @@
         }
     }
     /// may need to remove them after verify
-    for (std::map<Ipv4Address, DsrNodeStab>::iterator i = m_nodeCache.begin();
-         i != m_nodeCache.end();)
+    for (auto i = m_nodeCache.begin(); i != m_nodeCache.end();)
     {
         NS_LOG_DEBUG("The node stability " << i->second.GetNodeStability().As(Time::S));
-        std::map<Ipv4Address, DsrNodeStab>::iterator itmp = i;
+        auto itmp = i;
         if (i->second.GetNodeStability() <= Seconds(0))
         {
             ++i;
@@ -516,7 +497,7 @@
 {
     NS_LOG_FUNCTION(this);
     m_netGraph.clear();
-    for (std::map<Link, DsrLinkStab>::iterator i = m_linkCache.begin(); i != m_linkCache.end(); ++i)
+    for (auto i = m_linkCache.begin(); i != m_linkCache.end(); ++i)
     {
         // Here the weight is set as 1
         /// \todo May need to set different weight for different link here later
@@ -530,7 +511,7 @@
 DsrRouteCache::IncStability(Ipv4Address node)
 {
     NS_LOG_FUNCTION(this << node);
-    std::map<Ipv4Address, DsrNodeStab>::const_iterator i = m_nodeCache.find(node);
+    auto i = m_nodeCache.find(node);
     if (i == m_nodeCache.end())
     {
         NS_LOG_INFO("The initial stability " << m_initStability.As(Time::S));
@@ -555,7 +536,7 @@
 DsrRouteCache::DecStability(Ipv4Address node)
 {
     NS_LOG_FUNCTION(this << node);
-    std::map<Ipv4Address, DsrNodeStab>::const_iterator i = m_nodeCache.find(node);
+    auto i = m_nodeCache.find(node);
     if (i == m_nodeCache.end())
     {
         DsrNodeStab ns(m_initStability);
@@ -636,7 +617,7 @@
         NS_LOG_INFO("The route is too short");
         return;
     }
-    for (DsrRouteCacheEntry::IP_VECTOR::iterator i = rt.begin(); i != rt.end() - 1; ++i)
+    for (auto i = rt.begin(); i != rt.end() - 1; ++i)
     {
         Link link(*i, *(i + 1));
         if (m_linkCache.find(link) != m_linkCache.end())
@@ -655,7 +636,7 @@
         }
     }
     /// Increase the stability of the node cache
-    for (DsrRouteCacheEntry::IP_VECTOR::iterator i = rt.begin(); i != rt.end(); ++i)
+    for (auto i = rt.begin(); i != rt.end(); ++i)
     {
         if (m_nodeCache.find(*i) != m_nodeCache.end())
         {
@@ -682,8 +663,7 @@
     std::vector<Ipv4Address> route = rt.GetVector();
 
     NS_LOG_DEBUG("The route destination we have " << dst);
-    std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::const_iterator i =
-        m_sortedRoutes.find(dst);
+    auto i = m_sortedRoutes.find(dst);
 
     if (i == m_sortedRoutes.end())
     {
@@ -692,8 +672,7 @@
         /**
          * Save the new route cache along with the destination address in map
          */
-        std::pair<std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::iterator, bool> result =
-            m_sortedRoutes.insert(std::make_pair(dst, rtVector));
+        auto result = m_sortedRoutes.insert(std::make_pair(dst, rtVector));
         return result.second;
     }
 
@@ -734,8 +713,7 @@
             /**
              * Save the new route cache along with the destination address in map
              */
-            std::pair<std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::iterator, bool> result =
-                m_sortedRoutes.insert(std::make_pair(dst, rtVector));
+            auto result = m_sortedRoutes.insert(std::make_pair(dst, rtVector));
             return result.second;
         }
         else
@@ -751,7 +729,7 @@
 DsrRouteCache::FindSameRoute(DsrRouteCacheEntry& rt, std::list<DsrRouteCacheEntry>& rtVector)
 {
     NS_LOG_FUNCTION(this);
-    for (std::list<DsrRouteCacheEntry>::iterator i = rtVector.begin(); i != rtVector.end(); ++i)
+    for (auto i = rtVector.begin(); i != rtVector.end(); ++i)
     {
         // return the first route in the route vector
         DsrRouteCacheEntry::IP_VECTOR routeVector = i->GetVector();
@@ -773,8 +751,7 @@
             /*
              * Save the new route cache along with the destination address in map
              */
-            std::pair<std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::iterator, bool> result =
-                m_sortedRoutes.insert(std::make_pair(rt.GetDestination(), rtVector));
+            auto result = m_sortedRoutes.insert(std::make_pair(rt.GetDestination(), rtVector));
             return result.second;
         }
     }
@@ -819,7 +796,7 @@
         m_linkCache.erase(link2);
         NS_LOG_DEBUG("The link cache size " << m_linkCache.size());
 
-        std::map<Ipv4Address, DsrNodeStab>::iterator i = m_nodeCache.find(errorSrc);
+        auto i = m_nodeCache.find(errorSrc);
         if (i == m_nodeCache.end())
         {
             NS_LOG_LOGIC("Update the node stability unsuccessfuly");
@@ -854,17 +831,15 @@
         /*
          * Loop all the routes saved in the route cache
          */
-        for (std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::iterator j =
-                 m_sortedRoutes.begin();
-             j != m_sortedRoutes.end();)
+        for (auto j = m_sortedRoutes.begin(); j != m_sortedRoutes.end();)
         {
-            std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::iterator jtmp = j;
+            auto jtmp = j;
             Ipv4Address address = j->first;
             std::list<DsrRouteCacheEntry> rtVector = j->second;
             /*
              * Loop all the routes for a single destination
              */
-            for (std::list<DsrRouteCacheEntry>::iterator k = rtVector.begin(); k != rtVector.end();)
+            for (auto k = rtVector.begin(); k != rtVector.end();)
             {
                 // return the first route in the route vector
                 DsrRouteCacheEntry::IP_VECTOR routeVector = k->GetVector();
@@ -872,9 +847,7 @@
                 /*
                  * Loop the ip addresses within a single route entry
                  */
-                for (DsrRouteCacheEntry::IP_VECTOR::iterator i = routeVector.begin();
-                     i != routeVector.end();
-                     ++i)
+                for (auto i = routeVector.begin(); i != routeVector.end(); ++i)
                 {
                     if (*i != errorSrc)
                     {
@@ -972,7 +945,7 @@
     else
     {
         NS_LOG_DEBUG("Print all the elements in a vector");
-        for (std::vector<Ipv4Address>::const_iterator i = vec.begin(); i != vec.end(); ++i)
+        for (auto i = vec.begin(); i != vec.end(); ++i)
         {
             NS_LOG_DEBUG("The ip address " << *i);
         }
@@ -983,7 +956,7 @@
 DsrRouteCache::PrintRouteVector(std::list<DsrRouteCacheEntry> route)
 {
     NS_LOG_FUNCTION(this);
-    for (std::list<DsrRouteCacheEntry>::iterator i = route.begin(); i != route.end(); i++)
+    for (auto i = route.begin(); i != route.end(); i++)
     {
         std::vector<Ipv4Address> path = i->GetVector();
         NS_LOG_INFO("Route NO. ");
@@ -1001,11 +974,10 @@
         NS_LOG_DEBUG("The route cache is empty");
         return;
     }
-    for (std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::iterator i = m_sortedRoutes.begin();
-         i != m_sortedRoutes.end();)
+    for (auto i = m_sortedRoutes.begin(); i != m_sortedRoutes.end();)
     {
         // Loop of route cache entry with the route size
-        std::map<Ipv4Address, std::list<DsrRouteCacheEntry>>::iterator itmp = i;
+        auto itmp = i;
         /*
          * The route cache entry vector
          */
@@ -1014,7 +986,7 @@
         NS_LOG_DEBUG("The route vector size of 1 " << dst << " " << rtVector.size());
         if (!rtVector.empty())
         {
-            for (std::list<DsrRouteCacheEntry>::iterator j = rtVector.begin(); j != rtVector.end();)
+            for (auto j = rtVector.begin(); j != rtVector.end();)
             {
                 NS_LOG_DEBUG("The expire time of every entry with expire time "
                              << j->GetExpireTime());
@@ -1066,9 +1038,7 @@
     Purge();
     os << "\nDSR Route Cache\n"
        << "Destination\tGateway\t\tInterface\tFlag\tExpire\tHops\n";
-    for (std::list<DsrRouteCacheEntry>::const_iterator i = m_routeEntryVector.begin();
-         i != m_routeEntryVector.end();
-         ++i)
+    for (auto i = m_routeEntryVector.begin(); i != m_routeEntryVector.end(); ++i)
     {
         i->Print(os);
     }
@@ -1083,7 +1053,7 @@
 DsrRouteCache::CheckUniqueAckId(Ipv4Address nextHop)
 {
     NS_LOG_FUNCTION(this);
-    std::map<Ipv4Address, uint16_t>::const_iterator i = m_ackIdCache.find(nextHop);
+    auto i = m_ackIdCache.find(nextHop);
     if (i == m_ackIdCache.end())
     {
         NS_LOG_LOGIC("No Ack id for " << nextHop
@@ -1114,7 +1084,7 @@
 {
     NS_LOG_FUNCTION(this);
     PurgeMac(); // purge the mac cache
-    for (std::vector<Neighbor>::const_iterator i = m_nb.begin(); i != m_nb.end(); ++i)
+    for (auto i = m_nb.begin(); i != m_nb.end(); ++i)
     {
         if (i->m_neighborAddress == addr)
         {
@@ -1129,7 +1099,7 @@
 {
     NS_LOG_FUNCTION(this);
     PurgeMac();
-    for (std::vector<Neighbor>::const_iterator i = m_nb.begin(); i != m_nb.end(); ++i)
+    for (auto i = m_nb.begin(); i != m_nb.end(); ++i)
     {
         if (i->m_neighborAddress == addr)
         {
@@ -1143,9 +1113,9 @@
 DsrRouteCache::UpdateNeighbor(std::vector<Ipv4Address> nodeList, Time expire)
 {
     NS_LOG_FUNCTION(this);
-    for (std::vector<Neighbor>::iterator i = m_nb.begin(); i != m_nb.end(); ++i)
+    for (auto i = m_nb.begin(); i != m_nb.end(); ++i)
     {
-        for (std::vector<Ipv4Address>::iterator j = nodeList.begin(); j != nodeList.end(); ++j)
+        for (auto j = nodeList.begin(); j != nodeList.end(); ++j)
         {
             if (i->m_neighborAddress == (*j))
             {
@@ -1170,7 +1140,7 @@
 DsrRouteCache::AddNeighbor(std::vector<Ipv4Address> nodeList, Ipv4Address ownAddress, Time expire)
 {
     NS_LOG_LOGIC("Add neighbor number " << nodeList.size());
-    for (std::vector<Ipv4Address>::iterator j = nodeList.begin(); j != nodeList.end();)
+    for (auto j = nodeList.begin(); j != nodeList.end();)
     {
         Ipv4Address addr = *j;
         if (addr == ownAddress)
@@ -1214,7 +1184,7 @@
     CloseNeighbor pred;
     if (!m_handleLinkFailure.IsNull())
     {
-        for (std::vector<Neighbor>::iterator j = m_nb.begin(); j != m_nb.end(); ++j)
+        for (auto j = m_nb.begin(); j != m_nb.end(); ++j)
         {
             if (pred(*j))
             {
@@ -1252,7 +1222,7 @@
 DsrRouteCache::LookupMacAddress(Ipv4Address addr)
 {
     Mac48Address hwaddr;
-    for (std::vector<Ptr<ArpCache>>::const_iterator i = m_arp.begin(); i != m_arp.end(); ++i)
+    for (auto i = m_arp.begin(); i != m_arp.end(); ++i)
     {
         ArpCache::Entry* entry = (*i)->Lookup(addr);
         if (entry != nullptr && (entry->IsAlive() || entry->IsPermanent()) && !entry->IsExpired())
@@ -1269,7 +1239,7 @@
 {
     Mac48Address addr = hdr.GetAddr1();
 
-    for (std::vector<Neighbor>::iterator i = m_nb.begin(); i != m_nb.end(); ++i)
+    for (auto i = m_nb.begin(); i != m_nb.end(); ++i)
     {
         if (i->m_hardwareAddress == addr)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-rcache.h ns-3.40/src/dsr/model/dsr-rcache.h
--- ns-3.39/src/dsr/model/dsr-rcache.h	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-rcache.h	2023-09-27 13:30:37.638839000 -0700
@@ -356,8 +356,8 @@
             NS_ASSERT(false);
             return false;
         }
-        IP_VECTOR::const_iterator j = o.m_path.begin();
-        for (IP_VECTOR::const_iterator i = m_path.begin(); i != m_path.end(); i++, j++)
+        auto j = o.m_path.begin();
+        for (auto i = m_path.begin(); i != m_path.end(); i++, j++)
         {
             /*
              * Verify if neither the entry are not 0 and they equal to each other
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-routing.cc ns-3.40/src/dsr/model/dsr-routing.cc
--- ns-3.39/src/dsr/model/dsr-routing.cc	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-routing.cc	2023-09-27 13:30:37.642839000 -0700
@@ -443,8 +443,7 @@
                                               << m_maxNetworkDelay.As(Time::S));
         Ptr<dsr::DsrNetworkQueue> queue_i =
             CreateObject<dsr::DsrNetworkQueue>(m_maxNetworkSize, m_maxNetworkDelay);
-        std::pair<std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator, bool> result_i =
-            m_priorityQueue.insert(std::make_pair(i, queue_i));
+        auto result_i = m_priorityQueue.insert(std::make_pair(i, queue_i));
         NS_ASSERT_MSG(result_i.second, "Error in creating queues");
     }
     Ptr<dsr::DsrRreqTable> rreqTable = CreateObject<dsr::DsrRreqTable>();
@@ -748,7 +747,7 @@
     else
     {
         NS_LOG_DEBUG("Print all the elements in a vector");
-        for (std::vector<Ipv4Address>::const_iterator i = vec.begin(); i != vec.end(); ++i)
+        for (auto i = vec.begin(); i != vec.end(); ++i)
         {
             NS_LOG_DEBUG("The ip address " << *i);
         }
@@ -774,7 +773,7 @@
                                                                  << vec.back());
         return ipv4Address;
     }
-    for (std::vector<Ipv4Address>::const_iterator i = vec.begin(); i != vec.end(); ++i)
+    for (auto i = vec.begin(); i != vec.end(); ++i)
     {
         if (ipv4Address == (*i))
         {
@@ -866,8 +865,7 @@
     NS_LOG_INFO(Simulator::Now().As(Time::S) << " Checking send buffer at " << m_mainAddress
                                              << " with size " << m_sendBuffer.GetSize());
 
-    for (std::vector<DsrSendBuffEntry>::iterator i = m_sendBuffer.GetBuffer().begin();
-         i != m_sendBuffer.GetBuffer().end();)
+    for (auto i = m_sendBuffer.GetBuffer().begin(); i != m_sendBuffer.GetBuffer().end();)
     {
         NS_LOG_DEBUG("Here we try to find the data packet in the send buffer");
         Ipv4Address destination = i->GetDestination();
@@ -895,7 +893,7 @@
              * Peek data to get the option type as well as length and segmentsLeft field
              */
             uint32_t size = copyP->GetSize();
-            uint8_t* data = new uint8_t[size];
+            auto data = new uint8_t[size];
             copyP->CopyData(data, size);
 
             uint8_t optionType = 0;
@@ -959,8 +957,7 @@
                     m_ipv4Route->SetOutputDevice(dev);
 
                     uint32_t priority = GetPriority(DSR_CONTROL_PACKET); /// This will be priority 0
-                    std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator i =
-                        m_priorityQueue.find(priority);
+                    auto i = m_priorityQueue.find(priority);
                     Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = i->second;
                     NS_LOG_LOGIC("Will be inserting into priority queue number: " << priority);
 
@@ -1175,7 +1172,7 @@
          * Peek data to get the option type as well as length and segmentsLeft field
          */
         uint32_t size = pktMinusIpHdr->GetSize();
-        uint8_t* data = new uint8_t[size];
+        auto data = new uint8_t[size];
         pktMinusIpHdr->CopyData(data, size);
         uint8_t optionType = 0;
         optionType = *(data);
@@ -1451,7 +1448,7 @@
                                                                << newPacket->GetSize());
 
         uint32_t priority = GetPriority(DSR_CONTROL_PACKET);
-        std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator i = m_priorityQueue.find(priority);
+        auto i = m_priorityQueue.find(priority);
         Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = i->second;
         NS_LOG_DEBUG("Will be inserting into priority queue " << dsrNetworkQueue
                                                               << " number: " << priority);
@@ -1501,7 +1498,7 @@
     route->SetOutputDevice(dev);
 
     uint32_t priority = GetPriority(DSR_CONTROL_PACKET);
-    std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator i = m_priorityQueue.find(priority);
+    auto i = m_priorityQueue.find(priority);
     Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = i->second;
     NS_LOG_DEBUG("Will be inserting into priority queue " << dsrNetworkQueue
                                                           << " number: " << priority);
@@ -1740,7 +1737,7 @@
     m_ipv4Route->SetOutputDevice(dev);
 
     uint32_t priority = GetPriority(DSR_DATA_PACKET);
-    std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator i = m_priorityQueue.find(priority);
+    auto i = m_priorityQueue.find(priority);
     Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = i->second;
     NS_LOG_INFO("Will be inserting into priority queue number: " << priority);
 
@@ -1782,7 +1779,7 @@
     // priorities ranging from 0 to m_numPriorityQueues, with 0 as the highest priority
     for (uint32_t i = priority; numPriorities < m_numPriorityQueues; numPriorities++)
     {
-        std::map<uint32_t, Ptr<DsrNetworkQueue>>::iterator q = m_priorityQueue.find(i);
+        auto q = m_priorityQueue.find(i);
         Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = q->second;
         uint32_t queueSize = dsrNetworkQueue->GetSize();
         if (queueSize == 0)
@@ -1799,10 +1796,7 @@
         else
         {
             uint32_t totalQueueSize = 0;
-            for (std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator j =
-                     m_priorityQueue.begin();
-                 j != m_priorityQueue.end();
-                 j++)
+            for (auto j = m_priorityQueue.begin(); j != m_priorityQueue.end(); j++)
             {
                 NS_LOG_INFO("The size of the network queue for " << j->first << " is "
                                                                  << j->second->GetSize());
@@ -1854,18 +1848,14 @@
     // We may want to get the queue first and then we need to save a vector of the entries here and
     // then find
     uint32_t priority = GetPriority(DSR_DATA_PACKET);
-    std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator i = m_priorityQueue.find(priority);
+    auto i = m_priorityQueue.find(priority);
     Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = i->second;
 
     std::vector<DsrNetworkQueueEntry> newNetworkQueue = dsrNetworkQueue->GetQueue();
-    for (std::vector<DsrNetworkQueueEntry>::iterator i = newNetworkQueue.begin();
-         i != newNetworkQueue.end();
-         i++)
+    for (auto i = newNetworkQueue.begin(); i != newNetworkQueue.end(); i++)
     {
         Ipv4Address nextHop = i->GetNextHopAddress();
-        for (std::map<NetworkKey, Timer>::iterator j = m_addressForwardTimer.begin();
-             j != m_addressForwardTimer.end();
-             j++)
+        for (auto j = m_addressForwardTimer.begin(); j != m_addressForwardTimer.end(); j++)
         {
             if (nextHop == j->first.m_nextHop)
             {
@@ -2031,7 +2021,7 @@
              * Peek data to get the option type as well as length and segmentsLeft field
              */
             uint32_t size = copyP->GetSize();
-            uint8_t* data = new uint8_t[size];
+            auto data = new uint8_t[size];
             copyP->CopyData(data, size);
 
             uint8_t optionType = 0;
@@ -2085,8 +2075,7 @@
                     m_ipv4Route->SetOutputDevice(dev);
 
                     uint32_t priority = GetPriority(DSR_CONTROL_PACKET);
-                    std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator i =
-                        m_priorityQueue.find(priority);
+                    auto i = m_priorityQueue.find(priority);
                     Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = i->second;
                     NS_LOG_DEBUG("Will be inserting into priority queue "
                                  << dsrNetworkQueue << " number: " << priority);
@@ -2259,7 +2248,7 @@
     // TODO if find the linkkey, we need to remove it
 
     // Find the network acknowledgment timer
-    std::map<LinkKey, Timer>::const_iterator i = m_linkAckTimer.find(linkKey);
+    auto i = m_linkAckTimer.find(linkKey);
     if (i == m_linkAckTimer.end())
     {
         NS_LOG_INFO("did not find the link timer");
@@ -2308,7 +2297,7 @@
                          << mb.GetNextHop() << " source " << mb.GetSrc() << " destination "
                          << mb.GetDst() << " segsLeft " << (uint32_t)mb.GetSegsLeft());
     // Find the network acknowledgment timer
-    std::map<NetworkKey, Timer>::const_iterator i = m_addressForwardTimer.find(networkKey);
+    auto i = m_addressForwardTimer.find(networkKey);
     if (i == m_addressForwardTimer.end())
     {
         NS_LOG_INFO("did not find the packet timer");
@@ -2349,7 +2338,7 @@
     m_passiveCnt.erase(passiveKey);
 
     // Find the passive acknowledgment timer
-    std::map<PassiveKey, Timer>::const_iterator j = m_passiveAckTimer.find(passiveKey);
+    auto j = m_passiveAckTimer.find(passiveKey);
     if (j == m_passiveAckTimer.end())
     {
         NS_LOG_INFO("did not find the passive timer");
@@ -2523,7 +2512,7 @@
 
         // Send out the data packet
         uint32_t priority = GetPriority(DSR_DATA_PACKET);
-        std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator i = m_priorityQueue.find(priority);
+        auto i = m_priorityQueue.find(priority);
         Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = i->second;
         NS_LOG_DEBUG("Will be inserting into priority queue " << dsrNetworkQueue
                                                               << " number: " << priority);
@@ -3309,7 +3298,7 @@
      * The destination address here is directed broadcast address
      */
     uint32_t priority = GetPriority(DSR_CONTROL_PACKET);
-    std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator i = m_priorityQueue.find(priority);
+    auto i = m_priorityQueue.find(priority);
     Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = i->second;
     NS_LOG_LOGIC("Inserting into priority queue number: " << priority);
 
@@ -3363,16 +3352,14 @@
         /**
          * Push back the node addresses other than those between srcAddress and our own ip address
          */
-        std::vector<Ipv4Address>::iterator before =
-            find(nodeList.begin(), nodeList.end(), srcAddress);
-        for (std::vector<Ipv4Address>::iterator i = nodeList.begin(); i != before; ++i)
+        auto before = find(nodeList.begin(), nodeList.end(), srcAddress);
+        for (auto i = nodeList.begin(); i != before; ++i)
         {
             m_finalRoute.push_back(*i);
         }
         m_finalRoute.push_back(srcAddress);
-        std::vector<Ipv4Address>::iterator after =
-            find(nodeList.begin(), nodeList.end(), m_mainAddress);
-        for (std::vector<Ipv4Address>::iterator j = after; j != nodeList.end(); ++j)
+        auto after = find(nodeList.begin(), nodeList.end(), m_mainAddress);
+        for (auto j = after; j != nodeList.end(); ++j)
         {
             m_finalRoute.push_back(*j);
         }
@@ -3426,7 +3413,7 @@
     NS_LOG_INFO("The output device " << dev << " packet is: " << *packet);
 
     uint32_t priority = GetPriority(DSR_CONTROL_PACKET);
-    std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator i = m_priorityQueue.find(priority);
+    auto i = m_priorityQueue.find(priority);
     Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = i->second;
     NS_LOG_INFO("Inserting into priority queue number: " << priority);
 
@@ -3509,7 +3496,7 @@
     route->SetOutputDevice(dev);
 
     uint32_t priority = GetPriority(DSR_CONTROL_PACKET);
-    std::map<uint32_t, Ptr<dsr::DsrNetworkQueue>>::iterator i = m_priorityQueue.find(priority);
+    auto i = m_priorityQueue.find(priority);
     Ptr<dsr::DsrNetworkQueue> dsrNetworkQueue = i->second;
 
     NS_LOG_LOGIC("Will be inserting into priority queue " << dsrNetworkQueue
@@ -3568,7 +3555,7 @@
      * Peek data to get the option type as well as length and segmentsLeft field
      */
     uint32_t size = p->GetSize();
-    uint8_t* data = new uint8_t[size];
+    auto data = new uint8_t[size];
     p->CopyData(data, size);
 
     uint8_t optionType = 0;
@@ -3770,7 +3757,7 @@
 Ptr<dsr::DsrOptions>
 DsrRouting::GetOption(int optionNumber)
 {
-    for (DsrOptionList_t::iterator i = m_options.begin(); i != m_options.end(); ++i)
+    for (auto i = m_options.begin(); i != m_options.end(); ++i)
     {
         if ((*i)->GetOptionNumber() == optionNumber)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-rreq-table.cc ns-3.40/src/dsr/model/dsr-rreq-table.cc
--- ns-3.39/src/dsr/model/dsr-rreq-table.cc	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-rreq-table.cc	2023-09-27 13:30:37.642839000 -0700
@@ -71,9 +71,7 @@
     NS_LOG_FUNCTION(this);
     Ipv4Address firstExpire;
     Time max = Seconds(0.0);
-    for (std::map<Ipv4Address, RreqTableEntry>::const_iterator i = m_rreqDstMap.begin();
-         i != m_rreqDstMap.end();
-         ++i)
+    for (auto i = m_rreqDstMap.begin(); i != m_rreqDstMap.end(); ++i)
     {
         Ipv4Address dst = i->first;
         RreqTableEntry rreqTableEntry = i->second;
@@ -90,7 +88,7 @@
 DsrRreqTable::FindAndUpdate(Ipv4Address dst)
 {
     NS_LOG_FUNCTION(this << dst);
-    std::map<Ipv4Address, RreqTableEntry>::const_iterator i = m_rreqDstMap.find(dst);
+    auto i = m_rreqDstMap.find(dst);
     if (i == m_rreqDstMap.end())
     {
         NS_LOG_LOGIC("The request table entry for " << dst << " not found");
@@ -123,7 +121,7 @@
 DsrRreqTable::RemoveRreqEntry(Ipv4Address dst)
 {
     NS_LOG_FUNCTION(this << dst);
-    std::map<Ipv4Address, RreqTableEntry>::const_iterator i = m_rreqDstMap.find(dst);
+    auto i = m_rreqDstMap.find(dst);
     if (i == m_rreqDstMap.end())
     {
         NS_LOG_LOGIC("The request table entry not found");
@@ -139,7 +137,7 @@
 DsrRreqTable::GetRreqCnt(Ipv4Address dst)
 {
     NS_LOG_FUNCTION(this << dst);
-    std::map<Ipv4Address, RreqTableEntry>::const_iterator i = m_rreqDstMap.find(dst);
+    auto i = m_rreqDstMap.find(dst);
     if (i == m_rreqDstMap.end())
     {
         NS_LOG_LOGIC("Request table entry not found");
@@ -159,7 +157,7 @@
 DsrRreqTable::CheckUniqueRreqId(Ipv4Address dst)
 {
     NS_LOG_LOGIC("The size of id cache " << m_rreqIdCache.size());
-    std::map<Ipv4Address, uint32_t>::const_iterator i = m_rreqIdCache.find(dst);
+    auto i = m_rreqIdCache.find(dst);
     if (i == m_rreqIdCache.end())
     {
         NS_LOG_LOGIC("No Request id for " << dst << " found, initialize it to 0");
@@ -210,7 +208,7 @@
 DsrRreqTable::FindUnidirectional(Ipv4Address neighbor)
 {
     PurgeNeighbor(); // purge the neighbor cache
-    for (std::vector<BlackList>::iterator i = m_blackList.begin(); i != m_blackList.end(); ++i)
+    for (auto i = m_blackList.begin(); i != m_blackList.end(); ++i)
     {
         if (i->m_neighborAddress == neighbor)
         {
@@ -224,7 +222,7 @@
 DsrRreqTable::MarkLinkAsUnidirectional(Ipv4Address neighbor, Time blacklistTimeout)
 {
     NS_LOG_LOGIC("Add neighbor address in blacklist " << m_blackList.size());
-    for (std::vector<BlackList>::iterator i = m_blackList.begin(); i != m_blackList.end(); i++)
+    for (auto i = m_blackList.begin(); i != m_blackList.end(); i++)
     {
         if (i->m_neighborAddress == neighbor)
         {
@@ -260,8 +258,7 @@
     /*
      * this function will return false if the entry is not found, true if duplicate entry find
      */
-    std::map<Ipv4Address, std::list<DsrReceivedRreqEntry>>::const_iterator i =
-        m_sourceRreqMap.find(src);
+    auto i = m_sourceRreqMap.find(src);
     if (i == m_sourceRreqMap.end())
     {
         NS_LOG_LOGIC("The source request table entry for " << src << " not found");
@@ -284,9 +281,7 @@
     }
 
     // We loop the receive rreq entry to find duplicate
-    for (std::list<DsrReceivedRreqEntry>::const_iterator j = receivedRreqEntryList.begin();
-         j != receivedRreqEntryList.end();
-         ++j)
+    for (auto j = receivedRreqEntryList.begin(); j != receivedRreqEntryList.end(); ++j)
     {
         if (*j == rreqEntry) /// Check if we have found one duplication entry or not
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/model/dsr-rsendbuff.cc ns-3.40/src/dsr/model/dsr-rsendbuff.cc
--- ns-3.39/src/dsr/model/dsr-rsendbuff.cc	2023-07-05 14:23:47.777427200 -0700
+++ ns-3.40/src/dsr/model/dsr-rsendbuff.cc	2023-09-27 13:30:37.642839000 -0700
@@ -56,9 +56,7 @@
 DsrSendBuffer::Enqueue(DsrSendBuffEntry& entry)
 {
     Purge();
-    for (std::vector<DsrSendBuffEntry>::const_iterator i = m_sendBuffer.begin();
-         i != m_sendBuffer.end();
-         ++i)
+    for (auto i = m_sendBuffer.begin(); i != m_sendBuffer.end(); ++i)
     {
         //      NS_LOG_DEBUG ("packet id " << i->GetPacket ()->GetUid () << " " << entry.GetPacket
         //      ()->GetUid ()
@@ -94,8 +92,7 @@
     /*
      * Drop the packet with destination address dst
      */
-    for (std::vector<DsrSendBuffEntry>::iterator i = m_sendBuffer.begin(); i != m_sendBuffer.end();
-         ++i)
+    for (auto i = m_sendBuffer.begin(); i != m_sendBuffer.end(); ++i)
     {
         if (i->GetDestination() == dst)
         {
@@ -116,8 +113,7 @@
     /*
      * Dequeue the entry with destination address dst
      */
-    for (std::vector<DsrSendBuffEntry>::iterator i = m_sendBuffer.begin(); i != m_sendBuffer.end();
-         ++i)
+    for (auto i = m_sendBuffer.begin(); i != m_sendBuffer.end(); ++i)
     {
         if (i->GetDestination() == dst)
         {
@@ -136,9 +132,7 @@
     /*
      * Make sure if the send buffer contains entry with certain dst
      */
-    for (std::vector<DsrSendBuffEntry>::const_iterator i = m_sendBuffer.begin();
-         i != m_sendBuffer.end();
-         ++i)
+    for (auto i = m_sendBuffer.begin(); i != m_sendBuffer.end(); ++i)
     {
         if (i->GetDestination() == dst)
         {
@@ -171,8 +165,7 @@
      */
     NS_LOG_INFO("The send buffer size " << m_sendBuffer.size());
     IsExpired pred;
-    for (std::vector<DsrSendBuffEntry>::iterator i = m_sendBuffer.begin(); i != m_sendBuffer.end();
-         ++i)
+    for (auto i = m_sendBuffer.begin(); i != m_sendBuffer.end(); ++i)
     {
         if (pred(*i))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/dsr/test/dsr-test-suite.cc ns-3.40/src/dsr/test/dsr-test-suite.cc
--- ns-3.39/src/dsr/test/dsr-test-suite.cc	2023-07-05 14:23:47.785427300 -0700
+++ ns-3.40/src/dsr/test/dsr-test-suite.cc	2023-09-27 13:30:37.642839000 -0700
@@ -443,7 +443,7 @@
         Ipv4Address("0.0.0.1"),
     };
 
-    Ipv4Address dst = Ipv4Address("0.0.0.1");
+    Ipv4Address dst("0.0.0.1");
     dsr::DsrRouteCacheEntry entry(ip, dst, Seconds(1));
     NS_TEST_EXPECT_MSG_EQ(entry.GetVector().size(), 2, "trivial");
     NS_TEST_EXPECT_MSG_EQ(entry.GetDestination(), Ipv4Address("0.0.0.1"), "trivial");
@@ -464,7 +464,7 @@
         Ipv4Address("1.1.1.1"),
     };
 
-    Ipv4Address dst2 = Ipv4Address("1.1.1.1");
+    Ipv4Address dst2("1.1.1.1");
     dsr::DsrRouteCacheEntry entry2(ip2, dst2, Seconds(2));
     dsr::DsrRouteCacheEntry newEntry;
     NS_TEST_EXPECT_MSG_EQ(rcache->AddRoute(entry2), true, "trivial");
@@ -516,7 +516,7 @@
     NS_TEST_EXPECT_MSG_EQ(q.GetSendBufferTimeout(), Seconds(10), "trivial");
 
     Ptr<const Packet> packet = Create<Packet>();
-    Ipv4Address dst1 = Ipv4Address("0.0.0.1");
+    Ipv4Address dst1("0.0.0.1");
     dsr::DsrSendBuffEntry e1(packet, dst1, Seconds(1));
     q.Enqueue(e1);
     q.Enqueue(e1);
@@ -528,7 +528,7 @@
     NS_TEST_EXPECT_MSG_EQ(q.Find(Ipv4Address("0.0.0.1")), false, "trivial");
     NS_TEST_EXPECT_MSG_EQ(q.GetSize(), 0, "trivial");
 
-    Ipv4Address dst2 = Ipv4Address("0.0.0.2");
+    Ipv4Address dst2("0.0.0.2");
     dsr::DsrSendBuffEntry e2(packet, dst2, Seconds(1));
     q.Enqueue(e1);
     q.Enqueue(e2);
@@ -541,7 +541,7 @@
     q.Enqueue(e3);
     NS_TEST_EXPECT_MSG_EQ(q.GetSize(), 2, "trivial");
     Ptr<Packet> packet4 = Create<Packet>();
-    Ipv4Address dst4 = Ipv4Address("0.0.0.4");
+    Ipv4Address dst4("0.0.0.4");
     dsr::DsrSendBuffEntry e4(packet4, dst4, Seconds(20));
     q.Enqueue(e4);
     NS_TEST_EXPECT_MSG_EQ(q.GetSize(), 3, "trivial");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/CMakeLists.txt ns-3.40/src/energy/CMakeLists.txt
--- ns-3.39/src/energy/CMakeLists.txt	2023-07-05 14:23:47.785427300 -0700
+++ ns-3.40/src/energy/CMakeLists.txt	2023-09-27 13:30:37.642839000 -0700
@@ -7,6 +7,7 @@
     helper/energy-harvester-helper.cc
     helper/energy-model-helper.cc
     helper/energy-source-container.cc
+    helper/generic-battery-model-helper.cc
     helper/li-ion-energy-source-helper.cc
     helper/rv-battery-model-helper.cc
     model/basic-energy-harvester.cc
@@ -15,6 +16,7 @@
     model/device-energy-model.cc
     model/energy-harvester.cc
     model/energy-source.cc
+    model/generic-battery-model.cc
     model/li-ion-energy-source.cc
     model/rv-battery-model.cc
     model/simple-device-energy-model.cc
@@ -25,6 +27,7 @@
     helper/energy-harvester-helper.h
     helper/energy-model-helper.h
     helper/energy-source-container.h
+    helper/generic-battery-model-helper.h
     helper/li-ion-energy-source-helper.h
     helper/rv-battery-model-helper.h
     model/basic-energy-harvester.h
@@ -33,6 +36,7 @@
     model/device-energy-model.h
     model/energy-harvester.h
     model/energy-source.h
+    model/generic-battery-model.h
     model/li-ion-energy-source.h
     model/rv-battery-model.h
     model/simple-device-energy-model.h
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/doc/energy.rst ns-3.40/src/energy/doc/energy.rst
--- ns-3.39/src/energy/doc/energy.rst	2023-07-05 14:23:47.785427300 -0700
+++ ns-3.40/src/energy/doc/energy.rst	2023-09-27 13:30:37.642839000 -0700
@@ -1,57 +1,58 @@
+.. include:: replace.txt
+.. highlight:: cpp
+.. highlight:: bash
+
 Energy Framework
 ----------------
 
-Energy consumption is a key issue for wireless devices, and wireless
-network researchers often need to investigate the energy consumption
-at a node or in the overall network while running network simulations
-in ns-3. This requires ns-3 to support energy consumption
-modeling. Further, as concepts such as fuel cells and energy
+Energy is a key issue for wireless devices, and network researchers
+often need to investigate the energy consumption at a node or in the
+overall network while running network simulations in |ns3|.
+This requires |ns3| to support an energy framework.
+Further, as concepts such as fuel cells and energy
 scavenging are becoming viable for low power wireless devices,
 incorporating the effect of these emerging technologies into
-simulations requires support for modeling diverse energy sources in
-ns-3. The ns-3 Energy Framework provides the basis for energy
-consumption, energy source and energy harvesting modeling.
+simulations requires support for modeling diverse energy models in
+ns-3. The |ns3| energy framework provides the basis for energy storing
+consumption and harvesting.
 
 
 Model Description
-=================
+*****************
+The framework is implemented into the ``src/energy/`` folder.
+
+The |ns3| energy framework is composed of 3 essential parts:
+
+* **Energy source models.** Represent storing energy sources such as batteries or capacitors.
+
+* **Energy consumption models.** Represent a portion of a device that draws energy from energy sources. Examples of this include sensors, radio transceivers, vehicles, UAV, etc.
+
+* **Energy harvesting models.** Represent devices that provide energy to energy sources. For example, solar panels and chargers.
+
+.. _fig-energyFramework:
+
+.. figure:: figures/energyFramework.*
+
+    |ns3| energy framework
+
+
+Energy Source Models
+====================
 
-The source code for the Energy Framework is currently at: ``src/energy``.
+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).
+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
+the node such that each device energy model can react to this event. Further, each node
+can access the energy source objects for information such as remaining capacity , voltage or
+state of charge (SoC). This enables the implementation of energy aware protocols in ns-3.
 
-Design
-******
+In order to model a wide range of power supplies such as batteries, the energy source must be able to capture characteristics of these supplies. There are 2 important characteristics or effects related to practical batteries:
 
-The ns-3 Energy Framework is composed of 3 parts: Energy Source,
-Device Energy Model and Energy Harvester.  The framework is
-implemented into the ``src/energy/models`` folder.
-
-Energy Source
-#############
-
-The Energy Source represents the power supply on each node. A node can
-have one or more energy sources, and each energy source can be
-connected to multiple device energy models. Connecting an energy
-source to a device energy model implies that the corresponding device
-draws power from the source. The basic functionality of the Energy
-Source is to provide energy for devices on the node. When energy is
-completely drained from the Energy Source, it notifies the devices on
-node such that each device can react to this event. Further, each node
-can access the Energy Source Objects for information such as remaining
-energy or energy fraction (battery level). This enables the
-implementation of energy aware protocols in ns-3.
-
-In order to model a wide range of power supplies such as batteries,
-the Energy Source must be able to capture characteristics of these
-supplies. There are 2 important characteristics or effects related to
-practical batteries:
-
-Rate Capacity Effect
-  Decrease of battery lifetime when the current draw is higher
-  than the rated value of the battery.
-
-Recovery Effect
-  Increase of battery lifetime when the battery is alternating
-  between discharge and idle states.
+* **Rate Capacity Effect.** Decrease of battery lifetime when the current draw is higher than the rated value of the battery.
+* **Recovery Effect.** Increase of battery lifetime when the battery is alternating between discharge and idle states.
 
 In order to incorporate the Rate Capacity Effect, the Energy Source
 uses current draw from all the devices on the same node to calculate
@@ -64,47 +65,108 @@
 new total current draw will be calculated. Similarly, every Energy
 Harvester update triggers an update to the connected Energy Source.
 
-The Energy Source base class keeps a list of devices (Device Energy
-Model objects) and energy harvesters (Energy Harvester 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.
+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
+######################
 
-Device Energy 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),
+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,
+temperature and variable battery impedance is not considered for all batteries. batteries
+with similar discharge behavior might be also represented but one of the 4 basic
+arqueotipes must be chosen.
+
+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'
+discharge curves datasheets.
+
+.. _fig-energyFramework:
+
+.. figure:: figures/dischargeCurve.*
+
+    |ns3| Generic Battery Model Points in battery discharge curve.
+
+The 3 basic set of points that require identification in a datasheet are:
+
+* :math:`V_{full}:` The full battery voltage
+* :math:`Q:` The maximum battery capacity
+
+* :math:`V_{exp}:` The voltage at the end of the exponential zone
+* :math:`Q_{exp}:` The capacity at the end of the exponential zone
+
+* :math:`V_{nom}:` The voltage at the end of the exponential zone
+* :math:`Q_{nom}:` The capacity at the end of the exponential zone
+
+Additionally, it is also necessary to set the values of:
+
+* :math:`R:` The battery impedance (The battery internal resistance)
+* :math:`i_{typical}:` The typical current value used to discharge the battery, this value is used to calculate some of the constants used in the model.
+* :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
+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,
+trial an error adjustments might be necessary to obtain the desired results.
+
+Attributes:
+
+* ``FullVoltage``: Represents the :math:`V_{full}` value.
+* ``MaxCapacity``: Represents the :math:`Q` value.
+* ``ExponentialVoltage``: Represents the :math:`V_{exp}` value.
+* ``ExponentialCapacity``: Represents the :math:`Q_{exp}` value.
+* ``NominalVoltage``: Represents the :math:`V_{nom}` value.
+* ``NominalCapacity``: Represents the :math:`Q_{nom}` value.
+* ``InternalResistance``: Represents the :math:`R` value.
+* ``TypicalDischargeCurrent``: Represents the :math:`i_{typical}` value.
+* ``CutoffVoltage``: The voltage where the battery is considered depleted.
+* ``BatteryType``: Indicates the battery type used.
+* ``PeriodicEnergyUpdateInterval``: Indicates how often the update values are obtained.
+* ``LowBatteryThreshold``: Additional voltage threshold to indicate when the battery has low energy.
+
+The process described above can be simplified by installing batteries presents of previously tested
+batteries using helpers. Details on helpers usage are detailed in the following sections.
 
-The Device Energy Model is the energy consumption model of a device
-installed on the node. It is designed to be a state based model where
-each device is assumed to have a number of states, and each state is
-associated with a power consumption value. Whenever the state of the
-device changes, the corresponding Device Energy Model will notify the
-Energy Source of the new current draw of the device. The Energy Source
-will then calculate the new total current draw and update the
-remaining energy.
-
-The Device Energy Model can also be used for devices that do not have
-finite number of states. For example, in an electric vehicle, the
-current draw of the motor is determined by its speed. Since the
-vehicle's speed can take continuous values within a certain range, it
-is infeasible to define a set of discrete states of
-operation. However, by converting the speed value into current
-directly, the same set of Device Energy Model APIs can still be used.
 
-Energy Harvester
+RV Battery Model
 ################
 
-The energy harvester represents the elements that harvest energy from
-the environment and recharge the Energy Source to which it is
-connected. The energy harvester includes the complete implementation
-of the actual energy harvesting device (e.g., a solar panel) and the
-environment (e.g., the solar radiation). This means that in
-implementing an energy harvester, the energy contribution of the
-environment and the additional energy requirements of the energy
-harvesting device such as the conversion efficiency and the internal
-power consumption of the device needs to be jointly modeled.
+Attributes:
+
+* ``RvBatteryModelPeriodicEnergyUpdateInterval``: RV battery model sampling
+  interval.
+* ``RvBatteryModelOpenCircuitVoltage``: RV battery model open circuit voltage.
+* ``RvBatteryModelCutoffVoltage``: RV battery model cutoff voltage.
+* ``RvBatteryModelAlphaValue``: RV battery model alpha value.
+* ``RvBatteryModelBetaValue``: RV battery model beta value.
+* ``RvBatteryModelNumOfTerms``: The number of terms of the infinite sum for estimating battery level.
+
+Basic Energy Source
+###################
+
+Attributes:
+
+* ``BasicEnergySourceInitialEnergyJ``: Initial energy stored in
+  basic energy source.
+* ``BasicEnergySupplyVoltageV``: Initial supply voltage for basic energy source.
+* ``PeriodicEnergyUpdateInterval``: Time between two consecutive periodic energy updates.
+
+
+Energy Consumption Models
+=========================
 
+A ``DeviceEnergyModel`` is the energy consumption model of a device installed on the node.
+It is designed to be a state based model where each device is assumed to have a number of states, and each state is associated with a power consumption value.
+Whenever the state of the device changes, the corresponding ``DeviceEnergyModel`` will notify the associated ``EnergySourceModel`` of the new current draw of the device.
+The ``EnergySourceModel`` will then calculate the new total current draw and update the remaining energy. A ``DeviceEnergyModel`` can also be used for devices that do not have finite number of states.
+For example, in an electric vehicle, the current draw of the motor is determined by its speed.
+Since the vehicle's speed can take continuous values within a certain range, it is infeasible to define a set of discrete states of operation.
+However, by converting the speed value into current draw directly, the same set of ``DeviceEnergyModel`` APIs can still be used.
 
 WiFi Radio Energy Model
 #######################
@@ -146,53 +208,32 @@
 so that the Wifi PHY is resumed from the OFF mode when the energy
 source is recharged.
 
-Future Work
-***********
-
-For Device Energy Models, we are planning to include support for other
-PHY layer models provided in ns-3 such as WiMAX, and to model the
-energy consumptions of other non communicating devices, like a generic
-sensor and a CPU. For Energy Sources, we are planning to included new
-types of Energy Sources such as Supercapacitor and Nickel-Metal
-Hydride (Ni-MH) battery. For the Energy Harvesters, we are planning to
-implement an energy harvester that recharges the energy sources
-according to the power levels defined in a user customizable dataset
-of real measurements.
+Attributes
 
-References
-**********
+* ``IdleCurrentA``: The default radio Idle current in Ampere.
+* ``CcaBusyCurrentA``: The default radio CCA Busy State current in Ampere.
+* ``TxCurrentA``: The radio Tx current in Ampere.
+* ``RxCurrentA``: The radio Rx current in Ampere.
+* ``SwitchingCurrentA``: The default radio Channel Switch current in Ampere.
+* ``SleepCurrentA``: The radio Sleep current in Ampere.
+* ``TxCurrentModel``: A pointer to the attached tx current model.
 
-[1] ns-2 Energy model:
-    https://web.archive.org/web/20130428021737/http://www.cubinlab.ee.unimelb.edu.au/~jrid/Docs/Manuel-NS2/node204.html
+Energy Harvesting Models
+========================
 
-[2] H. Wu, S. Nabar and R. Poovendran. An Energy Framework for the
-    Network Simulator 3 (ns-3).
+The energy harvester represents the elements that supply energy from
+the environment and recharge an energy source to which it is
+connected. The energy harvester includes the complete implementation
+of the actual energy harvesting device (e.g., a solar panel) and the
+environment (e.g., the solar radiation). This means that in
+implementing an energy harvester, the energy contribution of the
+environment and the additional energy requirements of the energy
+harvesting device such as the conversion efficiency and the internal
+power consumption of the device needs to be jointly modeled.
 
-[3] M. Handy and D. Timmermann. Simulation of mobile wireless
-    networks with accurate modelling of non-linear battery effects. In
-    Proc. of Applied simulation and Modeling (ASM), 2003.
-
-[4] D. N. Rakhmatov and S. B. Vrudhula. An analytical high-level
-    battery model for use in energy management of portable electronic
-    systems. In Proc. of IEEE/ACM International Conference on Computer
-    Aided Design (ICCAD'01), pages 488-493, November 2001.
-
-[5] D. N. Rakhmatov, S. B. Vrudhula, and D. A. Wallach. Battery
-    lifetime prediction for energy-aware computing. In Proc. of the 2002
-    International Symposium on Low Power Electronics and Design
-    (ISLPED'02), pages 154-159, 2002.
-
-[6] C. Tapparello, H. Ayatollahi and W. Heinzelman. Extending the
-    Energy Framework for Network Simulator 3 (ns-3). Workshop on ns-3
-    (WNS3), Poster Session, Atlanta, GA, USA. May, 2014.
-
-[7] C. Tapparello, H. Ayatollahi and W. Heinzelman. Energy Harvesting
-    Framework for Network Simulator 3 (ns-3). 2nd International Workshop on
-    Energy Neutral Sensing Systems (ENSsys), Memphis, TN, USA. November 6,
-    2014.
 
 Usage
-=====
+*****
 
 The main way that ns-3 users will typically interact with the Energy
 Framework is through the helper API and through the publicly visible
@@ -218,122 +259,214 @@
 regarding the current harvestable power and the total energy harvested
 by the harvester.
 
-
-Examples
-********
-
-The example directories, ``src/examples/energy`` and
-``examples/energy``, contain some basic code that shows how to set up
-the framework.
-
 Helpers
-*******
+=======
 
-Energy Source Helper
-####################
+**Energy Source Helper:**
 
 Base helper class for Energy Source objects, this helper Aggregates
 Energy Source object onto a node. Child implementation of this class
 creates the actual Energy Source object.
 
-Device Energy Model Helper
-##########################
+**Device Energy Model Helper:**
 
 Base helper class for Device Energy Model objects, this helper
 attaches Device Energy Model objects onto Energy Source objects. Child
 implementation of this class creates the actual Device Energy Model
 object.
 
-Energy Harvesting Helper
-##########################
+**Energy Harvesting Helper:**
 
 Base helper class for Energy Harvester objects, this helper attaches
 Energy Harvester objects onto Energy Source objects. Child
 implementation of this class creates the actual Energy Harvester
 object.
 
+**Generic Battery Model Helper:**
 
-Attributes
-**********
-
-Attributes differ between Energy Sources, Devices Energy Models and
-Energy Harvesters implementations, please look at the specific child
-class for details.
-
-Basic Energy Source
-###################
-
-* ``BasicEnergySourceInitialEnergyJ``: Initial energy stored in
-  basic energy source.
-* ``BasicEnergySupplyVoltageV``: Initial supply voltage for basic energy source.
-* ``PeriodicEnergyUpdateInterval``: Time between two consecutive periodic
-  energy updates.
-
-RV Battery Model
-################
-
-* ``RvBatteryModelPeriodicEnergyUpdateInterval``: RV battery model sampling
-  interval.
-* ``RvBatteryModelOpenCircuitVoltage``: RV battery model open circuit voltage.
-* ``RvBatteryModelCutoffVoltage``: RV battery model cutoff voltage.
-* ``RvBatteryModelAlphaValue``: RV battery model alpha value.
-* ``RvBatteryModelBetaValue``: RV battery model beta value.
-* ``RvBatteryModelNumOfTerms``: The number of terms of the infinite sum for estimating battery level.
-
-WiFi Radio Energy Model
-#######################
-
-* ``IdleCurrentA``: The default radio Idle current in Ampere.
-* ``CcaBusyCurrentA``: The default radio CCA Busy State current in Ampere.
-* ``TxCurrentA``: The radio Tx current in Ampere.
-* ``RxCurrentA``: The radio Rx current in Ampere.
-* ``SwitchingCurrentA``: The default radio Channel Switch current in Ampere.
-* ``SleepCurrentA``: The radio Sleep current in Ampere.
-* ``TxCurrentModel``: A pointer to the attached tx current model.
-
-Basic Energy Harvester
-#######################
+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).
+Users must use one of the available presets that represent an specific battery.
+
+.. sourcecode:: cpp
+
+   GenericBatteryModelHelper batteryHelper;
+   EnergySourceContainer
+   energySourceContainer = batteryHelper.Install(nodeContainer,
+                                                 PANASONIC_CGR18650DA_LION);
+   batteryHelper.SetCellPack(energySourceContainer,2,2);
+
+In the previous example, the ``GenericBatteryModelHelper`` was used to install a Panasonic CGR18650DA
+Li-Ion battery. Likewise, the helper is used to define a cell pack of 4 batteries. 2 batteries
+connected in series and 2 connected in parallel (2S,2P).
+
+Another option is to manually configure the values that makes the preset:
+
+.. sourcecode:: cpp
+
+   auto node = CreateObject<Node>();
+   auto devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+   batteryModel = CreateObject<GenericBatteryModel>();
+   batteryModel->SetAttribute("FullVoltage", DoubleValue(1.39));            // Qfull
+   batteryModel->SetAttribute("MaxCapacity", DoubleValue(7.0));             // Q
+   batteryModel->SetAttribute("NominalVoltage", DoubleValue(1.18));         // Vnom
+   batteryModel->SetAttribute("NominalCapacity", DoubleValue(6.25));        // QNom
+   batteryModel->SetAttribute("ExponentialVoltage", DoubleValue(1.28));     // Vexp
+   batteryModel->SetAttribute("ExponentialCapacity", DoubleValue(1.3));     // Qexp
+   batteryModel->SetAttribute("InternalResistance", DoubleValue(0.0046));   // R
+   batteryModel->SetAttribute("TypicalDischargeCurrent", DoubleValue(1.3)); // i typical
+   batteryModel->SetAttribute("CutoffVoltage", DoubleValue(1.0));           // End of charge.
+   batteryModel->SetAttribute("BatteryType", EnumValue(NIMH_NICD));         // General battery type
+   batteryModel = DynamicCast<GenericBatteryModel>
+                  (batteryHelper.Install(node,PANASONIC_HHR650D_NIMH));
+   devicesEnergyModel->SetEnergySource(batteryModel);
+   batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+   devicesEnergyModel->SetNode(node);
+
+
+Usage of both of these type of configurations are shown in ``generic-battery-discharge-example.cc``.
+The following table is a list of the available presents in |ns3|:
+
+
++---------------------------+-------------------------------------------------+
+| Preset Name               | Description                                     |
++===========================+=================================================+
+| PANASONIC_CGR18650DA_LION | Panasonic Li-Ion  (3.6V, 2450Ah, Size A)        |
++---------------------------+-------------------------------------------------+
+| PANASONIC_HHR650D_NIMH    | Panasonic NiMh HHR550D (1.2V 6.5Ah, Size D)     |
++---------------------------+-------------------------------------------------+
+| CSB_GP1272_LEADACID       | CSB Lead Acid GP1272 (12V,7.2Ah)                |
++---------------------------+-------------------------------------------------+
+| PANASONIC_N700AAC_NICD    | Panasonic NiCd N-700AAC (1.2V 700mAh, Size: AA) |
++---------------------------+-------------------------------------------------+
+| RSPRO_LGP12100_LEADACID   | Rs Pro Lead Acid LGP12100 (12V, 100Ah)          |
++---------------------------+-------------------------------------------------+
 
-* ``PeriodicHarvestedPowerUpdateInterval``: Time between two consecutive
-  periodic updates of the harvested power.
-* ``HarvestablePower``: Random variables that represents the amount of power
-  that is provided by the energy harvester.
 
 Tracing
-*******
+=======
 
 Traced values differ between Energy Sources, Devices Energy Models and
 Energy Harvesters implementations, please look at the specific child
 class for details.
 
-Basic Energy Source
-###################
+**Basic Energy Source**
 
 * ``RemainingEnergy``: Remaining energy at BasicEnergySource.
 
-RV Battery Model
-################
+**RV Battery Model**
 
 * ``RvBatteryModelBatteryLevel``: RV battery model battery level.
 * ``RvBatteryModelBatteryLifetime``: RV battery model battery lifetime.
 
-WiFi Radio Energy Model
-#######################
+**WiFi Radio Energy Model**
 
 * ``TotalEnergyConsumption``: Total energy consumption of the radio device.
 
-Basic Energy Harvester
-#######################
+**Basic Energy Harvester**
 
 * ``HarvestedPower``: Current power provided by the BasicEnergyHarvester.
 * ``TotalEnergyHarvested``: Total energy harvested by the BasicEnergyHarvester.
 
+Examples
+========
+
+The following examples have been written.
+
+Examples in ``src/energy/examples``:
+
+* ``basic-energy-model-test.cc``: Demonstrates the use of a Basic energy source with a Wifi radio model.
+* ``generic-battery-discharge-example.cc``: Demonstrates the installation of battery energy sources. The output of this example shows the discharge curve of 5 different batteries.
+* ``generic-battery-discharge-example.py``: A simplified version of the previous example but using python bindings.
+* ``generic-battery-wifiradio-example.cc``: Demonstrates the use and installation of the Generic Battery Model with the WifiRadio model.
+* ``rv-battery-model-test.cc``: Discharge example of a RV energy source model.
+
+Examples in ``examples/energy``:
+
+* ``energy-model-example.cc``
+* ``energy-model-with-harvesting-example.cc``: Shows the harvesting model usage. Only usable with basicEnergySources.
+
+
+Tests
+=====
+The following tests have been written, which can be found in ``src/energy/tests/``:
+
 
 Validation
 **********
 
-Comparison of the Energy Framework against actual devices have not
-been performed. Current implementation of the Energy Framework is
-checked numerically for computation errors. The RV battery model is
-validated by comparing results with what was presented in the original
-RV battery model paper.
+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:
+
+
+.. _fig-leadacid:
+
+.. figure:: figures/leadacid.*
+
+    Lead acid battery discharge curve (CSB GP1272)
+
+.. _fig-liion:
+
+.. figure:: figures/liion.*
+
+    Li-Ion battery discharge curve (Panasonic CGR18650DA)
+
+.. _fig-nicd:
+
+.. figure:: figures/nicd.*
+
+    NiCd battery discharge curve (Panasonic N-700AAC)
+
+.. _fig-nimh:
+
+.. figure:: figures/nimh.*
+
+    NiMH battery discharge curve (Panasonic HHR650D)
+
+
+
+Scope and Limitations
+=====================
+
+* In the ``GenericBatteryModel`` charging behavior (voltage as a function of SoC) is included but is not been thoroughly tested. Testing requires the implementation of a harvesting device (A charger) capable of providing a CCCV charging method typically used in batteries.
+* In the ``GenericBatteryModel`` impedance (battery resistance) is constant, battery aging or temperature effects are not considered.
+* The Rv battery model has some reported issues (See: issue #164)
+* The harvesting mode can only be used with basic energy sources because it does not consider the current capacity or voltage of the battery.
+
+Future Work
+===========
+
+* 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 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.
+
+References
+==========
+
+Energy source models and energy consumption models:
+
+[`1 <https://labs.ece.uw.edu/nsl/papers/SIMUTools-11.pdf>`_] H. Wu, S. Nabar and R. Poovendran. An Energy Framework for the Network Simulator 3 (ns-3).
+
+[2] M. Handy and D. Timmermann. Simulation of mobile wireless networks with accurate modelling of non-linear battery effects. In Proc. of Applied simulation and Modeling (ASM), 2003.
+
+[3] D. N. Rakhmatov and S. B. Vrudhula. An analytical high-level battery model for use in energy management of portable electronic systems. In Proc. of IEEE/ACM International Conference on Computer Aided Design (ICCAD'01), pages 488-493, November 2001.
+
+[4] D. N. Rakhmatov, S. B. Vrudhula, and D. A. Wallach. Battery lifetime prediction for energy-aware computing. In Proc. of the 2002 International Symposium on Low Power Electronics and Design (ISLPED'02), pages 154-159, 2002.
+
+[`5 <https://www.mdpi.com/2032-6653/3/2/289>`_] Olivier Tremblay and Louis-A. Dessaint. 2009. Experimental Validation of a Battery Dynamic Model for EV Applications. World Electric Vehicle Journal 3, 2 (2009), 289–298. https://doi.org/10.3390/wevj3020289
+
+[`6 <https://ieeexplore.ieee.org/document/4544139>`_] Olivier Tremblay, Louis-A. Dessaint, and Abdel-Illah Dekkiche. 2007. A Generic Battery Model for the Dynamic Simulation of Hybrid Electric Vehicles. In 2007 IEEE Vehicle Power and Propulsion Conference. 284–289. https://doi.org/10.1109/VPPC.2007.4544139
+
+[`7 <https://www.mathworks.com/help/sps/powersys/ref/battery.html>`_]  MatWorks SimuLink Generic Battery Model
+
+[8] C. M. Shepherd. 1965. Design of Primary and Secondary Cells: II . An Equation Describing Battery Discharge. Journal of The Electrochemical Society 112, 7 (jul 1965), 657. https://doi.org/10.1149/1.2423659
+
+[`9 <https://dl.acm.org/doi/abs/10.1145/3592149.3592156>`_] Alberto Gallegos Ramonet, Alexander Guzman Urbina, and Kazuhiko Kinoshita. 2023. Evaluation and Extension of ns-3 Battery Framework. In Proceedings of the 2023 Workshop on ns-3 (WNS3 '23). Association for Computing Machinery, New York, NY, USA, 102–108. https://doi.org/10.1145/3592149.3592156
+
+
+Energy Harvesting Models:
+
+[10] C. Tapparello, H. Ayatollahi and W. Heinzelman. Extending the Energy Framework for Network Simulator 3 (ns-3). Workshop on ns-3 (WNS3), Poster Session, Atlanta, GA, USA. May, 2014.
+
+[11] C. Tapparello, H. Ayatollahi and W. Heinzelman. Energy Harvesting Framework for Network Simulator 3 (ns-3). 2nd International Workshop on Energy Neutral Sensing Systems (ENSsys), Memphis, TN, USA. November 6, 2014.
+
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/examples/basic-energy-model-test.cc ns-3.40/src/energy/examples/basic-energy-model-test.cc
--- ns-3.39/src/energy/examples/basic-energy-model-test.cc	2023-07-05 14:23:47.785427300 -0700
+++ ns-3.40/src/energy/examples/basic-energy-model-test.cc	2023-09-27 13:30:37.642839000 -0700
@@ -91,35 +91,35 @@
     // run state switch tests
     if (StateSwitchTest(WifiPhyState::IDLE))
     {
-        return 1;
+        return true;
         std::cerr << "Problem with state switch test (WifiPhy idle)." << std::endl;
     }
     if (StateSwitchTest(WifiPhyState::CCA_BUSY))
     {
-        return 1;
+        return true;
         std::cerr << "Problem with state switch test (WifiPhy cca busy)." << std::endl;
     }
     if (StateSwitchTest(WifiPhyState::TX))
     {
-        return 1;
+        return true;
         std::cerr << "Problem with state switch test (WifiPhy tx)." << std::endl;
     }
     if (StateSwitchTest(WifiPhyState::RX))
     {
-        return 1;
+        return true;
         std::cerr << "Problem with state switch test (WifiPhy rx)." << std::endl;
     }
     if (StateSwitchTest(WifiPhyState::SWITCHING))
     {
-        return 1;
+        return true;
         std::cerr << "Problem with state switch test (WifiPhy switching)." << std::endl;
     }
     if (StateSwitchTest(WifiPhyState::SLEEP))
     {
-        return 1;
+        return true;
         std::cerr << "Problem with state switch test (WifiPhy sleep)." << std::endl;
     }
-    return 0;
+    return false;
 }
 
 bool
@@ -302,7 +302,7 @@
     /*
      * Run simulation with different simulation time and update interval.
      */
-    uint8_t ret = 0;
+    bool ret = false;
 
     for (double simTimeS = 0.0; simTimeS <= m_simTimeS; simTimeS += m_timeStepS)
     {
@@ -311,7 +311,7 @@
         {
             if (DepletionTestCase(simTimeS, updateIntervalS))
             {
-                ret = 1;
+                ret = true;
                 std::cerr << "Depletion test case problem." << std::endl;
             }
             // reset callback count
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/examples/CMakeLists.txt ns-3.40/src/energy/examples/CMakeLists.txt
--- ns-3.39/src/energy/examples/CMakeLists.txt	2023-07-05 14:23:47.785427300 -0700
+++ ns-3.40/src/energy/examples/CMakeLists.txt	2023-09-27 13:30:37.642839000 -0700
@@ -1,4 +1,23 @@
 build_lib_example(
+  NAME generic-battery-discharge-example
+  SOURCE_FILES generic-battery-discharge-example.cc
+  LIBRARIES_TO_LINK ${libcore}
+                    ${libenergy}
+)
+
+build_example(
+  NAME generic-battery-wifiradio-example
+  SOURCE_FILES generic-battery-wifiradio-example.cc
+  LIBRARIES_TO_LINK
+    ${libcore}
+    ${libconfig-store}
+    ${libenergy}
+    ${libinternet}
+    ${libmobility}
+    ${libwifi}
+)
+
+build_lib_example(
   NAME li-ion-energy-source-example
   SOURCE_FILES li-ion-energy-source-example.cc
   LIBRARIES_TO_LINK ${libcore}
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/examples/generic-battery-discharge-example.cc ns-3.40/src/energy/examples/generic-battery-discharge-example.cc
--- ns-3.39/src/energy/examples/generic-battery-discharge-example.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/src/energy/examples/generic-battery-discharge-example.cc	2023-09-27 13:30:37.642839000 -0700
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2023 Tokushima University
+ *
+ * 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>
+ */
+
+#include <ns3/core-module.h>
+#include <ns3/energy-module.h>
+#include <ns3/gnuplot.h>
+
+#include <fstream>
+#include <sstream>
+#include <string>
+
+using namespace ns3;
+
+/**
+ * This example shows the use of batteries in ns-3.
+ * 5 batteries of different chemistries are discharged
+ * using a constant current. Batteries can be configured
+ * manually using the necessary parameters or using
+ * presets.
+ *
+ * In this example, only the first battery uses parameters
+ * to form a NiMh battery. The rest of the batteries in this
+ * example use defined presets with already tested parameters.
+ *
+ * Users can make their own battery presets by setting
+ * the necessary parameters as in the example in the first
+ * battery.
+ *
+ * Plot files are produced as a result of this example.
+ * Graphs can be obtained from the plot using:
+ *
+ * $> gnuplot <plotname>.plt
+ */
+
+Gnuplot battDischPlot1 = Gnuplot("BattDisch1.eps");
+Gnuplot2dDataset battDischDataset1;
+std::ofstream battDischFile1("BattDischCurve1.plt");
+
+Gnuplot battDischPlot2 = Gnuplot("BattDisch2.eps");
+Gnuplot2dDataset battDischDataset2;
+std::ofstream battDischFile2("BattDischCurve2.plt");
+
+Gnuplot battDischPlot3 = Gnuplot("BattDisch3.eps");
+Gnuplot2dDataset battDischDataset3;
+std::ofstream battDischFile3("BattDischCurve3.plt");
+
+Gnuplot battDischPlot4 = Gnuplot("BattDisch4.eps");
+Gnuplot2dDataset battDischDataset4;
+std::ofstream battDischFile4("BattDischCurve4.plt");
+
+Gnuplot battDischPlot5 = Gnuplot("BattDisch5.eps");
+Gnuplot2dDataset battDischDataset5;
+std::ofstream battDischFile5("BattDischCurve5.plt");
+
+void
+GraphBattery1(Ptr<GenericBatteryModel> es)
+{
+    // NiMh battery  Panasonic HHR650D NiMH
+    double cellVoltage = es->GetSupplyVoltage();
+    Time currentTime = Simulator::Now();
+    battDischDataset1.Add(currentTime.GetMinutes(), cellVoltage);
+    // battDischDataset1.Add(currentTime.GetHours(), cellVoltage);
+
+    if (!Simulator::IsFinished())
+    {
+        Simulator::Schedule(Seconds(20), &GraphBattery1, es);
+    }
+}
+
+void
+GraphBattery2(Ptr<GenericBatteryModel> es)
+{
+    // CSB GP1272 Lead Acid
+    double cellVoltage = es->GetSupplyVoltage();
+    Time currentTime = Simulator::Now();
+    battDischDataset2.Add(currentTime.GetMinutes(), cellVoltage);
+    // battDischDataset2.Add(currentTime.GetHours(), cellVoltage);
+
+    if (!Simulator::IsFinished())
+    {
+        Simulator::Schedule(Seconds(20), &GraphBattery2, es);
+    }
+}
+
+void
+GraphBattery3(Ptr<GenericBatteryModel> es)
+{
+    // Panasonic CGR18650DA Li-on
+    double cellVoltage = es->GetSupplyVoltage();
+    double dischargeCapacityAh = es->GetDrainedCapacity();
+    battDischDataset3.Add(dischargeCapacityAh * 1000, cellVoltage);
+
+    if (!Simulator::IsFinished())
+    {
+        Simulator::Schedule(Seconds(20), &GraphBattery3, es);
+    }
+}
+
+void
+GraphBattery4(Ptr<GenericBatteryModel> es)
+{
+    // Rs Pro LGP12100 Lead Acid
+    double cellVoltage = es->GetSupplyVoltage();
+    Time currentTime = Simulator::Now();
+    battDischDataset4.Add(currentTime.GetMinutes(), cellVoltage);
+    // battDischDataset4.Add(currentTime.GetHours(), cellVoltage);
+
+    if (!Simulator::IsFinished())
+    {
+        Simulator::Schedule(Seconds(20), &GraphBattery4, es);
+    }
+}
+
+void
+GraphBattery5(Ptr<GenericBatteryModel> es)
+{
+    // Panasonic N-700AAC NiCd
+    double cellVoltage = es->GetSupplyVoltage();
+    Time currentTime = Simulator::Now();
+    // battDischDataset5.Add(currentTime.GetMinutes(), cellVoltage);
+    battDischDataset5.Add(currentTime.GetHours(), cellVoltage);
+
+    if (!Simulator::IsFinished())
+    {
+        Simulator::Schedule(Seconds(20), &GraphBattery5, es);
+    }
+}
+
+int
+main(int argc, char** argv)
+{
+    CommandLine cmd(__FILE__);
+    cmd.Parse(argc, argv);
+
+    LogComponentEnable("GenericBatteryModel", LOG_LEVEL_DEBUG);
+
+    Ptr<Node> node;
+    GenericBatteryModelHelper batteryHelper;
+    Ptr<GenericBatteryModel> batteryModel;
+    Ptr<SimpleDeviceEnergyModel> devicesEnergyModel;
+
+    //////////////////////// PANASONIC HHR650D NiMH discharge 1C,2C,5C ////////////////////
+
+    // Discharge 6.5A (1C)
+    battDischDataset1 = Gnuplot2dDataset("Panasonic NiMH HHR650D 6.5 A (1C)");
+
+    node = CreateObject<Node>();
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    batteryModel = CreateObject<GenericBatteryModel>();
+
+    batteryModel->SetAttribute("FullVoltage", DoubleValue(1.39)); // Vfull
+    batteryModel->SetAttribute("MaxCapacity", DoubleValue(7.0));  // Q
+
+    batteryModel->SetAttribute("NominalVoltage", DoubleValue(1.18));  // Vnom
+    batteryModel->SetAttribute("NominalCapacity", DoubleValue(6.25)); // QNom
+
+    batteryModel->SetAttribute("ExponentialVoltage", DoubleValue(1.28)); // Vexp
+    batteryModel->SetAttribute("ExponentialCapacity", DoubleValue(1.3)); // Qexp
+
+    batteryModel->SetAttribute("InternalResistance", DoubleValue(0.0046));   // R
+    batteryModel->SetAttribute("TypicalDischargeCurrent", DoubleValue(1.3)); // i typical
+    batteryModel->SetAttribute("CutoffVoltage", DoubleValue(1.0));           // End of charge.
+
+    // Capacity Ah(qMax) * (Vfull) voltage * 3600 = (7 * 1.39 * 3.6) = 35028
+    batteryModel->SetAttribute("BatteryType", EnumValue(NIMH_NICD)); // Battery type
+
+    // The Generic battery model allow users to simulate different types of
+    // batteries based on some parameters. However, presets of batteries are
+    // included in ns-3, for example, the previous battery values can be
+    // configured using a helper to set a NiMh battery preset:
+
+    // batteryModel = DynamicCast<GenericBatteryModel>
+    //                (batteryHelper.Install(node,PANASONIC_HHR650D_NIMH));
+
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(6.5);
+
+    GraphBattery1(batteryModel);
+
+    battDischPlot1.AddDataset(battDischDataset1);
+    // 18717 secs around 5.3hrs, 750secs for 32.5 current, or   (4200 70 mins)
+    Simulator::Stop(Seconds(3600));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    // Discharge 13A (2C)
+    battDischDataset1 = Gnuplot2dDataset("Panasonic NiMH HHR650D 13 A (2C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, PANASONIC_HHR650D_NIMH));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(13);
+
+    GraphBattery1(batteryModel);
+
+    battDischPlot1.AddDataset(battDischDataset1);
+    Simulator::Stop(Seconds(1853));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    // Discharge 32.5A (5C)
+    battDischDataset1 = Gnuplot2dDataset("Panasonic NiMH HHR650D 32.5 A (5C)");
+    node = CreateObject<Node>();
+    batteryModel = CreateObject<GenericBatteryModel>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, PANASONIC_HHR650D_NIMH));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(32.5);
+
+    GraphBattery1(batteryModel);
+    battDischPlot1.AddDataset(battDischDataset1);
+
+    Simulator::Stop(Seconds(716));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    battDischPlot1.SetTerminal("postscript eps color enh \"Times-BoldItalic\"");
+    battDischPlot1.SetLegend(" Time (minutes)", "Voltage (V)");
+    battDischPlot1.SetExtra("set xrange[0:70]\n\
+                               set yrange [0.8:1.8]\n\
+                               set xtics 10\n\
+                               set ytics 0.1\n\
+                               set grid\n\
+                               set style line 1 linewidth 5\n\
+                               set style line 2 linewidth 5\n\
+                               set style line 3 linewidth 5\n\
+                               set style line 4 linewidth 5\n\
+                               set style line 5 linewidth 5\n\
+                               set style line 6 linewidth 5\n\
+                               set style line 7 linewidth 5\n\
+                               set style line 8 linewidth 5\n\
+                               set style increment user\n\
+                               set key reverse Left");
+
+    battDischPlot1.GenerateOutput(battDischFile1);
+    battDischFile1.close();
+    std::cout << "The end, plotting now\n";
+
+    //////////////////////// CSB GP1272 Lead Acid  discharge 0.5C, 0.9C ////////////
+
+    // Discharge 0.36A (0.05C)
+    battDischDataset2 = Gnuplot2dDataset("CSB GP1272 0.36 A (0.05C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, CSB_GP1272_LEADACID));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(0.36);
+
+    GraphBattery2(batteryModel);
+    battDischPlot2.AddDataset(battDischDataset2);
+
+    Simulator::Stop(Seconds(55000));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    // Discharge 0.648A (0.09C)
+    battDischDataset2 = Gnuplot2dDataset("CSB GP1272 0.648 A (0.09C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, CSB_GP1272_LEADACID));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(0.648);
+
+    GraphBattery2(batteryModel);
+    battDischPlot2.AddDataset(battDischDataset2);
+
+    Simulator::Stop(Seconds(30000));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    battDischPlot2.SetTerminal("postscript eps color enh \"Times-BoldItalic\"");
+    battDischPlot2.SetLegend(" Time (Minutes)", "Voltage (V)");
+    battDischPlot2.SetExtra("set xrange[1:1800]\n\
+                               set yrange [7:14]\n\
+                               set logscale x \n\
+                               set tics scale 3\n\
+                               set xtics (1,2,3,5,10,20,30,60,120,180,300,600,1200,1800)\n\
+                               set ytics (0,8,9,10,11,12,13,14)\n\
+                               set grid\n\
+                               set style line 1 linewidth 5\n\
+                               set style line 2 linewidth 5\n\
+                               set style line 3 linewidth 5\n\
+                               set style line 4 linewidth 5\n\
+                               set style line 5 linewidth 5\n\
+                               set style line 6 linewidth 5\n\
+                               set style line 7 linewidth 5\n\
+                               set style line 8 linewidth 5\n\
+                               set style increment user\n\
+                               set key reverse Left");
+    battDischPlot2.GenerateOutput(battDischFile2);
+    battDischFile2.close();
+    std::cout << "The end, plotting now\n";
+
+    //////////////////////// Panasonic Li-on CGR18650DA,  discharge 0.2C,1C,2C  ///////////
+
+    // Discharge 0.466A (0.2C)
+    battDischDataset3 = Gnuplot2dDataset("Panasonic Li-on CGR18650DA 0.466 A (0.2C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, PANASONIC_CGR18650DA_LION));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(0.466);
+
+    GraphBattery3(batteryModel);
+    battDischPlot3.AddDataset(battDischDataset3);
+
+    Simulator::Stop(Seconds(17720));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    // Discharge 2.33A (1C)
+    battDischDataset3 = Gnuplot2dDataset("Panasonic Li-on CGR18650DA 2.33 A (1C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, PANASONIC_CGR18650DA_LION));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(2.33);
+
+    GraphBattery3(batteryModel);
+    battDischPlot3.AddDataset(battDischDataset3);
+
+    Simulator::Stop(Seconds(3528));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    // Discharge 4.66A (2C)
+    battDischDataset3 = Gnuplot2dDataset("Panasonic Li-on CGR18650DA 4.66 A (2C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, PANASONIC_CGR18650DA_LION));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(4.66);
+
+    GraphBattery3(batteryModel);
+    battDischPlot3.AddDataset(battDischDataset3);
+
+    Simulator::Stop(Seconds(1744));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    battDischPlot3.SetTerminal("postscript eps color enh \"Times-BoldItalic\"");
+    battDischPlot3.SetLegend(" Discharge Capacity (mAh)", "Voltage (V)");
+    battDischPlot3.SetExtra("set xrange[0:2400]\n\
+                               set yrange [2.6:4.4]\n\
+                               set xtics 400\n\
+                               set ytics 0.2\n\
+                               set grid\n\
+                               set style line 1 linewidth 5\n\
+                               set style line 2 linewidth 5\n\
+                               set style line 3 linewidth 5\n\
+                               set style line 4 linewidth 5\n\
+                               set style line 5 linewidth 5\n\
+                               set style line 6 linewidth 5\n\
+                               set style line 7 linewidth 5\n\
+                               set style line 8 linewidth 5\n\
+                               set style increment user\n\
+                               set key reverse Left");
+    battDischPlot3.GenerateOutput(battDischFile3);
+    battDischFile3.close();
+    std::cout << "The end, plotting now\n";
+
+    //////////////////////// Rs PRO LGP12100 Lead Acid  discharge 0.05C, 1C ///////////////
+
+    // Discharge 0.36A (0.05C)
+    battDischDataset4 = Gnuplot2dDataset("Rs PRO LGP12100  5A (0.05C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, RSPRO_LGP12100_LEADACID));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(5);
+
+    GraphBattery4(batteryModel);
+    battDischPlot4.AddDataset(battDischDataset4);
+
+    Simulator::Stop(Seconds(65000));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    // Discharge 100A (1C)
+    battDischDataset4 = Gnuplot2dDataset("Rs PRO LGP12100  100A (1C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, RSPRO_LGP12100_LEADACID));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(100);
+
+    GraphBattery4(batteryModel);
+    battDischPlot4.AddDataset(battDischDataset4);
+
+    Simulator::Stop(Seconds(2800));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    battDischPlot4.SetTerminal("postscript eps color enh \"Times-BoldItalic\"");
+    battDischPlot4.SetLegend(" Time (Minutes)", "Voltage (V)");
+    battDischPlot4.SetExtra("set xrange[1:1800]\n\
+                               set yrange [7:13]\n\
+                               set logscale \n\
+                               set tics scale 3\n\
+                               set xtics (1,2,4,6,8,10,20,40,60,120,240,360,480,600,1200)\n\
+                               set ytics (7,8,9,10,11,12,13)\n\
+                               set grid\n\
+                               set style line 1 linewidth 5\n\
+                               set style line 2 linewidth 5\n\
+                               set style line 3 linewidth 5\n\
+                               set style line 4 linewidth 5\n\
+                               set style line 5 linewidth 5\n\
+                               set style line 6 linewidth 5\n\
+                               set style line 7 linewidth 5\n\
+                               set style line 8 linewidth 5\n\
+                               set style increment user\n\
+                               set key reverse Left");
+    battDischPlot4.GenerateOutput(battDischFile4);
+    battDischFile4.close();
+    std::cout << "The end, plotting now\n";
+
+    //////////////////////// Panasonic N-700AAC NiCd discharge  ///////////////////////////
+
+    // Discharge 0.7A (0.1C)
+    battDischDataset5 = Gnuplot2dDataset("Panasonic N-700AAC  0.7A (0.01C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, PANASONIC_N700AAC_NICD));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(0.07);
+
+    GraphBattery5(batteryModel);
+    battDischPlot5.AddDataset(battDischDataset5);
+
+    Simulator::Stop(Seconds(38500));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    // Discharge 0.14A (0.2C)
+    battDischDataset5 = Gnuplot2dDataset("Panasonic N-700AAC 0.14A (0.2C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, PANASONIC_N700AAC_NICD));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(0.14);
+
+    GraphBattery5(batteryModel);
+    battDischPlot5.AddDataset(battDischDataset5);
+
+    Simulator::Stop(Seconds(19200));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    // Discharge 0.35A (0.5C)
+    battDischDataset5 = Gnuplot2dDataset("Panasonic N-700AAC 0.35A (0.5C)");
+    node = CreateObject<Node>();
+    batteryModel =
+        DynamicCast<GenericBatteryModel>(batteryHelper.Install(node, PANASONIC_N700AAC_NICD));
+
+    devicesEnergyModel = CreateObject<SimpleDeviceEnergyModel>();
+    devicesEnergyModel->SetEnergySource(batteryModel);
+    batteryModel->AppendDeviceEnergyModel(devicesEnergyModel);
+    devicesEnergyModel->SetNode(node);
+
+    devicesEnergyModel->SetCurrentA(0.35);
+
+    GraphBattery5(batteryModel);
+    battDischPlot5.AddDataset(battDischDataset5);
+
+    Simulator::Stop(Seconds(7700));
+    Simulator::Run();
+    Simulator::Destroy();
+
+    battDischPlot5.SetTerminal("postscript eps color enh \"Times-BoldItalic\"");
+    battDischPlot5.SetLegend(" Time (Hours)", "Voltage (V)");
+    battDischPlot5.SetExtra("set xrange[0:16]\n\
+                            set yrange [0.7:1.5]\n\
+                            set tics scale 3\n\
+                            set xtics 2\n\
+                            set ytics 0.1\n\
+                            set grid\n\
+                            set style line 1 linewidth 5\n\
+                            set style line 2 linewidth 5\n\
+                            set style line 3 linewidth 5\n\
+                            set style line 4 linewidth 5\n\
+                            set style line 5 linewidth 5\n\
+                            set style line 6 linewidth 5\n\
+                            set style line 7 linewidth 5\n\
+                            set style line 8 linewidth 5\n\
+                            set style increment user\n\
+                            set key reverse Left");
+    battDischPlot5.GenerateOutput(battDischFile5);
+    battDischFile5.close();
+    std::cout << "The end, plotting now\n";
+    return 0;
+}
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/examples/generic-battery-discharge-example.py ns-3.40/src/energy/examples/generic-battery-discharge-example.py
--- ns-3.39/src/energy/examples/generic-battery-discharge-example.py	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/src/energy/examples/generic-battery-discharge-example.py	2023-09-27 13:30:37.642839000 -0700
@@ -0,0 +1,70 @@
+# Copyright (c) 2023 Tokushima University
+#
+# 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>
+#
+
+#  Panasonic HHR650D NiMh battery (single cell)
+#  Demonstrates the discharge behavior of a NIMH battery discharged with a
+#  constant current of 6.5 A (1C)
+
+from ns import ns
+
+def main(argv):
+    """The main function in this Battery discharge example
+
+    Parameters:
+    argv: System parameters to use if necessary
+    """
+
+    ns.core.LogComponentEnable("GenericBatteryModel", ns.core.LOG_LEVEL_DEBUG)
+
+    node = ns.network.Node()
+    batteryHelper =  ns.energy.GenericBatteryModelHelper()
+    batteryModel = ns.CreateObject("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("NominalVoltage", ns.core.DoubleValue(1.18))  # Vnom
+    batteryModel.SetAttribute("NominalCapacity", ns.core.DoubleValue(6.25)) # QNom
+
+    batteryModel.SetAttribute("ExponentialVoltage", ns.core.DoubleValue(1.28)) # Vexp
+    batteryModel.SetAttribute("ExponentialCapacity", ns.core.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
+
+    devicesEnergyModel.SetEnergySource(batteryModel)
+    batteryModel.AppendDeviceEnergyModel(devicesEnergyModel)
+    devicesEnergyModel.SetNode(node)
+
+    devicesEnergyModel.SetCurrentA(6.5)
+
+
+    ns.core.Simulator.Stop(ns.core.Seconds(3600))
+    ns.core.Simulator.Run()
+    ns.core.Simulator.Destroy()
+
+
+
+if __name__ == '__main__':
+    import sys
+    main(sys.argv)
+
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/examples/generic-battery-wifiradio-example.cc ns-3.40/src/energy/examples/generic-battery-wifiradio-example.cc
--- ns-3.39/src/energy/examples/generic-battery-wifiradio-example.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/src/energy/examples/generic-battery-wifiradio-example.cc	2023-09-27 13:30:37.642839000 -0700
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2023 Tokushima University, 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>
+ */
+
+/*
+ *  Node 1 <-------------- distanceToRx ------------> Node2
+ *  (SoC 89%)                                        (SoC 95%)
+ *
+ *  This example is based on the basic-energy-model-test created by He Wu.
+ *  The objective is to demonstrate the use of a GenericBatteryModel with
+ *  the WifiRadioEnergyModel. The WifiRadioEnergyModel was created to work
+ *  specifically with the BasicEnergySource, therefore, the current example
+ *  should be considered a prototype until WifiRadioEnergyModel can be
+ *  revised and thoroughly tested with the GenericBatterySource.
+ *
+ *  In the example, 2 wifi nodes are created each with a GenericBatterySource
+ *  (Li-Ion battery type) is created with 4 cells (2 series, 2 parallel).
+ *  The simulation runs for 3600 secs. Tx, Rx and Idle consumption values
+ *  have been exaggerated for demonstration purposes. At the end of the simulation,
+ *  the State of Charge (Soc %) and remaining capacity in Jouls for each node is
+ *  displayed.
+ *
+ */
+
+#include <ns3/core-module.h>
+#include <ns3/energy-module.h>
+#include <ns3/internet-module.h>
+#include <ns3/mobility-module.h>
+#include <ns3/network-module.h>
+#include <ns3/wifi-module.h>
+
+#include <sstream>
+#include <string>
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE("GenericBatteryWifiRadioExample");
+
+/**
+ * Print a received packet
+ *
+ * \param from sender address
+ * \return a string with the details of the packet: dst {IP, port}, time.
+ */
+inline std::string
+PrintReceivedPacket(Address& from)
+{
+    InetSocketAddress iaddr = InetSocketAddress::ConvertFrom(from);
+
+    std::ostringstream oss;
+    oss << " Received one packet! Socket: " << iaddr.GetIpv4() << " port: " << iaddr.GetPort()
+        << "\n";
+
+    return oss.str();
+}
+
+/**
+ * \param socket Pointer to socket.
+ *
+ * Packet receiving sink.
+ */
+void
+ReceivePacket(Ptr<Socket> socket)
+{
+    Ptr<Packet> packet;
+    Address from;
+    while ((packet = socket->RecvFrom(from)))
+    {
+        if (packet->GetSize() > 0)
+        {
+            NS_LOG_DEBUG(PrintReceivedPacket(from));
+        }
+    }
+}
+
+/**
+ * \param socket Pointer to socket.
+ * \param pktSize Packet size.
+ * \param n Pointer to node.
+ * \param pktCount Number of packets to generate.
+ * \param pktInterval Packet sending interval.
+ *
+ * Generate Traffic
+ */
+static void
+GenerateTraffic(Ptr<Socket> socket,
+                uint32_t pktSize,
+                Ptr<Node> n,
+                uint32_t pktCount,
+                Time pktInterval)
+{
+    if (pktCount > 0)
+    {
+        socket->Send(Create<Packet>(pktSize));
+        Simulator::Schedule(pktInterval,
+                            &GenerateTraffic,
+                            socket,
+                            pktSize,
+                            n,
+                            pktCount - 1,
+                            pktInterval);
+    }
+    else
+    {
+        socket->Close();
+    }
+}
+
+/**
+ * Trace function for remaining energy at node.
+ *
+ * \param oldValue Old value
+ * \param remainingEnergy New value
+ */
+void
+RemainingEnergy(double oldValue, double remainingEnergy)
+{
+    NS_LOG_DEBUG(" Remaining energy Node 1 = " << remainingEnergy << " J");
+}
+
+int
+main(int argc, char* argv[])
+{
+    LogComponentEnableAll(LogLevel(LOG_PREFIX_TIME | LOG_PREFIX_FUNC));
+    LogComponentEnable("GenericBatteryWifiRadioExample", LOG_LEVEL_DEBUG);
+
+    std::string phyMode("DsssRate1Mbps");
+    double rss = -80;          // dBm
+    uint32_t packetSize = 200; // bytes
+    bool verbose = false;
+
+    // simulation parameters
+    uint32_t numPackets = 10000; // number of packets to send
+    double interval = 1;         // seconds
+    double startTime = 0.0;      // seconds
+    double distanceToRx = 100.0; // meters
+
+    CommandLine cmd(__FILE__);
+    cmd.AddValue("phyMode", "Wifi Phy mode", phyMode);
+    cmd.AddValue("rss", "Intended primary RSS (dBm)", rss);
+    cmd.AddValue("packetSize", "size of application packet sent (Bytes)", packetSize);
+    cmd.AddValue("numPackets", "Total number of packets to send", numPackets);
+    cmd.AddValue("startTime", "Simulation start time (seconds)", startTime);
+    cmd.AddValue("distanceToRx", "X-Axis distance between nodes (meters)", distanceToRx);
+    cmd.AddValue("verbose", "Turn on all device log components", verbose);
+    cmd.Parse(argc, argv);
+
+    Time interPacketInterval = Seconds(interval);
+
+    Config::SetDefault("ns3::WifiRemoteStationManager::FragmentationThreshold",
+                       StringValue("2200"));
+    Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue("2200"));
+    Config::SetDefault("ns3::WifiRemoteStationManager::NonUnicastMode", StringValue(phyMode));
+
+    NodeContainer nodeContainer;
+    nodeContainer.Create(2);
+
+    WifiHelper wifi;
+    if (verbose)
+    {
+        WifiHelper::EnableLogComponents();
+    }
+    wifi.SetStandard(WIFI_STANDARD_80211b);
+
+    ////////////////////////
+    // Wifi PHY and MAC   //
+    ////////////////////////
+
+    YansWifiPhyHelper wifiPhy;
+    YansWifiChannelHelper wifiChannel;
+    wifiChannel.SetPropagationDelay("ns3::ConstantSpeedPropagationDelayModel");
+    wifiChannel.AddPropagationLoss("ns3::FriisPropagationLossModel");
+
+    Ptr<YansWifiChannel> wifiChannelPtr = wifiChannel.Create();
+    wifiPhy.SetChannel(wifiChannelPtr);
+
+    WifiMacHelper wifiMac;
+    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
+                                 "DataMode",
+                                 StringValue(phyMode),
+                                 "ControlMode",
+                                 StringValue(phyMode));
+
+    wifiMac.SetType("ns3::AdhocWifiMac");
+    NetDeviceContainer devices = wifi.Install(wifiPhy, wifiMac, nodeContainer);
+
+    //////////////////
+    //   Mobility   //
+    //////////////////
+
+    MobilityHelper mobility;
+    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
+    positionAlloc->Add(Vector(0.0, 0.0, 0.0));
+    positionAlloc->Add(Vector(2 * distanceToRx, 0.0, 0.0));
+    mobility.SetPositionAllocator(positionAlloc);
+    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
+    mobility.Install(nodeContainer);
+
+    //////////////////////
+    //  Energy Model    //
+    //////////////////////
+
+    // Use a preset PANASONIC Li-Ion batteries arranged in a cell pack (2 series, 2 parallel)
+    GenericBatteryModelHelper batteryHelper;
+    EnergySourceContainer energySourceContainer =
+        batteryHelper.Install(nodeContainer, PANASONIC_CGR18650DA_LION);
+    batteryHelper.SetCellPack(energySourceContainer, 2, 2);
+
+    Ptr<GenericBatteryModel> battery0 =
+        DynamicCast<GenericBatteryModel>(energySourceContainer.Get(0));
+    Ptr<GenericBatteryModel> battery1 =
+        DynamicCast<GenericBatteryModel>(energySourceContainer.Get(1));
+
+    // Energy consumption quantities have been exaggerated for
+    // demonstration purposes, real consumption values are much smaller.
+    WifiRadioEnergyModelHelper radioEnergyHelper;
+    radioEnergyHelper.Set("TxCurrentA", DoubleValue(4.66));
+    radioEnergyHelper.Set("RxCurrentA", DoubleValue(0.466));
+    radioEnergyHelper.Set("IdleCurrentA", DoubleValue(0.466));
+    DeviceEnergyModelContainer deviceModels =
+        radioEnergyHelper.Install(devices, energySourceContainer);
+
+    /////////////////////
+    // Internet stack  //
+    /////////////////////
+
+    InternetStackHelper internet;
+    internet.Install(nodeContainer);
+
+    Ipv4AddressHelper ipv4;
+    ipv4.SetBase("10.1.1.0", "255.255.255.0");
+    Ipv4InterfaceContainer i = ipv4.Assign(devices);
+
+    TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
+    Ptr<Socket> recvSink = Socket::CreateSocket(nodeContainer.Get(1), tid); // node 1, receiver
+    InetSocketAddress local = InetSocketAddress(Ipv4Address::GetAny(), 80);
+    recvSink->Bind(local);
+    recvSink->SetRecvCallback(MakeCallback(&ReceivePacket));
+
+    Ptr<Socket> source = Socket::CreateSocket(nodeContainer.Get(0), tid); // node 0, sender
+    InetSocketAddress remote = InetSocketAddress(Ipv4Address::GetBroadcast(), 80);
+    source->SetAllowBroadcast(true);
+    source->Connect(remote);
+
+    /////////////////////
+    // Trace Sources   //
+    /////////////////////
+
+    battery1->TraceConnectWithoutContext("RemainingEnergy", MakeCallback(&RemainingEnergy));
+
+    Ptr<DeviceEnergyModel> radioConsumptionModel =
+        battery1->FindDeviceEnergyModels("ns3::WifiRadioEnergyModel").Get(0);
+
+    /////////////////////
+    // Traffic Setup   //
+    /////////////////////
+    Simulator::Schedule(Seconds(startTime),
+                        &GenerateTraffic,
+                        source,
+                        packetSize,
+                        nodeContainer.Get(0),
+                        numPackets,
+                        interPacketInterval);
+
+    Simulator::Stop(Seconds(3600));
+    Simulator::Run();
+
+    NS_LOG_DEBUG(" *Remaining Capacity * "
+                 << "| Node 0: " << battery0->GetRemainingEnergy() << " J "
+                 << "| Node 1: " << battery1->GetRemainingEnergy() << " J");
+    NS_LOG_DEBUG(" *SoC * "
+                 << "| Node 0: " << battery0->GetStateOfCharge() << " % "
+                 << "| Node 1: " << battery1->GetStateOfCharge() << " % ");
+
+    Simulator::Destroy();
+
+    return 0;
+}
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/helper/energy-harvester-container.cc ns-3.40/src/energy/helper/energy-harvester-container.cc
--- ns-3.39/src/energy/helper/energy-harvester-container.cc	2023-07-05 14:23:47.785427300 -0700
+++ ns-3.40/src/energy/helper/energy-harvester-container.cc	2023-09-27 13:30:37.642839000 -0700
@@ -105,7 +105,7 @@
 EnergyHarvesterContainer::Add(EnergyHarvesterContainer container)
 {
     NS_LOG_FUNCTION(this << &container);
-    for (Iterator i = container.Begin(); i != container.End(); i++)
+    for (auto i = container.Begin(); i != container.End(); i++)
     {
         m_harvesters.push_back(*i);
     }
@@ -143,9 +143,7 @@
 EnergyHarvesterContainer::DoDispose()
 {
     // call Object::Dispose for all EnergyHarvester objects
-    for (std::vector<Ptr<EnergyHarvester>>::iterator i = m_harvesters.begin();
-         i != m_harvesters.end();
-         i++)
+    for (auto i = m_harvesters.begin(); i != m_harvesters.end(); i++)
     {
         (*i)->Dispose();
     }
@@ -156,9 +154,7 @@
 EnergyHarvesterContainer::DoInitialize()
 {
     // call Object::Initialize for all EnergyHarvester objects
-    for (std::vector<Ptr<EnergyHarvester>>::iterator i = m_harvesters.begin();
-         i != m_harvesters.end();
-         i++)
+    for (auto i = m_harvesters.begin(); i != m_harvesters.end(); i++)
     {
         (*i)->Initialize();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/helper/energy-harvester-helper.cc ns-3.40/src/energy/helper/energy-harvester-helper.cc
--- ns-3.39/src/energy/helper/energy-harvester-helper.cc	2023-07-05 14:23:47.785427300 -0700
+++ ns-3.40/src/energy/helper/energy-harvester-helper.cc	2023-09-27 13:30:37.642839000 -0700
@@ -43,8 +43,7 @@
 EnergyHarvesterHelper::Install(EnergySourceContainer sourceContainer) const
 {
     EnergyHarvesterContainer container;
-    for (EnergySourceContainer::Iterator i = sourceContainer.Begin(); i != sourceContainer.End();
-         ++i)
+    for (auto i = sourceContainer.Begin(); i != sourceContainer.End(); ++i)
     {
         Ptr<EnergyHarvester> harvester = DoInstall(*i);
         container.Add(harvester);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/helper/energy-harvester-helper.h ns-3.40/src/energy/helper/energy-harvester-helper.h
--- ns-3.39/src/energy/helper/energy-harvester-helper.h	2023-07-05 14:23:47.785427300 -0700
+++ ns-3.40/src/energy/helper/energy-harvester-helper.h	2023-09-27 13:30:37.642839000 -0700
@@ -21,10 +21,11 @@
 #ifndef ENERGY_HARVESTER_HELPER_H
 #define ENERGY_HARVESTER_HELPER_H
 
+#include "energy-harvester-container.h"
+#include "energy-source-container.h"
+
 #include "ns3/attribute.h"
-#include "ns3/energy-harvester-container.h"
 #include "ns3/energy-harvester.h"
-#include "ns3/energy-source-container.h"
 #include "ns3/energy-source.h"
 #include "ns3/node-container.h"
 #include "ns3/object-factory.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/helper/energy-model-helper.cc ns-3.40/src/energy/helper/energy-model-helper.cc
--- ns-3.39/src/energy/helper/energy-model-helper.cc	2023-07-05 14:23:47.785427300 -0700
+++ ns-3.40/src/energy/helper/energy-model-helper.cc	2023-09-27 13:30:37.642839000 -0700
@@ -42,7 +42,7 @@
 EnergySourceHelper::Install(NodeContainer c) const
 {
     EnergySourceContainer container;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<EnergySource> src = DoInstall(*i);
         container.Add(src);
@@ -105,8 +105,8 @@
 {
     NS_ASSERT(deviceContainer.GetN() <= sourceContainer.GetN());
     DeviceEnergyModelContainer container;
-    NetDeviceContainer::Iterator dev = deviceContainer.Begin();
-    EnergySourceContainer::Iterator src = sourceContainer.Begin();
+    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
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/helper/energy-source-container.cc ns-3.40/src/energy/helper/energy-source-container.cc
--- ns-3.39/src/energy/helper/energy-source-container.cc	2023-07-05 14:23:47.785427300 -0700
+++ ns-3.40/src/energy/helper/energy-source-container.cc	2023-09-27 13:30:37.642839000 -0700
@@ -93,7 +93,7 @@
 void
 EnergySourceContainer::Add(EnergySourceContainer container)
 {
-    for (Iterator i = container.Begin(); i != container.End(); i++)
+    for (auto i = container.Begin(); i != container.End(); i++)
     {
         m_sources.push_back(*i);
     }
@@ -122,7 +122,7 @@
 EnergySourceContainer::DoDispose()
 {
     // call Object::Dispose for all EnergySource objects
-    for (std::vector<Ptr<EnergySource>>::iterator i = m_sources.begin(); i != m_sources.end(); i++)
+    for (auto i = m_sources.begin(); i != m_sources.end(); i++)
     {
         (*i)->DisposeDeviceModels();
         (*i)->Dispose();
@@ -134,7 +134,7 @@
 EnergySourceContainer::DoInitialize()
 {
     // call Object::Start for all EnergySource objects
-    for (std::vector<Ptr<EnergySource>>::iterator i = m_sources.begin(); i != m_sources.end(); i++)
+    for (auto i = m_sources.begin(); i != m_sources.end(); i++)
     {
         (*i)->Initialize();
         (*i)->InitializeDeviceModels();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/helper/generic-battery-model-helper.cc ns-3.40/src/energy/helper/generic-battery-model-helper.cc
--- ns-3.39/src/energy/helper/generic-battery-model-helper.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/src/energy/helper/generic-battery-model-helper.cc	2023-09-27 13:30:37.642839000 -0700
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2023 Tokushima University, 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
+ *
+ * Authors: Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
+ */
+
+#include "generic-battery-model-helper.h"
+
+namespace ns3
+{
+
+GenericBatteryModelHelper::GenericBatteryModelHelper()
+{
+    m_batteryModel.SetTypeId("ns3::GenericBatteryModel");
+}
+
+GenericBatteryModelHelper::~GenericBatteryModelHelper()
+{
+}
+
+void
+GenericBatteryModelHelper::Set(std::string name, const AttributeValue& v)
+{
+    m_batteryModel.Set(name, v);
+}
+
+Ptr<EnergySource>
+GenericBatteryModelHelper::DoInstall(Ptr<Node> node) const
+{
+    NS_ASSERT(node != nullptr);
+    Ptr<EnergySource> energySource = m_batteryModel.Create<EnergySource>();
+    NS_ASSERT(energySource != nullptr);
+    energySource->SetNode(node);
+    return energySource;
+}
+
+Ptr<EnergySourceContainer>
+GenericBatteryModelHelper::Install(NodeContainer c) const
+{
+    Ptr<EnergySourceContainer> batteryContainer = CreateObject<EnergySourceContainer>();
+    for (auto i = c.Begin(); i != c.End(); i++)
+    {
+        batteryContainer->Add(DoInstall(*i));
+    }
+    return batteryContainer;
+}
+
+Ptr<EnergySource>
+GenericBatteryModelHelper::Install(Ptr<Node> node, BatteryModel bm) const
+{
+    NS_ASSERT(node != nullptr);
+    Ptr<EnergySource> energySource = m_batteryModel.Create<EnergySource>();
+    NS_ASSERT(energySource != nullptr);
+
+    energySource->SetAttribute("FullVoltage", DoubleValue(g_batteryPreset[bm].vFull));
+    energySource->SetAttribute("MaxCapacity", DoubleValue(g_batteryPreset[bm].qMax));
+
+    energySource->SetAttribute("NominalVoltage", DoubleValue(g_batteryPreset[bm].vNom));
+    energySource->SetAttribute("NominalCapacity", DoubleValue(g_batteryPreset[bm].qNom));
+
+    energySource->SetAttribute("ExponentialVoltage", DoubleValue(g_batteryPreset[bm].vExp));
+    energySource->SetAttribute("ExponentialCapacity", DoubleValue(g_batteryPreset[bm].qExp));
+
+    energySource->SetAttribute("InternalResistance",
+                               DoubleValue(g_batteryPreset[bm].internalResistance));
+    energySource->SetAttribute("TypicalDischargeCurrent",
+                               DoubleValue(g_batteryPreset[bm].typicalCurrent));
+    energySource->SetAttribute("CutoffVoltage", DoubleValue(g_batteryPreset[bm].cuttoffVoltage));
+
+    energySource->SetAttribute("BatteryType", EnumValue(g_batteryPreset[bm].batteryType));
+
+    energySource->SetNode(node);
+    return energySource;
+}
+
+EnergySourceContainer
+GenericBatteryModelHelper::Install(NodeContainer c, BatteryModel bm) const
+{
+    EnergySourceContainer batteryContainer;
+    for (auto i = c.Begin(); i != c.End(); i++)
+    {
+        Ptr<EnergySource> energySource = Install(*i, bm);
+        batteryContainer.Add(energySource);
+    }
+    return batteryContainer;
+}
+
+void
+GenericBatteryModelHelper::SetCellPack(Ptr<EnergySource> energySource,
+                                       uint8_t series,
+                                       uint8_t parallel) const
+{
+    NS_ASSERT_MSG(series > 0, "The value of cells in series must be > 0");
+    NS_ASSERT_MSG(parallel > 0, "The value of cells in parallel must be > 0");
+    NS_ASSERT(energySource != nullptr);
+
+    DoubleValue vFull;
+    DoubleValue q;
+    DoubleValue vExp;
+    DoubleValue qExp;
+    DoubleValue vNom;
+    DoubleValue qNom;
+    DoubleValue r;
+
+    // Get the present values of the battery cell
+    energySource->GetAttribute("FullVoltage", vFull);
+    energySource->GetAttribute("MaxCapacity", q);
+
+    energySource->GetAttribute("NominalVoltage", vNom);
+    energySource->GetAttribute("NominalCapacity", qNom);
+
+    energySource->GetAttribute("ExponentialVoltage", vExp);
+    energySource->GetAttribute("ExponentialCapacity", qExp);
+
+    energySource->GetAttribute("InternalResistance", r);
+
+    // Configuring the Cell packs
+    energySource->SetAttribute("FullVoltage", DoubleValue(vFull.Get() * series));
+    energySource->SetAttribute("MaxCapacity", DoubleValue(q.Get() * parallel));
+
+    energySource->SetAttribute("NominalVoltage", DoubleValue(vNom.Get() * series));
+    energySource->SetAttribute("NominalCapacity", DoubleValue(qNom.Get() * parallel));
+
+    energySource->SetAttribute("ExponentialVoltage", DoubleValue(vExp.Get() * series));
+    energySource->SetAttribute("ExponentialCapacity", DoubleValue(qExp.Get() * parallel));
+
+    energySource->SetAttribute("InternalResistance", DoubleValue(r.Get() * (series / parallel)));
+}
+
+void
+GenericBatteryModelHelper::SetCellPack(EnergySourceContainer energySourceContainer,
+                                       uint8_t series,
+                                       uint8_t parallel) const
+{
+    NS_ASSERT_MSG(energySourceContainer.GetN() > 0, "This energy container is empty");
+
+    for (auto i = energySourceContainer.Begin(); i != energySourceContainer.End(); i++)
+    {
+        SetCellPack(*i, series, parallel);
+    }
+}
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/helper/generic-battery-model-helper.h ns-3.40/src/energy/helper/generic-battery-model-helper.h
--- ns-3.39/src/energy/helper/generic-battery-model-helper.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/src/energy/helper/generic-battery-model-helper.h	2023-09-27 13:30:37.642839000 -0700
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2023 Tokushima University, 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
+ *
+ * Authors: Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
+ */
+
+#ifndef GENERIC_BATTERY_MODEL_HELPER_H_
+#define GENERIC_BATTERY_MODEL_HELPER_H_
+
+#include "energy-model-helper.h"
+
+#include <ns3/generic-battery-model.h>
+#include <ns3/node.h>
+
+namespace ns3
+{
+
+/**
+ * \ingroup energy
+ * \brief Creates and assign an assortment of BatteryModels to Nodes.
+ *
+ */
+class GenericBatteryModelHelper : public EnergySourceHelper
+{
+  public:
+    GenericBatteryModelHelper();
+    ~GenericBatteryModelHelper() override;
+
+    /**
+     * Sets one of the attributes of underlying EnergySource.
+     *
+     * \param name Name of attribute to set.
+     * \param v Value of the attribute.
+     */
+    void Set(std::string name, const AttributeValue& v) override;
+
+    /**
+     * This function installs energy sources in a group of nodes in a
+     * node container. An energy source (Li-Ion battery) with default values
+     * is used on each node.
+     *
+     * \param c The node container
+     * \returns An EnergySourceContainer which contains all the EnergySources.
+     */
+    Ptr<EnergySourceContainer> Install(NodeContainer c) const;
+
+    /**
+     * This function installs an energy source (battery) into a node.
+     *
+     * \param node The node object.
+     * \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;
+
+    /**
+     * This function installs energy sources in a group of nodes in a
+     * node container.
+     *
+     * \param c The node container.
+     * \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;
+
+    /**
+     * This function takes an existing energy source and transform its values to form
+     * a group of connected identical cells. The values of the newly formed cell block
+     * depends on the connection of the cells defined by the user
+     * (number of cells connected in series, number of cells connected in parallel).
+     *
+     * \param energySource The energy source used.
+     * \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;
+
+    /**
+     * This function takes an existing energy source container and transform the values
+     * of each of its containing energy sources to form groups of connected identical cells.
+     * The values of the newly formed cell blocks for each energy source
+     * depends on the connection of the cells defined by the user
+     * (number of cells connected in series, number of cells connected in parallel).
+     *
+     * \param energySourceContainer The energy source container used.
+     * \param series The number of cells connected in series.
+     * \param parallel The number of cells connected in parallel.
+     */
+    void SetCellPack(EnergySourceContainer energySourceContainer,
+                     uint8_t series,
+                     uint8_t parallel) const;
+
+  private:
+    /**
+     * Child classes of EnergySourceHelper only have to implement this function,
+     * to create and aggregate an EnergySource object onto a single node. Rest of
+     * the installation process (eg. installing EnergySource on set of nodes) is
+     * implemented in the EnergySourceHelper base class.
+     *
+     * \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;
+
+  private:
+    ObjectFactory m_batteryModel; //!< The energy source (battery) used by this helper.
+};
+
+} // namespace ns3
+
+#endif /* GENERIC_BATTERY_MODEL_HELPER_H_ */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/model/basic-energy-harvester.h ns-3.40/src/energy/model/basic-energy-harvester.h
--- ns-3.39/src/energy/model/basic-energy-harvester.h	2023-07-05 14:23:47.789427300 -0700
+++ ns-3.40/src/energy/model/basic-energy-harvester.h	2023-09-27 13:30:37.642839000 -0700
@@ -21,17 +21,16 @@
 #ifndef BASIC_ENERGY_HARVESTER
 #define BASIC_ENERGY_HARVESTER
 
-#include <iostream>
-
-// include from ns-3
+#include "device-energy-model.h"
 #include "energy-harvester.h"
 
-#include "ns3/device-energy-model.h"
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
 #include "ns3/random-variable-stream.h"
 #include "ns3/traced-value.h"
 
+#include <iostream>
+
 namespace ns3
 {
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/model/device-energy-model-container.cc ns-3.40/src/energy/model/device-energy-model-container.cc
--- ns-3.39/src/energy/model/device-energy-model-container.cc	2023-07-05 14:23:47.789427300 -0700
+++ ns-3.40/src/energy/model/device-energy-model-container.cc	2023-09-27 13:30:37.642839000 -0700
@@ -89,7 +89,7 @@
 DeviceEnergyModelContainer::Add(DeviceEnergyModelContainer container)
 {
     NS_LOG_FUNCTION(this << &container);
-    for (Iterator i = container.Begin(); i != container.End(); i++)
+    for (auto i = container.Begin(); i != container.End(); i++)
     {
         m_models.push_back(*i);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/model/device-energy-model-container.h ns-3.40/src/energy/model/device-energy-model-container.h
--- ns-3.39/src/energy/model/device-energy-model-container.h	2023-07-05 14:23:47.789427300 -0700
+++ ns-3.40/src/energy/model/device-energy-model-container.h	2023-09-27 13:30:37.642839000 -0700
@@ -22,7 +22,7 @@
 #ifndef DEVICE_ENERGY_MODEL_CONTAINER_H
 #define DEVICE_ENERGY_MODEL_CONTAINER_H
 
-#include "ns3/device-energy-model.h"
+#include "device-energy-model.h"
 
 #include <stdint.h>
 #include <vector>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/model/energy-source.cc ns-3.40/src/energy/model/energy-source.cc
--- ns-3.39/src/energy/model/energy-source.cc	2023-07-05 14:23:47.789427300 -0700
+++ ns-3.40/src/energy/model/energy-source.cc	2023-09-27 13:30:37.642839000 -0700
@@ -22,7 +22,8 @@
  * Modifications made by: Cristiano Tapparello <cristiano.tapparello@rochester.edu>
  */
 
-#include <ns3/energy-source.h>
+#include "energy-source.h"
+
 #include <ns3/log.h>
 
 namespace ns3
@@ -171,8 +172,7 @@
     {
         double totalHarvestedPower = 0.0;
 
-        std::vector<Ptr<EnergyHarvester>>::const_iterator harvester;
-        for (harvester = m_harvesters.begin(); harvester != m_harvesters.end(); harvester++)
+        for (auto harvester = m_harvesters.begin(); harvester != m_harvesters.end(); harvester++)
         {
             totalHarvestedPower += (*harvester)->GetPower();
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/model/energy-source.h ns-3.40/src/energy/model/energy-source.h
--- ns-3.39/src/energy/model/energy-source.h	2023-07-05 14:23:47.789427300 -0700
+++ ns-3.40/src/energy/model/energy-source.h	2023-09-27 13:30:37.642839000 -0700
@@ -26,8 +26,8 @@
 #define ENERGY_SOURCE_H
 
 #include "device-energy-model-container.h" // #include "device-energy-model.h"
+#include "energy-harvester.h"
 
-#include "ns3/energy-harvester.h"
 #include "ns3/node.h"
 #include "ns3/object.h"
 #include "ns3/ptr.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/model/generic-battery-model.cc ns-3.40/src/energy/model/generic-battery-model.cc
--- ns-3.39/src/energy/model/generic-battery-model.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/src/energy/model/generic-battery-model.cc	2023-09-27 13:30:37.642839000 -0700
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2010 Andrea Sacco: Li-Ion battery
+ * Copyright (c) 2023 Tokushima University, Japan:
+ * NiMh,NiCd,LeaAcid batteries and preset and multicell extensions.
+ *
+ * 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: Andrea Sacco <andrea.sacco85@gmail.com>
+ *         Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
+ */
+
+#include "generic-battery-model.h"
+
+#include <ns3/assert.h>
+#include <ns3/double.h>
+#include <ns3/log.h>
+#include <ns3/simulator.h>
+#include <ns3/trace-source-accessor.h>
+
+#include <cmath>
+
+namespace ns3
+{
+
+NS_LOG_COMPONENT_DEFINE("GenericBatteryModel");
+
+NS_OBJECT_ENSURE_REGISTERED(GenericBatteryModel);
+
+TypeId
+GenericBatteryModel::GetTypeId()
+{
+    static TypeId tid =
+        TypeId("ns3::GenericBatteryModel")
+            .SetParent<EnergySource>()
+            .SetGroupName("Energy")
+            .AddConstructor<GenericBatteryModel>()
+            .AddAttribute("LowBatteryThreshold",
+                          "Low battery threshold for generic battery model.",
+                          DoubleValue(0.10), // 0.10 as a fraction of the initial energy
+                          MakeDoubleAccessor(&GenericBatteryModel::m_lowBatteryTh),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("FullVoltage",
+                          "(Q_full) The voltage of the cell when fully charged (V).",
+                          DoubleValue(4.18),
+                          MakeDoubleAccessor(&GenericBatteryModel::m_vFull),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("MaxCapacity",
+                          "(Q) The maximum capacity of the cell (Ah).",
+                          DoubleValue(2.45),
+                          MakeDoubleAccessor(&GenericBatteryModel::m_qMax),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("NominalVoltage",
+                          "(V_nom) Nominal voltage of the cell (V).",
+                          DoubleValue(3.59),
+                          MakeDoubleAccessor(&GenericBatteryModel::m_vNom),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("NominalCapacity",
+                          "(Q_nom) Cell capacity at the end of the nominal zone (Ah)",
+                          DoubleValue(1.3),
+                          MakeDoubleAccessor(&GenericBatteryModel::m_qNom),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("ExponentialVoltage",
+                          "(V_exp) Cell voltage at the end of the exponential zone (V).",
+                          DoubleValue(3.75),
+                          MakeDoubleAccessor(&GenericBatteryModel::m_vExp),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("ExponentialCapacity",
+                          "(Q_exp) Cell Capacity at the end of the exponential zone (Ah).",
+                          DoubleValue(0.39),
+                          MakeDoubleAccessor(&GenericBatteryModel::m_qExp),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("InternalResistance",
+                          "(R) Internal resistance of the cell (Ohms)",
+                          DoubleValue(0.083),
+                          MakeDoubleAccessor(&GenericBatteryModel::m_internalResistance),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("TypicalDischargeCurrent",
+                          "Typical discharge current used in manufacters datasheets (A)",
+                          DoubleValue(2.33),
+                          MakeDoubleAccessor(&GenericBatteryModel::m_typicalCurrent),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("CutoffVoltage",
+                          "The voltage where the battery is considered depleted (V).",
+                          DoubleValue(3.3),
+                          MakeDoubleAccessor(&GenericBatteryModel::m_cutoffVoltage),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("PeriodicEnergyUpdateInterval",
+                          "Time between two consecutive periodic energy updates.",
+                          TimeValue(Seconds(1.0)),
+                          MakeTimeAccessor(&GenericBatteryModel::SetEnergyUpdateInterval,
+                                           &GenericBatteryModel::GetEnergyUpdateInterval),
+                          MakeTimeChecker())
+            .AddAttribute("BatteryType",
+                          "Indicates the battery type used by the model",
+                          EnumValue(LION_LIPO),
+                          MakeEnumAccessor(&GenericBatteryModel::m_batteryType),
+                          MakeEnumChecker(LION_LIPO,
+                                          "LION_LIPO",
+                                          NIMH_NICD,
+                                          "NIMH_NICD",
+                                          LEADACID,
+                                          "LEADACID"))
+            .AddTraceSource("RemainingEnergy",
+                            "Remaining energy of generic battery",
+                            MakeTraceSourceAccessor(&GenericBatteryModel::m_remainingEnergyJ),
+                            "ns3::TracedValueCallback::Double");
+    return tid;
+}
+
+GenericBatteryModel::GenericBatteryModel()
+    : m_drainedCapacity(0),
+      m_currentFiltered(0),
+      m_entn(0),
+      m_expZone(0),
+      m_lastUpdateTime(Seconds(0.0))
+{
+    NS_LOG_FUNCTION(this);
+}
+
+GenericBatteryModel::~GenericBatteryModel()
+{
+    NS_LOG_FUNCTION(this);
+}
+
+double
+GenericBatteryModel::GetInitialEnergy() const
+{
+    double initialEnergy = m_qMax * m_vFull * 3600;
+    return initialEnergy;
+}
+
+double
+GenericBatteryModel::GetSupplyVoltage() const
+{
+    return m_supplyVoltageV;
+}
+
+void
+GenericBatteryModel::SetEnergyUpdateInterval(Time interval)
+{
+    NS_LOG_FUNCTION(this << interval);
+    m_energyUpdateInterval = interval;
+}
+
+void
+GenericBatteryModel::SetDrainedCapacity(double drainedCapacity)
+{
+    NS_ASSERT(drainedCapacity >= 0 && drainedCapacity < m_qMax);
+    m_drainedCapacity = drainedCapacity;
+}
+
+double
+GenericBatteryModel::GetDrainedCapacity() const
+{
+    return m_drainedCapacity;
+}
+
+double
+GenericBatteryModel::GetStateOfCharge() const
+{
+    double soc = 100 * (1 - m_drainedCapacity / m_qMax);
+    return soc;
+}
+
+Time
+GenericBatteryModel::GetEnergyUpdateInterval() const
+{
+    NS_LOG_FUNCTION(this);
+    return m_energyUpdateInterval;
+}
+
+double
+GenericBatteryModel::GetRemainingEnergy()
+{
+    NS_LOG_FUNCTION(this);
+    UpdateEnergySource();
+    return m_remainingEnergyJ;
+}
+
+double
+GenericBatteryModel::GetEnergyFraction()
+{
+    NS_LOG_FUNCTION(this);
+    return GetStateOfCharge();
+}
+
+void
+GenericBatteryModel::UpdateEnergySource()
+{
+    NS_LOG_FUNCTION(this);
+
+    // do not update if simulation has finished
+    if (Simulator::IsFinished())
+    {
+        return;
+    }
+
+    m_energyUpdateEvent.Cancel();
+
+    CalculateRemainingEnergy();
+
+    m_lastUpdateTime = Simulator::Now();
+
+    if (m_supplyVoltageV <= m_cutoffVoltage)
+    {
+        // check if battery is depleted
+        BatteryDepletedEvent();
+    }
+    else if (m_supplyVoltageV >= m_vFull)
+    {
+        // check if battery has reached full charge
+        BatteryChargedEvent();
+        // TODO: Should battery charging be stopped if full voltage is reached?
+        //       or should it be allowed to continue charging (overcharge)?
+    }
+
+    m_energyUpdateEvent =
+        Simulator::Schedule(m_energyUpdateInterval, &GenericBatteryModel::UpdateEnergySource, this);
+}
+
+void
+GenericBatteryModel::DoInitialize()
+{
+    NS_LOG_FUNCTION(this);
+}
+
+void
+GenericBatteryModel::DoDispose()
+{
+    NS_LOG_FUNCTION(this);
+    BreakDeviceEnergyModelRefCycle();
+}
+
+void
+GenericBatteryModel::BatteryDepletedEvent()
+{
+    NS_LOG_FUNCTION(this);
+    // notify DeviceEnergyModel objects, all "usable" energy has been depleted
+    // (cutoff voltage was reached)
+    NotifyEnergyDrained();
+}
+
+void
+GenericBatteryModel::BatteryChargedEvent()
+{
+    NS_LOG_FUNCTION(this);
+    // notify DeviceEnergyModel objects, the battery has reached its full energy potential.
+    // (full voltage was reached)
+    NotifyEnergyRecharged();
+}
+
+void
+GenericBatteryModel::CalculateRemainingEnergy()
+{
+    NS_LOG_FUNCTION(this);
+
+    double totalCurrentA = CalculateTotalCurrent();
+
+    m_energyUpdateLapseTime = Simulator::Now() - m_lastUpdateTime;
+
+    NS_ASSERT(m_energyUpdateLapseTime.GetSeconds() >= 0);
+
+    // Calculate i* (current step response)
+    Time batteryResponseConstant = Seconds(30);
+
+    double responseTime = (Simulator::Now() / batteryResponseConstant).GetDouble();
+    m_currentFiltered = totalCurrentA * (1 - 1 / (std::exp(responseTime)));
+    // TODO: the time in the responseTime should be a time taken since the last *battery current*
+    // change, in the testing the  battery current is only changed at the beginning of the
+    // simulation therefore, the simulation time can be used. However this must be changed to
+    // a time counter to allow this value to reset in the middle of the simulation when the
+    // battery current changes.
+
+    m_drainedCapacity += (totalCurrentA * m_energyUpdateLapseTime).GetHours();
+
+    if (totalCurrentA < 0)
+    {
+        // Charge current (Considered as "Negative" i)
+        m_supplyVoltageV = GetChargeVoltage(totalCurrentA);
+    }
+    else
+    {
+        // Discharge current (Considered as "Positive" i)
+        m_supplyVoltageV = GetVoltage(totalCurrentA);
+    }
+}
+
+double
+GenericBatteryModel::GetChargeVoltage(double i)
+{
+    // integral of i over time drained capacity in Ah
+    double it = m_drainedCapacity;
+
+    // empirical factors
+    double A = m_vFull - m_vExp;
+    double B = 3 / m_qExp;
+
+    // voltage constant
+    double E0 = m_vFull + m_internalResistance * m_typicalCurrent - A;
+
+    // voltage of exponential zone when battery is fully charged
+    double expZoneFull = A * std::exp(-B * m_qNom);
+
+    // Obtain the voltage|resistance polarization constant
+    double K = (E0 - m_vNom - (m_internalResistance * m_typicalCurrent) + expZoneFull) /
+               (m_qMax / (m_qMax - m_qNom) * (m_qNom + m_typicalCurrent));
+
+    double V = 0;
+    double polResistance = 0;
+    double polVoltage = 0;
+
+    if (m_batteryType == LION_LIPO)
+    { // For LiOn & LiPo batteries
+
+        // Calculate exponential zone voltage
+        m_expZone = A * std::exp(-B * it);
+
+        polResistance = K * m_qMax / (it + 0.1 * m_qMax);
+        polVoltage = K * m_qMax / (m_qMax - it);
+        V = E0 - (m_internalResistance * i) - (polResistance * m_currentFiltered) -
+            (polVoltage * it) + m_expZone;
+    }
+    else
+    {
+        // Calculate exponential zone voltage
+
+        if (m_expZone == 0)
+        {
+            m_expZone = A * std::exp(-B * it);
+        }
+        double entnPrime = m_entn;
+        double expZonePrime = m_expZone;
+        m_entn = B * std::abs(i) * (-expZonePrime + A);
+        m_expZone = expZonePrime + (m_energyUpdateLapseTime * entnPrime).GetHours();
+
+        if (m_batteryType == NIMH_NICD)
+        { // For NiMH and NiCd batteries
+            polResistance = K * m_qMax / (std::abs(it) + 0.1 * m_qMax);
+        }
+        else if (m_batteryType == LEADACID)
+        { // For Lead acid batteries
+            polResistance = K * m_qMax / (it + 0.1 * m_qMax);
+        }
+
+        polVoltage = K * m_qMax / (m_qMax - it);
+
+        V = E0 - (m_internalResistance * i) - (polResistance * m_currentFiltered) -
+            (polVoltage * it) + m_expZone;
+    }
+
+    // Energy in Joules = RemainingCapacity * Voltage * Seconds in an Hour
+    m_remainingEnergyJ = (m_qMax - it) * V * 3600;
+
+    NS_LOG_DEBUG("* CHARGE *| " << Simulator::Now().As(Time::S) << "| i " << i << " | it " << it
+                                << "| E0 " << E0 << " | polRes " << polResistance << " | polVol "
+                                << polVoltage << "| B " << B << " | ExpZone " << m_expZone
+                                << " | A " << A << "| K " << K << "| i* " << m_currentFiltered
+                                << " | V " << V << " |  rmnEnergy " << m_remainingEnergyJ
+                                << "J | SoC " << GetStateOfCharge() << "% ");
+
+    return V;
+}
+
+double
+GenericBatteryModel::GetVoltage(double i)
+{
+    NS_LOG_FUNCTION(this << i);
+
+    // integral of i in dt, drained capacity in Ah
+    double it = m_drainedCapacity;
+
+    // empirical factors
+    double A = m_vFull - m_vExp;
+
+    double B = 3 / m_qExp;
+
+    // constant voltage
+    double E0 = m_vFull + m_internalResistance * m_typicalCurrent - A;
+
+    // voltage of exponential zone when battery is fully charged
+    double expZoneFull = A * std::exp(-B * m_qNom);
+
+    // Obtain the voltage|resistance polarization constant
+    double K = (E0 - m_vNom - (m_internalResistance * m_typicalCurrent) + expZoneFull) /
+               (m_qMax / (m_qMax - m_qNom) * (m_qNom + m_typicalCurrent));
+
+    double V = 0;
+    double polResistance = K * (m_qMax / (m_qMax - it));
+    double polVoltage = polResistance;
+
+    // Calculate exponential zone voltage according to the battery type
+    if (m_batteryType == LION_LIPO)
+    {
+        m_expZone = A * exp(-B * it);
+    }
+    else
+    {
+        NS_ASSERT(m_batteryType == NIMH_NICD || m_batteryType == LEADACID);
+        if (m_expZone == 0)
+        {
+            m_expZone = A * exp(-B * it);
+        }
+
+        double entnPrime = m_entn;
+        double expZonePrime = m_expZone;
+
+        m_entn = B * std::abs(i) * (-expZonePrime);
+        m_expZone = expZonePrime + (m_energyUpdateLapseTime * entnPrime).GetHours();
+    }
+
+    V = E0 - (m_internalResistance * i) - (polResistance * m_currentFiltered) - (polVoltage * it) +
+        m_expZone;
+
+    // EnergyJ = RemainingCapacity * Voltage * Seconds in an Hour
+    m_remainingEnergyJ = (m_qMax - it) * V * 3600;
+
+    NS_LOG_DEBUG("* DISCHARGE *| " << Simulator::Now().As(Time::S) << "| i " << i << " | it " << it
+                                   << " | A " << A << " | B " << B << " | ExpZone " << m_expZone
+                                   << " | V " << V << " | rmnEnergy " << m_remainingEnergyJ
+                                   << "J | SoC " << GetStateOfCharge() << "% "
+                                   << "\n"
+                                   << "             | K " << K << " | E0 " << E0);
+
+    return V;
+}
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/model/generic-battery-model.h ns-3.40/src/energy/model/generic-battery-model.h
--- ns-3.39/src/energy/model/generic-battery-model.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/src/energy/model/generic-battery-model.h	2023-09-27 13:30:37.642839000 -0700
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2010 Andrea Sacco: Li-Ion battery
+ * Copyright (c) 2023 Tokushima University, Japan:
+ * NiMh,NiCd,LeaAcid batteries and preset and multi-cell extensions.
+ *
+ * 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: Andrea Sacco <andrea.sacco85@gmail.com>
+ *         Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
+ */
+
+#ifndef GENERIC_BATTERY_MODEL_H
+#define GENERIC_BATTERY_MODEL_H
+
+#include "energy-source.h"
+
+#include <ns3/event-id.h>
+#include <ns3/nstime.h>
+#include <ns3/traced-value.h>
+
+namespace ns3
+{
+
+/**
+ * \ingroup energy
+ *
+ *  Battery types.
+ *  These are grouped according to their chemical characteristics
+ *  present during a charge/discharge curve.
+ */
+enum GenericBatteryType
+{
+    LION_LIPO = 0, //!< Lithium-ion and Lithium-polymer batteries
+    NIMH_NICD = 1, //!< Nickel-metal hydride and Nickel cadmium batteries
+    LEADACID = 2   //!< Lead Acid Batteries
+};
+
+/**
+ * \ingroup energy
+ *
+ *  Battery models that described the parameters of the the battery presets.
+ */
+enum BatteryModel
+{
+    PANASONIC_HHR650D_NIMH = 0,    //!< Panasonic HHR650D NiMh battery
+    CSB_GP1272_LEADACID = 1,       //!< CSB GP1272 Lead acid battery
+    PANASONIC_CGR18650DA_LION = 2, //!< Panasonic CGR18650DA Li-Ion battery
+    RSPRO_LGP12100_LEADACID = 3,   //!< RS Pro LGP12100 Lead acid battery
+    PANASONIC_N700AAC_NICD = 4     //!< Panasonic N700AAC NiCd battery
+};
+
+/**
+ * \ingroup energy
+ *
+ *  The structure containing the the parameter values that describe a
+ *  battery preset.
+ */
+struct BatteryPresets
+{
+    GenericBatteryType batteryType; //!< The type of battery used in the preset.
+    std::string description;        //!< Additional information about the battery.
+    double vFull;                   //!< Initial voltage of the battery, in Volts
+    double qMax;                    //!< The maximum capacity of the battery, in Ah
+    double vNom;                    //!< Nominal voltage of the battery, in Volts
+    double qNom;                    //!< Battery capacity at the end of the nominal zone, in Ah
+    double vExp;               //!< Battery voltage at the end of the exponential zone, in Volts
+    double qExp;               //!< Capacity value at the end of the exponential zone, in Ah
+    double internalResistance; //!< Internal resistance of the battery, in Ohms
+    double typicalCurrent;     //!< Typical discharge current used to fit the curves
+    double cuttoffVoltage;     //!< The threshold voltage where the battery is considered depleted
+};
+
+/**
+ * \ingroup energy
+ *
+ *  Contains the values that form the battery presents available in this module.
+ */
+static BatteryPresets g_batteryPreset[] = {{NIMH_NICD,
+                                            "Panasonic HHR650D | NiMH | 1.2V 6.5Ah | Size: D",
+                                            1.39,
+                                            7.0,
+                                            1.18,
+                                            6.25,
+                                            1.28,
+                                            1.3,
+                                            0.0046,
+                                            1.3,
+                                            1.0},
+                                           {LEADACID,
+                                            "CSB GP1272 | Lead Acid | 12V 7.2Ah",
+                                            12.8,
+                                            7.2,
+                                            11.5,
+                                            4.5,
+                                            12.5,
+                                            2,
+                                            0.056,
+                                            0.36,
+                                            8.0},
+                                           {LION_LIPO,
+                                            "Panasonic CGR18650DA | Li-Ion | 3.6V 2.45Ah | Size: A",
+                                            4.17,
+                                            2.33,
+                                            3.57,
+                                            2.14,
+                                            3.714,
+                                            1.74,
+                                            0.0830,
+                                            0.466,
+                                            3.0},
+                                           {LEADACID,
+                                            "Rs PRO LGP12100 | Lead Acid | 12V 100Ah",
+                                            12.60,
+                                            130,
+                                            12.44,
+                                            12.3,
+                                            12.52,
+                                            12,
+                                            0.00069,
+                                            5,
+                                            11},
+                                           {NIMH_NICD,
+                                            "PANASONIC N-700AAC | NiCd | 1.2V 700mAh | Size: AA",
+                                            1.38,
+                                            0.790,
+                                            1.17,
+                                            0.60,
+                                            1.25,
+                                            0.24,
+                                            0.016,
+                                            0.7,
+                                            0.8}};
+
+/**
+ * \ingroup energy
+ * \brief A generic battery model for  Li-Ion, NiCd, NiMh and Lead acid batteries
+ *
+ * The generic battery model can be used to describe the discharge behavior of
+ * the battery chemestries supported by the model.
+ */
+class GenericBatteryModel : public EnergySource
+{
+  public:
+    /**
+     * \brief Get the type ID.
+     * \return The object TypeId.
+     */
+    static TypeId GetTypeId();
+
+    GenericBatteryModel();
+
+    ~GenericBatteryModel() override;
+
+    /**
+     * Implements GetInitialEnergy. It returns the amount of energy in Joules stored in the
+     * battery when fully charged. This energy is different to the total amount of usable energy
+     * in the battery. This is because the battery cannot be used until Voltage = 0, only until
+     * it reaches the cutoff voltage.
+     *
+     * \return The initial energy stored in the fully charged battery, in Joules.
+     */
+    double GetInitialEnergy() const override;
+
+    /**
+     * Implements GetSupplyVoltage.
+     *
+     * \return Supply voltage at the energy source.
+     */
+    double GetSupplyVoltage() const override;
+
+    /**
+     * Implements GetRemainingEnergy.
+     *
+     * \return Remaining energy in energy source, in Joules
+     */
+    double GetRemainingEnergy() override;
+
+    /**
+     * Implements GetEnergyFraction. For the generic battery model, energy fraction
+     * is equivalent to the remaining usable capacity (i.e. The SoC).
+     *
+     * \return Energy fraction.
+     */
+    double GetEnergyFraction() override;
+
+    /**
+     * Implements UpdateEnergySource.
+     */
+    void UpdateEnergySource() override;
+
+    /**
+     * This function sets the interval between each energy update.
+     *
+     * \param interval Energy update interval.
+     */
+    void SetEnergyUpdateInterval(Time interval);
+
+    /**
+     *  This function is used to change the initial capacity in the battery.
+     *  A value of 0 means that the battery is fully charged. The value cannot
+     *  be set to a value bigger than the rated capacity (fully discharged) or
+     *  less than 0 (fully charged).
+     *
+     *  \param drainedCapacity The capacity drained so far in the battery.
+     */
+    void SetDrainedCapacity(double drainedCapacity);
+
+    /**
+     * Obtain the amount of drained capacity from the battery based on the
+     * integral of the current over time (Coulomb counting method).
+     *
+     * \return The drainedCapacity (Ah)
+     */
+    double GetDrainedCapacity() const;
+
+    /**
+     *  Calculates an estimate of the State of Charge (SoC).
+     *  In essence, the amount of usable capacity remaining in the battery (%).
+     *
+     *  \return The percentage of usable capacity remaining in the battery.
+     */
+    double GetStateOfCharge() const;
+
+    /**
+     * \return The interval between each energy update.
+     */
+    Time GetEnergyUpdateInterval() const;
+
+  private:
+    void DoInitialize() override;
+    void DoDispose() override;
+
+    /**
+     * Handles the battery reaching its cutoff voltage. This function notifies
+     * all the energy models aggregated to the node about the usable energy in the
+     * battery has being depleted. Each energy model is then responsible for its own handler.
+     */
+    void BatteryDepletedEvent();
+
+    /**
+     * Handles the battery reaching its full voltage. This function notifies
+     * all the energy models aggregated to the node about the battery reaching its
+     * full energy charge.
+     */
+    void BatteryChargedEvent();
+
+    /**
+     * Calculates remaining energy. This function uses the total current from all
+     * device models to calculate the amount of energy to decrease. The energy to
+     * decrease is given by:
+     *    energy to decrease = total current * supply voltage * time duration
+     * This function subtracts the calculated energy to decrease from remaining
+     * energy.
+     */
+    void CalculateRemainingEnergy();
+
+    /**
+     *  Get the battery voltage in function of the discharge current.
+     *  It consider different discharge curves for different discharge currents
+     *  and the remaining energy of the battery.
+     *
+     *  \param current The actual discharge current value (+i).
+     *  \return The voltage of the battery.
+     */
+    double GetVoltage(double current);
+
+    /**
+     *  Obtain the battery voltage as a result of a charge current.
+     *
+     *  \param current The actual charge current value (-i).
+     *  \return The voltage of the battery.
+     */
+    double GetChargeVoltage(double current);
+
+  private:
+    TracedValue<double> m_remainingEnergyJ; //!< Remaining energy, in Joules
+    double m_drainedCapacity;               //!< Capacity drained from the battery, in Ah
+    double m_currentFiltered;               //!< The step response (a.k.a. low pass filter)
+    double m_entn;                          //!< The previous value of the exponential zone
+                                            //!< in NiMh,NiCd and LeadAcid.
+    double m_expZone;                       //!< Voltage value of the exponential zone
+    Time m_energyUpdateLapseTime; //!< The lapse of time between the last battery energy update and
+                                  //!< the current time.
+    double m_supplyVoltageV;      //!< Actual voltage of the battery
+    double m_lowBatteryTh;        //!< Low battery threshold, as a fraction of the initial energy
+    EventId m_energyUpdateEvent;  //!< Energy update event
+    Time m_lastUpdateTime;        //!< Last update time
+    Time m_energyUpdateInterval;  //!< Energy update interval
+    double m_vFull;               //!< Initial voltage of the battery, in Volts
+    double m_vNom;                //!< Nominal voltage of the battery, in Volts
+    double m_vExp;                //!< Battery voltage at the end of the exponential zone, in Volts
+    double m_internalResistance;  //!< Internal resistance of the battery, in Ohms
+    double m_qMax;                //!< The maximum capacity of the battery, in Ah
+    double m_qNom;                //!< Battery capacity at the end of the nominal zone, in Ah
+    double m_qExp;                //!< Capacity value at the end of the exponential zone, in Ah
+    double m_typicalCurrent;      //!< Typical discharge current used to fit the curves
+    double m_cutoffVoltage; //!< The threshold voltage where the battery is considered depleted
+    GenericBatteryType m_batteryType; //!< Indicates the battery type used by the model
+};
+
+} // namespace ns3
+
+#endif /* GENERIC_BATTERY_MODEL_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/model/li-ion-energy-source.h ns-3.40/src/energy/model/li-ion-energy-source.h
--- ns-3.39/src/energy/model/li-ion-energy-source.h	2023-07-05 14:23:47.789427300 -0700
+++ ns-3.40/src/energy/model/li-ion-energy-source.h	2023-09-27 13:30:37.642839000 -0700
@@ -20,7 +20,8 @@
 #ifndef LI_ION_ENERGY_SOURCE_H
 #define LI_ION_ENERGY_SOURCE_H
 
-#include "ns3/energy-source.h"
+#include "energy-source.h"
+
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
 #include "ns3/traced-value.h"
@@ -32,6 +33,9 @@
  * \ingroup energy
  * \brief Model a generic Lithium Ion Battery basing on [1][2].
  *
+ * \deprecated The LiIonEnergySource was deprecated in ns-3.40 in favor of GenericBatteryModel, and
+ * will be removed in a future release.
+ *
  * The model can be fitted to any type of Li-Ion Battery, simply changing the
  * model parameters.
  * The default values are fitted for the Panasonic CGR18650DA Li-Ion Battery [3].
@@ -131,6 +135,7 @@
      *
      * Implements DecreaseRemainingEnergy.
      */
+    NS_DEPRECATED_3_40("Use GenericBatteryModel instead")
     virtual void DecreaseRemainingEnergy(double energyJ);
 
     /**
@@ -138,6 +143,7 @@
      *
      * Implements IncreaseRemainingEnergy.
      */
+    NS_DEPRECATED_3_40("Use GenericBatteryModel instead")
     virtual void IncreaseRemainingEnergy(double energyJ);
 
     /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/model/simple-device-energy-model.cc ns-3.40/src/energy/model/simple-device-energy-model.cc
--- ns-3.39/src/energy/model/simple-device-energy-model.cc	2023-07-05 14:23:47.789427300 -0700
+++ ns-3.40/src/energy/model/simple-device-energy-model.cc	2023-09-27 13:30:37.642839000 -0700
@@ -19,7 +19,8 @@
 
 #include "simple-device-energy-model.h"
 
-#include "ns3/energy-source.h"
+#include "energy-source.h"
+
 #include "ns3/log.h"
 #include "ns3/simulator.h"
 #include "ns3/trace-source-accessor.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/energy/model/simple-device-energy-model.h ns-3.40/src/energy/model/simple-device-energy-model.h
--- ns-3.39/src/energy/model/simple-device-energy-model.h	2023-07-05 14:23:47.789427300 -0700
+++ ns-3.40/src/energy/model/simple-device-energy-model.h	2023-09-27 13:30:37.642839000 -0700
@@ -20,7 +20,8 @@
 #ifndef SIMPLE_DEVICE_ENERGY_MODEL_H
 #define SIMPLE_DEVICE_ENERGY_MODEL_H
 
-#include "ns3/device-energy-model.h"
+#include "device-energy-model.h"
+
 #include "ns3/nstime.h"
 #include "ns3/traced-value.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/examples/fd2fd-onoff.cc ns-3.40/src/fd-net-device/examples/fd2fd-onoff.cc
--- ns-3.39/src/fd-net-device/examples/fd2fd-onoff.cc	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/examples/fd2fd-onoff.cc	2023-09-27 13:30:37.646839100 -0700
@@ -64,7 +64,7 @@
     cmd.Parse(argc, argv);
 
     std::string factory;
-    if (tcpMode == 1)
+    if (tcpMode)
     {
         factory = "ns3::TcpSocketFactory";
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/examples/fd-emu-onoff.cc ns-3.40/src/fd-net-device/examples/fd-emu-onoff.cc
--- ns-3.39/src/fd-net-device/examples/fd-emu-onoff.cc	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/examples/fd-emu-onoff.cc	2023-09-27 13:30:37.646839100 -0700
@@ -200,7 +200,7 @@
 #ifdef HAVE_PACKET_H
     if (emuMode == "raw")
     {
-        EmuFdNetDeviceHelper* raw = new EmuFdNetDeviceHelper;
+        auto raw = new EmuFdNetDeviceHelper;
         raw->SetDeviceName(deviceName);
         helper = raw;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/examples/fd-emu-ping.cc ns-3.40/src/fd-net-device/examples/fd-emu-ping.cc
--- ns-3.39/src/fd-net-device/examples/fd-emu-ping.cc	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/examples/fd-emu-ping.cc	2023-09-27 13:30:37.646839100 -0700
@@ -184,7 +184,7 @@
 #ifdef HAVE_PACKET_H
     if (emuMode == "raw")
     {
-        EmuFdNetDeviceHelper* raw = new EmuFdNetDeviceHelper;
+        auto raw = new EmuFdNetDeviceHelper;
         raw->SetDeviceName(deviceName);
         helper = raw;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/examples/fd-emu-send.cc ns-3.40/src/fd-net-device/examples/fd-emu-send.cc
--- ns-3.39/src/fd-net-device/examples/fd-emu-send.cc	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/examples/fd-emu-send.cc	2023-09-27 13:30:37.646839100 -0700
@@ -57,15 +57,15 @@
 
     int packets = 10000000;
 
-    Mac48Address sender = Mac48Address("00:00:00:aa:00:01");
-    Mac48Address receiver = Mac48Address("ff:ff:ff:ff:ff:ff");
+    Mac48Address sender("00:00:00:aa:00:01");
+    Mac48Address receiver("ff:ff:ff:ff:ff:ff");
 
     int packetsSize = 64;
     Ptr<Packet> packet = Create<Packet>(packetsSize);
     EthernetHeader header;
 
     ssize_t len = (size_t)packet->GetSize();
-    uint8_t* buffer = (uint8_t*)malloc(len);
+    auto buffer = (uint8_t*)malloc(len);
     packet->CopyData(buffer, len);
 
     int sent = 0;
@@ -166,7 +166,7 @@
 #ifdef HAVE_PACKET_H
     if (emuMode == "raw")
     {
-        EmuFdNetDeviceHelper* raw = new EmuFdNetDeviceHelper;
+        auto raw = new EmuFdNetDeviceHelper;
         raw->SetDeviceName(deviceName);
         helper = raw;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/examples/fd-emu-tc.cc ns-3.40/src/fd-net-device/examples/fd-emu-tc.cc
--- ns-3.39/src/fd-net-device/examples/fd-emu-tc.cc	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/examples/fd-emu-tc.cc	2023-09-27 13:30:37.646839100 -0700
@@ -168,11 +168,11 @@
 #ifdef HAVE_PACKET_H
     if (emuMode == "raw")
     {
-        EmuFdNetDeviceHelper* raw0 = new EmuFdNetDeviceHelper;
+        auto raw0 = new EmuFdNetDeviceHelper;
         raw0->SetDeviceName(deviceName0);
         helper0 = raw0;
 
-        EmuFdNetDeviceHelper* raw1 = new EmuFdNetDeviceHelper;
+        auto raw1 = new EmuFdNetDeviceHelper;
         raw1->SetDeviceName(deviceName1);
         helper1 = raw1;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/helper/dpdk-net-device-helper.h ns-3.40/src/fd-net-device/helper/dpdk-net-device-helper.h
--- ns-3.39/src/fd-net-device/helper/dpdk-net-device-helper.h	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/helper/dpdk-net-device-helper.h	2023-09-27 13:30:37.646839100 -0700
@@ -21,7 +21,7 @@
 #ifndef DPDK_NET_DEVICE_HELPER_H
 #define DPDK_NET_DEVICE_HELPER_H
 
-#include "ns3/emu-fd-net-device-helper.h"
+#include "emu-fd-net-device-helper.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/helper/emu-fd-net-device-helper.h ns-3.40/src/fd-net-device/helper/emu-fd-net-device-helper.h
--- ns-3.39/src/fd-net-device/helper/emu-fd-net-device-helper.h	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/helper/emu-fd-net-device-helper.h	2023-09-27 13:30:37.646839100 -0700
@@ -19,8 +19,9 @@
 #ifndef EMU_FD_NET_DEVICE_HELPER_H
 #define EMU_FD_NET_DEVICE_HELPER_H
 
+#include "fd-net-device-helper.h"
+
 #include "ns3/attribute.h"
-#include "ns3/fd-net-device-helper.h"
 #include "ns3/fd-net-device.h"
 #include "ns3/net-device-container.h"
 #include "ns3/node-container.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/helper/fd-net-device-helper.cc ns-3.40/src/fd-net-device/helper/fd-net-device-helper.cc
--- ns-3.39/src/fd-net-device/helper/fd-net-device-helper.cc	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/helper/fd-net-device-helper.cc	2023-09-27 13:30:37.646839100 -0700
@@ -199,7 +199,7 @@
 {
     NetDeviceContainer devs;
 
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); i++)
+    for (auto i = c.Begin(); i != c.End(); i++)
     {
         devs.Add(InstallPriv(*i));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/helper/netmap-net-device-helper.h ns-3.40/src/fd-net-device/helper/netmap-net-device-helper.h
--- ns-3.39/src/fd-net-device/helper/netmap-net-device-helper.h	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/helper/netmap-net-device-helper.h	2023-09-27 13:30:37.646839100 -0700
@@ -20,8 +20,9 @@
 #ifndef NETMAP_NET_DEVICE_HELPER_H
 #define NETMAP_NET_DEVICE_HELPER_H
 
+#include "fd-net-device-helper.h"
+
 #include "ns3/attribute.h"
-#include "ns3/fd-net-device-helper.h"
 #include "ns3/fd-net-device.h"
 #include "ns3/net-device-container.h"
 #include "ns3/netmap-net-device.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/helper/tap-device-creator.cc ns-3.40/src/fd-net-device/helper/tap-device-creator.cc
--- ns-3.39/src/fd-net-device/helper/tap-device-creator.cc	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/helper/tap-device-creator.cc	2023-09-27 13:30:37.646839100 -0700
@@ -216,8 +216,8 @@
 int
 CreateTap(char* deviceName,
           const char* mac,
-          const int ifftap,
-          const int iffpi,
+          bool ifftap,
+          bool iffpi,
           const char* ip4,
           const char* netmask,
           const char* ip6,
@@ -293,8 +293,8 @@
     char* mac = nullptr;
     char* netmask = nullptr;
     char* path = nullptr;
-    int tap = false;
-    int pi = false;
+    bool tap = false;
+    bool pi = false;
     int prefix = -1;
 
     while ((c = getopt(argc, argv, "vd:i:m:n:I:P:thp:")) != -1)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/helper/tap-fd-net-device-helper.cc ns-3.40/src/fd-net-device/helper/tap-fd-net-device-helper.cc
--- ns-3.39/src/fd-net-device/helper/tap-fd-net-device-helper.cc	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/helper/tap-fd-net-device-helper.cc	2023-09-27 13:30:37.646839100 -0700
@@ -22,7 +22,6 @@
 #include "ns3/abort.h"
 #include "ns3/config.h"
 #include "ns3/fd-net-device.h"
-#include "ns3/internet-module.h"
 #include "ns3/log.h"
 #include "ns3/names.h"
 #include "ns3/object-factory.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/model/dpdk-net-device.cc ns-3.40/src/fd-net-device/model/dpdk-net-device.cc
--- ns-3.39/src/fd-net-device/model/dpdk-net-device.cc	2023-07-05 14:23:47.793427200 -0700
+++ ns-3.40/src/fd-net-device/model/dpdk-net-device.cc	2023-09-27 13:30:37.646839100 -0700
@@ -144,14 +144,11 @@
         /* print link status if flag set */
         if (printFlag == 1)
         {
-            if (link.link_status)
+            if (!link.link_status)
             {
-                continue;
-            }
-            else
-            {
-                printf("Port %d Link Down\n", m_portId);
+                NS_LOG_INFO("Port " << +m_portId << " Link Down");
             }
+
             continue;
         }
         /* clear allPortsUp flag if any link down */
@@ -186,7 +183,7 @@
 {
     if (signum == SIGINT || signum == SIGTERM)
     {
-        printf("\n\nSignal %d received, preparing to exit...\n", signum);
+        NS_LOG_INFO("Signal " << signum << " received, preparing to exit...");
         m_forceQuit = true;
     }
 }
@@ -260,7 +257,7 @@
     command.append(dpdkDriver);
     command.append(" ");
     command.append(m_deviceName);
-    printf("Executing: %s\n", command.c_str());
+    NS_LOG_INFO("Executing: " << command);
     if (system(command.c_str()))
     {
         rte_exit(EXIT_FAILURE, "Execution failed - bye\n");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/fd-net-device/model/fd-net-device.cc ns-3.40/src/fd-net-device/model/fd-net-device.cc
--- ns-3.39/src/fd-net-device/model/fd-net-device.cc	2023-07-05 14:23:47.797427200 -0700
+++ ns-3.40/src/fd-net-device/model/fd-net-device.cc	2023-09-27 13:30:37.646839100 -0700
@@ -61,7 +61,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    uint8_t* buf = (uint8_t*)malloc(m_bufferSize);
+    auto buf = (uint8_t*)malloc(m_bufferSize);
     NS_ABORT_MSG_IF(buf == nullptr, "malloc() failed");
 
     NS_LOG_LOGIC("Calling read on fd " << m_fd);
@@ -350,7 +350,7 @@
 AddPIHeader(uint8_t*& buf, size_t& len)
 {
     // Synthesize PI header for our friend the kernel
-    uint8_t* buf2 = (uint8_t*)malloc(len + 4);
+    auto buf2 = (uint8_t*)malloc(len + 4);
     memcpy(buf2 + 4, buf, len);
     len += 4;
 
@@ -617,7 +617,7 @@
 
     NS_LOG_LOGIC("calling write");
 
-    size_t len = (size_t)packet->GetSize();
+    auto len = (size_t)packet->GetSize();
     uint8_t* buffer = AllocateBuffer(len);
     if (!buffer)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/examples/flowmon-parse-results.py ns-3.40/src/flow-monitor/examples/flowmon-parse-results.py
--- ns-3.39/src/flow-monitor/examples/flowmon-parse-results.py	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/examples/flowmon-parse-results.py	2023-09-27 13:30:37.646839100 -0700
@@ -179,23 +179,23 @@
 
 
 def main(argv):
-    file_obj = open(argv[1])
-    print("Reading XML file ", end=" ")
+    with open(argv[1], encoding="utf-8") as file_obj:
+        print("Reading XML file ", end=" ")
 
-    sys.stdout.flush()
-    level = 0
-    sim_list = []
-    for event, elem in ElementTree.iterparse(file_obj, events=("start", "end")):
-        if event == "start":
-            level += 1
-        if event == "end":
-            level -= 1
-            if level == 0 and elem.tag == 'FlowMonitor':
-                sim = Simulation(elem)
-                sim_list.append(sim)
-                elem.clear() # won't need this any more
-                sys.stdout.write(".")
-                sys.stdout.flush()
+        sys.stdout.flush()
+        level = 0
+        sim_list = []
+        for event, elem in ElementTree.iterparse(file_obj, events=("start", "end")):
+            if event == "start":
+                level += 1
+            if event == "end":
+                level -= 1
+                if level == 0 and elem.tag == 'FlowMonitor':
+                    sim = Simulation(elem)
+                    sim_list.append(sim)
+                    elem.clear() # won't need this any more
+                    sys.stdout.write(".")
+                    sys.stdout.flush()
     print(" done.")
 
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/helper/flow-monitor-helper.cc ns-3.40/src/flow-monitor/helper/flow-monitor-helper.cc
--- ns-3.39/src/flow-monitor/helper/flow-monitor-helper.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/helper/flow-monitor-helper.cc	2023-09-27 13:30:37.646839100 -0700
@@ -112,7 +112,7 @@
 Ptr<FlowMonitor>
 FlowMonitorHelper::Install(NodeContainer nodes)
 {
-    for (NodeContainer::Iterator i = nodes.Begin(); i != nodes.End(); ++i)
+    for (auto i = nodes.Begin(); i != nodes.End(); ++i)
     {
         Ptr<Node> node = *i;
         if (node->GetObject<Ipv4L3Protocol>() || node->GetObject<Ipv6L3Protocol>())
@@ -126,7 +126,7 @@
 Ptr<FlowMonitor>
 FlowMonitorHelper::InstallAll()
 {
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> node = *i;
         if (node->GetObject<Ipv4L3Protocol>() || node->GetObject<Ipv6L3Protocol>())
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/flow-monitor.cc ns-3.40/src/flow-monitor/model/flow-monitor.cc
--- ns-3.39/src/flow-monitor/model/flow-monitor.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/flow-monitor.cc	2023-09-27 13:30:37.646839100 -0700
@@ -102,9 +102,7 @@
     NS_LOG_FUNCTION(this);
     Simulator::Cancel(m_startEvent);
     Simulator::Cancel(m_stopEvent);
-    for (std::list<Ptr<FlowClassifier>>::iterator iter = m_classifiers.begin();
-         iter != m_classifiers.end();
-         iter++)
+    for (auto iter = m_classifiers.begin(); iter != m_classifiers.end(); iter++)
     {
         *iter = nullptr;
     }
@@ -120,8 +118,7 @@
 FlowMonitor::GetStatsForFlow(FlowId flowId)
 {
     NS_LOG_FUNCTION(this);
-    FlowStatsContainerI iter;
-    iter = m_flowStats.find(flowId);
+    auto iter = m_flowStats.find(flowId);
     if (iter == m_flowStats.end())
     {
         FlowMonitor::FlowStats& ref = m_flowStats[flowId];
@@ -191,7 +188,7 @@
         return;
     }
     std::pair<FlowId, FlowPacketId> key(flowId, packetId);
-    TrackedPacketMap::iterator tracked = m_trackedPackets.find(key);
+    auto tracked = m_trackedPackets.find(key);
     if (tracked == m_trackedPackets.end())
     {
         NS_LOG_WARN("Received packet forward report (flowId="
@@ -218,7 +215,7 @@
         NS_LOG_DEBUG("FlowMonitor not enabled; returning");
         return;
     }
-    TrackedPacketMap::iterator tracked = m_trackedPackets.find(std::make_pair(flowId, packetId));
+    auto tracked = m_trackedPackets.find(std::make_pair(flowId, packetId));
     if (tracked == m_trackedPackets.end())
     {
         NS_LOG_WARN("Received packet last-tx report (flowId="
@@ -302,7 +299,7 @@
     NS_LOG_DEBUG("++stats.packetsDropped["
                  << reasonCode << "]; // becomes: " << stats.packetsDropped[reasonCode]);
 
-    TrackedPacketMap::iterator tracked = m_trackedPackets.find(std::make_pair(flowId, packetId));
+    auto tracked = m_trackedPackets.find(std::make_pair(flowId, packetId));
     if (tracked != m_trackedPackets.end())
     {
         // we don't need to track this packet anymore
@@ -325,13 +322,12 @@
     NS_LOG_FUNCTION(this << maxDelay.As(Time::S));
     Time now = Simulator::Now();
 
-    for (TrackedPacketMap::iterator iter = m_trackedPackets.begin();
-         iter != m_trackedPackets.end();)
+    for (auto iter = m_trackedPackets.begin(); iter != m_trackedPackets.end();)
     {
         if (now - iter->second.lastSeenTime >= maxDelay)
         {
             // packet is considered lost, add it to the loss statistics
-            FlowStatsContainerI flow = m_flowStats.find(iter->first.first);
+            auto flow = m_flowStats.find(iter->first.first);
             NS_ASSERT(flow != m_flowStats.end());
             flow->second.lostPackets++;
 
@@ -444,7 +440,7 @@
     indent += 2;
     os << std::string(indent, ' ') << "<FlowStats>\n";
     indent += 2;
-    for (FlowStatsContainerCI flowI = m_flowStats.begin(); flowI != m_flowStats.end(); flowI++)
+    for (auto flowI = m_flowStats.begin(); flowI != m_flowStats.end(); flowI++)
     {
         os << std::string(indent, ' ');
 #define ATTRIB(name) << " " #name "=\"" << flowI->second.name << "\""
@@ -492,9 +488,7 @@
     indent -= 2;
     os << std::string(indent, ' ') << "</FlowStats>\n";
 
-    for (std::list<Ptr<FlowClassifier>>::iterator iter = m_classifiers.begin();
-         iter != m_classifiers.end();
-         iter++)
+    for (auto iter = m_classifiers.begin(); iter != m_classifiers.end(); iter++)
     {
         (*iter)->SerializeToXmlStream(os, indent);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/flow-monitor.h ns-3.40/src/flow-monitor/model/flow-monitor.h
--- ns-3.39/src/flow-monitor/model/flow-monitor.h	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/flow-monitor.h	2023-09-27 13:30:37.646839100 -0700
@@ -20,9 +20,10 @@
 #ifndef FLOW_MONITOR_H
 #define FLOW_MONITOR_H
 
+#include "flow-classifier.h"
+#include "flow-probe.h"
+
 #include "ns3/event-id.h"
-#include "ns3/flow-classifier.h"
-#include "ns3/flow-probe.h"
 #include "ns3/histogram.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/flow-probe.cc ns-3.40/src/flow-monitor/model/flow-probe.cc
--- ns-3.39/src/flow-monitor/model/flow-probe.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/flow-probe.cc	2023-09-27 13:30:37.646839100 -0700
@@ -17,9 +17,9 @@
 // Author: Gustavo J. A. M. Carneiro  <gjc@inescporto.pt> <gjcarneiro@gmail.com>
 //
 
-#include "ns3/flow-probe.h"
+#include "flow-probe.h"
 
-#include "ns3/flow-monitor.h"
+#include "flow-monitor.h"
 
 namespace ns3
 {
@@ -88,7 +88,7 @@
 
     indent += 2;
 
-    for (Stats::const_iterator iter = m_stats.begin(); iter != m_stats.end(); iter++)
+    for (auto iter = m_stats.begin(); iter != m_stats.end(); iter++)
     {
         os << std::string(indent, ' ');
         os << "<FlowStats "
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/flow-probe.h ns-3.40/src/flow-monitor/model/flow-probe.h
--- ns-3.39/src/flow-monitor/model/flow-probe.h	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/flow-probe.h	2023-09-27 13:30:37.646839100 -0700
@@ -20,7 +20,8 @@
 #ifndef FLOW_PROBE_H
 #define FLOW_PROBE_H
 
-#include "ns3/flow-classifier.h"
+#include "flow-classifier.h"
+
 #include "ns3/nstime.h"
 #include "ns3/object.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/ipv4-flow-classifier.cc ns-3.40/src/flow-monitor/model/ipv4-flow-classifier.cc
--- ns-3.39/src/flow-monitor/model/ipv4-flow-classifier.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/ipv4-flow-classifier.cc	2023-09-27 13:30:37.646839100 -0700
@@ -145,8 +145,7 @@
     tuple.destinationPort = dstPort;
 
     // try to insert the tuple, but check if it already exists
-    std::pair<std::map<FiveTuple, FlowId>::iterator, bool> insert =
-        m_flowMap.insert(std::pair<FiveTuple, FlowId>(tuple, 0));
+    auto insert = m_flowMap.insert(std::pair<FiveTuple, FlowId>(tuple, 0));
 
     // if the insertion succeeded, we need to assign this tuple a new flow identifier
     if (insert.second)
@@ -163,9 +162,8 @@
 
     // increment the counter of packets with the same DSCP value
     Ipv4Header::DscpType dscp = ipHeader.GetDscp();
-    std::pair<std::map<Ipv4Header::DscpType, uint32_t>::iterator, bool> dscpInserter =
-        m_flowDscpMap[insert.first->second].insert(
-            std::pair<Ipv4Header::DscpType, uint32_t>(dscp, 1));
+    auto dscpInserter = m_flowDscpMap[insert.first->second].insert(
+        std::pair<Ipv4Header::DscpType, uint32_t>(dscp, 1));
 
     // if the insertion did not succeed, we need to increment the counter
     if (!dscpInserter.second)
@@ -182,9 +180,7 @@
 Ipv4FlowClassifier::FiveTuple
 Ipv4FlowClassifier::FindFlow(FlowId flowId) const
 {
-    for (std::map<FiveTuple, FlowId>::const_iterator iter = m_flowMap.begin();
-         iter != m_flowMap.end();
-         iter++)
+    for (auto iter = m_flowMap.begin(); iter != m_flowMap.end(); iter++)
     {
         if (iter->second == flowId)
         {
@@ -206,8 +202,7 @@
 std::vector<std::pair<Ipv4Header::DscpType, uint32_t>>
 Ipv4FlowClassifier::GetDscpCounts(FlowId flowId) const
 {
-    std::map<FlowId, std::map<Ipv4Header::DscpType, uint32_t>>::const_iterator flow =
-        m_flowDscpMap.find(flowId);
+    auto flow = m_flowDscpMap.find(flowId);
 
     if (flow == m_flowDscpMap.end())
     {
@@ -227,9 +222,7 @@
     os << "<Ipv4FlowClassifier>\n";
 
     indent += 2;
-    for (std::map<FiveTuple, FlowId>::const_iterator iter = m_flowMap.begin();
-         iter != m_flowMap.end();
-         iter++)
+    for (auto iter = m_flowMap.begin(); iter != m_flowMap.end(); iter++)
     {
         Indent(os, indent);
         os << "<Flow flowId=\"" << iter->second << "\""
@@ -240,14 +233,11 @@
            << " destinationPort=\"" << iter->first.destinationPort << "\">\n";
 
         indent += 2;
-        std::map<FlowId, std::map<Ipv4Header::DscpType, uint32_t>>::const_iterator flow =
-            m_flowDscpMap.find(iter->second);
+        auto flow = m_flowDscpMap.find(iter->second);
 
         if (flow != m_flowDscpMap.end())
         {
-            for (std::map<Ipv4Header::DscpType, uint32_t>::const_iterator i = flow->second.begin();
-                 i != flow->second.end();
-                 i++)
+            for (auto i = flow->second.begin(); i != flow->second.end(); i++)
             {
                 Indent(os, indent);
                 os << "<Dscp value=\"0x" << std::hex << static_cast<uint32_t>(i->first) << "\""
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/ipv4-flow-classifier.h ns-3.40/src/flow-monitor/model/ipv4-flow-classifier.h
--- ns-3.39/src/flow-monitor/model/ipv4-flow-classifier.h	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/ipv4-flow-classifier.h	2023-09-27 13:30:37.646839100 -0700
@@ -20,7 +20,8 @@
 #ifndef IPV4_FLOW_CLASSIFIER_H
 #define IPV4_FLOW_CLASSIFIER_H
 
-#include "ns3/flow-classifier.h"
+#include "flow-classifier.h"
+
 #include "ns3/ipv4-header.h"
 
 #include <map>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/ipv4-flow-probe.cc ns-3.40/src/flow-monitor/model/ipv4-flow-probe.cc
--- ns-3.39/src/flow-monitor/model/ipv4-flow-probe.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/ipv4-flow-probe.cc	2023-09-27 13:30:37.646839100 -0700
@@ -17,12 +17,13 @@
 // Author: Gustavo J. A. M. Carneiro  <gjc@inescporto.pt> <gjcarneiro@gmail.com>
 //
 
-#include "ns3/ipv4-flow-probe.h"
+#include "ipv4-flow-probe.h"
+
+#include "flow-monitor.h"
+#include "ipv4-flow-classifier.h"
 
 #include "ns3/config.h"
 #include "ns3/flow-id-tag.h"
-#include "ns3/flow-monitor.h"
-#include "ns3/ipv4-flow-classifier.h"
 #include "ns3/log.h"
 #include "ns3/node.h"
 #include "ns3/packet.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/ipv4-flow-probe.h ns-3.40/src/flow-monitor/model/ipv4-flow-probe.h
--- ns-3.39/src/flow-monitor/model/ipv4-flow-probe.h	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/ipv4-flow-probe.h	2023-09-27 13:30:37.646839100 -0700
@@ -20,8 +20,9 @@
 #ifndef IPV4_FLOW_PROBE_H
 #define IPV4_FLOW_PROBE_H
 
-#include "ns3/flow-probe.h"
-#include "ns3/ipv4-flow-classifier.h"
+#include "flow-probe.h"
+#include "ipv4-flow-classifier.h"
+
 #include "ns3/ipv4-l3-protocol.h"
 #include "ns3/queue-item.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/ipv6-flow-classifier.cc ns-3.40/src/flow-monitor/model/ipv6-flow-classifier.cc
--- ns-3.39/src/flow-monitor/model/ipv6-flow-classifier.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/ipv6-flow-classifier.cc	2023-09-27 13:30:37.646839100 -0700
@@ -146,8 +146,7 @@
     tuple.destinationPort = dstPort;
 
     // try to insert the tuple, but check if it already exists
-    std::pair<std::map<FiveTuple, FlowId>::iterator, bool> insert =
-        m_flowMap.insert(std::pair<FiveTuple, FlowId>(tuple, 0));
+    auto insert = m_flowMap.insert(std::pair<FiveTuple, FlowId>(tuple, 0));
 
     // if the insertion succeeded, we need to assign this tuple a new flow identifier
     if (insert.second)
@@ -164,9 +163,8 @@
 
     // increment the counter of packets with the same DSCP value
     Ipv6Header::DscpType dscp = ipHeader.GetDscp();
-    std::pair<std::map<Ipv6Header::DscpType, uint32_t>::iterator, bool> dscpInserter =
-        m_flowDscpMap[insert.first->second].insert(
-            std::pair<Ipv6Header::DscpType, uint32_t>(dscp, 1));
+    auto dscpInserter = m_flowDscpMap[insert.first->second].insert(
+        std::pair<Ipv6Header::DscpType, uint32_t>(dscp, 1));
 
     // if the insertion did not succeed, we need to increment the counter
     if (!dscpInserter.second)
@@ -183,9 +181,7 @@
 Ipv6FlowClassifier::FiveTuple
 Ipv6FlowClassifier::FindFlow(FlowId flowId) const
 {
-    for (std::map<FiveTuple, FlowId>::const_iterator iter = m_flowMap.begin();
-         iter != m_flowMap.end();
-         iter++)
+    for (auto iter = m_flowMap.begin(); iter != m_flowMap.end(); iter++)
     {
         if (iter->second == flowId)
         {
@@ -207,8 +203,7 @@
 std::vector<std::pair<Ipv6Header::DscpType, uint32_t>>
 Ipv6FlowClassifier::GetDscpCounts(FlowId flowId) const
 {
-    std::map<FlowId, std::map<Ipv6Header::DscpType, uint32_t>>::const_iterator flow =
-        m_flowDscpMap.find(flowId);
+    auto flow = m_flowDscpMap.find(flowId);
 
     if (flow == m_flowDscpMap.end())
     {
@@ -228,9 +223,7 @@
     os << "<Ipv6FlowClassifier>\n";
 
     indent += 2;
-    for (std::map<FiveTuple, FlowId>::const_iterator iter = m_flowMap.begin();
-         iter != m_flowMap.end();
-         iter++)
+    for (auto iter = m_flowMap.begin(); iter != m_flowMap.end(); iter++)
     {
         Indent(os, indent);
         os << "<Flow flowId=\"" << iter->second << "\""
@@ -241,14 +234,11 @@
            << " destinationPort=\"" << iter->first.destinationPort << "\">\n";
 
         indent += 2;
-        std::map<FlowId, std::map<Ipv6Header::DscpType, uint32_t>>::const_iterator flow =
-            m_flowDscpMap.find(iter->second);
+        auto flow = m_flowDscpMap.find(iter->second);
 
         if (flow != m_flowDscpMap.end())
         {
-            for (std::map<Ipv6Header::DscpType, uint32_t>::const_iterator i = flow->second.begin();
-                 i != flow->second.end();
-                 i++)
+            for (auto i = flow->second.begin(); i != flow->second.end(); i++)
             {
                 Indent(os, indent);
                 os << "<Dscp value=\"0x" << std::hex << static_cast<uint32_t>(i->first) << "\""
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/ipv6-flow-classifier.h ns-3.40/src/flow-monitor/model/ipv6-flow-classifier.h
--- ns-3.39/src/flow-monitor/model/ipv6-flow-classifier.h	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/ipv6-flow-classifier.h	2023-09-27 13:30:37.646839100 -0700
@@ -21,7 +21,8 @@
 #ifndef IPV6_FLOW_CLASSIFIER_H
 #define IPV6_FLOW_CLASSIFIER_H
 
-#include "ns3/flow-classifier.h"
+#include "flow-classifier.h"
+
 #include "ns3/ipv6-header.h"
 
 #include <map>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/ipv6-flow-probe.cc ns-3.40/src/flow-monitor/model/ipv6-flow-probe.cc
--- ns-3.39/src/flow-monitor/model/ipv6-flow-probe.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/ipv6-flow-probe.cc	2023-09-27 13:30:37.646839100 -0700
@@ -18,12 +18,13 @@
 // Modifications: Tommaso Pecorella <tommaso.pecorella@unifi.it>
 //
 
-#include "ns3/ipv6-flow-probe.h"
+#include "ipv6-flow-probe.h"
+
+#include "flow-monitor.h"
+#include "ipv6-flow-classifier.h"
 
 #include "ns3/config.h"
 #include "ns3/flow-id-tag.h"
-#include "ns3/flow-monitor.h"
-#include "ns3/ipv6-flow-classifier.h"
 #include "ns3/log.h"
 #include "ns3/node.h"
 #include "ns3/packet.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/flow-monitor/model/ipv6-flow-probe.h ns-3.40/src/flow-monitor/model/ipv6-flow-probe.h
--- ns-3.39/src/flow-monitor/model/ipv6-flow-probe.h	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/flow-monitor/model/ipv6-flow-probe.h	2023-09-27 13:30:37.646839100 -0700
@@ -21,8 +21,9 @@
 #ifndef IPV6_FLOW_PROBE_H
 #define IPV6_FLOW_PROBE_H
 
-#include "ns3/flow-probe.h"
-#include "ns3/ipv6-flow-classifier.h"
+#include "flow-probe.h"
+#include "ipv6-flow-classifier.h"
+
 #include "ns3/ipv6-l3-protocol.h"
 #include "ns3/queue-item.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/doc/tcp.rst ns-3.40/src/internet/doc/tcp.rst
--- ns-3.39/src/internet/doc/tcp.rst	2023-07-05 14:23:47.833427400 -0700
+++ ns-3.40/src/internet/doc/tcp.rst	2023-09-27 13:30:37.650839000 -0700
@@ -456,7 +456,7 @@
 by a full-sized segment (SMSS).  In contrast, in ns-3 NewReno, cwnd is increased
 by (1/cwnd) with a rounding off due to type casting into int.
 
-.. code-block::
+.. code-block:: c++
    :caption: Linux Reno `cwnd` update
 
    if (m_cWndCnt >= w)
@@ -469,7 +469,7 @@
    }
 
 
-.. code-block::
+.. code-block:: c++
    :caption: New Reno `cwnd` update
 
    if (segmentsAcked > 0)
@@ -1840,7 +1840,7 @@
 CreateReceiverSocket, setting an Rx buffer value of 0 bytes (at line 6 of the
 following code):
 
-.. code-block::
+.. code-block:: c++
    :linenos:
    :emphasize-lines: 6,7,8
 
@@ -1987,7 +1987,7 @@
 the SENDER should send a window probe, and the receiver should reply reporting
 again a zero window situation. At first, we investigates on what the sender sends:
 
-.. code-block::
+.. code-block:: c++
       :linenos:
       :emphasize-lines: 1,6,7,11
 
@@ -2020,7 +2020,7 @@
 to check (line 6) between 6.0 and 7.0 simulated seconds that the probe is sent.
 Only one probe is allowed, and this is the reason for the check at line 11.
 
-.. code-block::
+.. code-block:: c++
    :linenos:
    :emphasize-lines: 6,7
 
@@ -2072,7 +2072,7 @@
 To be sure that the sender receives the window update, we can use the Rx
 method:
 
-.. code-block::
+.. code-block:: c++
    :linenos:
    :emphasize-lines: 5
 
@@ -2137,7 +2137,6 @@
 
 .. code-block:: bash
 
-
     ./ns3 shell && gdb --args ./build/utils/ns3-dev-test-runner-debug --test-name=tcp-zero-window-test --stop-on-failure --fullness=QUICK --assert-on-failure --verbose
 
 and then, hit "Run".
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/internet-stack-helper.cc ns-3.40/src/internet/helper/internet-stack-helper.cc
--- ns-3.39/src/internet/helper/internet-stack-helper.cc	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/internet-stack-helper.cc	2023-09-27 13:30:37.650839000 -0700
@@ -223,7 +223,7 @@
 InternetStackHelper::AssignStreams(NodeContainer c, int64_t stream)
 {
     int64_t currentStream = stream;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<GlobalRouter> router = node->GetObject<GlobalRouter>();
@@ -267,7 +267,7 @@
 void
 InternetStackHelper::Install(NodeContainer c) const
 {
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Install(*i);
     }
@@ -404,11 +404,11 @@
 bool
 InternetStackHelper::PcapHooked(Ptr<Ipv4> ipv4)
 {
-    for (InterfaceFileMapIpv4::const_iterator i = g_interfaceFileMapIpv4.begin();
-         i != g_interfaceFileMapIpv4.end();
-         ++i)
+    auto id = ipv4->GetObject<Node>()->GetId();
+
+    for (auto i = g_interfaceFileMapIpv4.begin(); i != g_interfaceFileMapIpv4.end(); ++i)
     {
-        if ((*i).first.first == ipv4->GetObject<Node>()->GetId())
+        if ((*i).first.first == id)
         {
             return true;
         }
@@ -510,11 +510,11 @@
 bool
 InternetStackHelper::PcapHooked(Ptr<Ipv6> ipv6)
 {
-    for (InterfaceFileMapIpv6::const_iterator i = g_interfaceFileMapIpv6.begin();
-         i != g_interfaceFileMapIpv6.end();
-         ++i)
+    auto id = ipv6->GetObject<Node>()->GetId();
+
+    for (auto i = g_interfaceFileMapIpv6.begin(); i != g_interfaceFileMapIpv6.end(); ++i)
     {
-        if ((*i).first.first == ipv6->GetObject<Node>()->GetId())
+        if ((*i).first.first == id)
         {
             return true;
         }
@@ -774,11 +774,11 @@
 bool
 InternetStackHelper::AsciiHooked(Ptr<Ipv4> ipv4)
 {
-    for (InterfaceStreamMapIpv4::const_iterator i = g_interfaceStreamMapIpv4.begin();
-         i != g_interfaceStreamMapIpv4.end();
-         ++i)
+    auto id = ipv4->GetObject<Node>()->GetId();
+
+    for (auto i = g_interfaceStreamMapIpv4.begin(); i != g_interfaceStreamMapIpv4.end(); ++i)
     {
-        if ((*i).first.first == ipv4->GetObject<Node>()->GetId())
+        if ((*i).first.first == id)
         {
             return true;
         }
@@ -1118,11 +1118,11 @@
 bool
 InternetStackHelper::AsciiHooked(Ptr<Ipv6> ipv6)
 {
-    for (InterfaceStreamMapIpv6::const_iterator i = g_interfaceStreamMapIpv6.begin();
-         i != g_interfaceStreamMapIpv6.end();
-         ++i)
+    auto id = ipv6->GetObject<Node>()->GetId();
+
+    for (auto i = g_interfaceStreamMapIpv6.begin(); i != g_interfaceStreamMapIpv6.end(); ++i)
     {
-        if ((*i).first.first == ipv6->GetObject<Node>()->GetId())
+        if ((*i).first.first == id)
         {
             return true;
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/internet-trace-helper.cc ns-3.40/src/internet/helper/internet-trace-helper.cc
--- ns-3.39/src/internet/helper/internet-trace-helper.cc	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/internet-trace-helper.cc	2023-09-27 13:30:37.650839000 -0700
@@ -57,17 +57,16 @@
 void
 PcapHelperForIpv4::EnablePcapIpv4(std::string prefix, Ipv4InterfaceContainer c)
 {
-    for (Ipv4InterfaceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
-        std::pair<Ptr<Ipv4>, uint32_t> pair = *i;
-        EnablePcapIpv4(prefix, pair.first, pair.second, false);
+        EnablePcapIpv4(prefix, (*i).first, (*i).second, false);
     }
 }
 
 void
 PcapHelperForIpv4::EnablePcapIpv4(std::string prefix, NodeContainer n)
 {
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
@@ -95,7 +94,7 @@
 {
     NodeContainer n = NodeContainer::GetGlobal();
 
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         if (node->GetId() != nodeid)
@@ -198,10 +197,9 @@
                                              std::string prefix,
                                              Ipv4InterfaceContainer c)
 {
-    for (Ipv4InterfaceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
-        std::pair<Ptr<Ipv4>, uint32_t> pair = *i;
-        EnableAsciiIpv4Internal(stream, prefix, pair.first, pair.second, false);
+        EnableAsciiIpv4Internal(stream, prefix, (*i).first, (*i).second, false);
     }
 }
 
@@ -231,7 +229,7 @@
                                              std::string prefix,
                                              NodeContainer n)
 {
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
@@ -299,7 +297,7 @@
 {
     NodeContainer n = NodeContainer::GetGlobal();
 
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         if (node->GetId() != nodeid)
@@ -339,17 +337,16 @@
 void
 PcapHelperForIpv6::EnablePcapIpv6(std::string prefix, Ipv6InterfaceContainer c)
 {
-    for (Ipv6InterfaceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
-        std::pair<Ptr<Ipv6>, uint32_t> pair = *i;
-        EnablePcapIpv6(prefix, pair.first, pair.second, false);
+        EnablePcapIpv6(prefix, (*i).first, (*i).second, false);
     }
 }
 
 void
 PcapHelperForIpv6::EnablePcapIpv6(std::string prefix, NodeContainer n)
 {
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
@@ -377,7 +374,7 @@
 {
     NodeContainer n = NodeContainer::GetGlobal();
 
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         if (node->GetId() != nodeid)
@@ -480,10 +477,9 @@
                                              std::string prefix,
                                              Ipv6InterfaceContainer c)
 {
-    for (Ipv6InterfaceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
-        std::pair<Ptr<Ipv6>, uint32_t> pair = *i;
-        EnableAsciiIpv6Internal(stream, prefix, pair.first, pair.second, false);
+        EnableAsciiIpv6Internal(stream, prefix, (*i).first, (*i).second, false);
     }
 }
 
@@ -513,7 +509,7 @@
                                              std::string prefix,
                                              NodeContainer n)
 {
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
@@ -580,7 +576,7 @@
 {
     NodeContainer n = NodeContainer::GetGlobal();
 
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         if (node->GetId() != nodeid)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/internet-trace-helper.h ns-3.40/src/internet/helper/internet-trace-helper.h
--- ns-3.39/src/internet/helper/internet-trace-helper.h	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/internet-trace-helper.h	2023-09-27 13:30:37.650839000 -0700
@@ -18,10 +18,11 @@
 #ifndef INTERNET_TRACE_HELPER_H
 #define INTERNET_TRACE_HELPER_H
 
+#include "ipv4-interface-container.h"
+#include "ipv6-interface-container.h"
+
 #include "ns3/assert.h"
-#include "ns3/ipv4-interface-container.h"
 #include "ns3/ipv4.h"
-#include "ns3/ipv6-interface-container.h"
 #include "ns3/ipv6.h"
 #include "ns3/trace-helper.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv4-global-routing-helper.h ns-3.40/src/internet/helper/ipv4-global-routing-helper.h
--- ns-3.39/src/internet/helper/ipv4-global-routing-helper.h	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/ipv4-global-routing-helper.h	2023-09-27 13:30:37.650839000 -0700
@@ -19,7 +19,8 @@
 #ifndef IPV4_GLOBAL_ROUTING_HELPER_H
 #define IPV4_GLOBAL_ROUTING_HELPER_H
 
-#include "ns3/ipv4-routing-helper.h"
+#include "ipv4-routing-helper.h"
+
 #include "ns3/node-container.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv4-interface-container.cc ns-3.40/src/internet/helper/ipv4-interface-container.cc
--- ns-3.39/src/internet/helper/ipv4-interface-container.cc	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/ipv4-interface-container.cc	2023-09-27 13:30:37.650839000 -0700
@@ -32,9 +32,7 @@
 void
 Ipv4InterfaceContainer::Add(const Ipv4InterfaceContainer& other)
 {
-    for (InterfaceVector::const_iterator i = other.m_interfaces.begin();
-         i != other.m_interfaces.end();
-         i++)
+    for (auto i = other.m_interfaces.begin(); i != other.m_interfaces.end(); i++)
     {
         m_interfaces.push_back(*i);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv4-list-routing-helper.cc ns-3.40/src/internet/helper/ipv4-list-routing-helper.cc
--- ns-3.39/src/internet/helper/ipv4-list-routing-helper.cc	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/ipv4-list-routing-helper.cc	2023-09-27 13:30:37.650839000 -0700
@@ -30,9 +30,7 @@
 
 Ipv4ListRoutingHelper::~Ipv4ListRoutingHelper()
 {
-    for (std::list<std::pair<const Ipv4RoutingHelper*, int16_t>>::iterator i = m_list.begin();
-         i != m_list.end();
-         ++i)
+    for (auto i = m_list.begin(); i != m_list.end(); ++i)
     {
         delete i->first;
     }
@@ -40,8 +38,7 @@
 
 Ipv4ListRoutingHelper::Ipv4ListRoutingHelper(const Ipv4ListRoutingHelper& o)
 {
-    std::list<std::pair<const Ipv4RoutingHelper*, int16_t>>::const_iterator i;
-    for (i = o.m_list.begin(); i != o.m_list.end(); ++i)
+    for (auto i = o.m_list.begin(); i != o.m_list.end(); ++i)
     {
         m_list.emplace_back(const_cast<const Ipv4RoutingHelper*>(i->first->Copy()), i->second);
     }
@@ -63,9 +60,7 @@
 Ipv4ListRoutingHelper::Create(Ptr<Node> node) const
 {
     Ptr<Ipv4ListRouting> list = CreateObject<Ipv4ListRouting>();
-    for (std::list<std::pair<const Ipv4RoutingHelper*, int16_t>>::const_iterator i = m_list.begin();
-         i != m_list.end();
-         ++i)
+    for (auto i = m_list.begin(); i != m_list.end(); ++i)
     {
         Ptr<Ipv4RoutingProtocol> prot = i->first->Create(node);
         list->AddRoutingProtocol(prot, i->second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv4-list-routing-helper.h ns-3.40/src/internet/helper/ipv4-list-routing-helper.h
--- ns-3.39/src/internet/helper/ipv4-list-routing-helper.h	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/ipv4-list-routing-helper.h	2023-09-27 13:30:37.650839000 -0700
@@ -19,7 +19,7 @@
 #ifndef IPV4_LIST_ROUTING_HELPER_H
 #define IPV4_LIST_ROUTING_HELPER_H
 
-#include "ns3/ipv4-routing-helper.h"
+#include "ipv4-routing-helper.h"
 
 #include <list>
 #include <stdint.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv4-static-routing-helper.cc ns-3.40/src/internet/helper/ipv4-static-routing-helper.cc
--- ns-3.39/src/internet/helper/ipv4-static-routing-helper.cc	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/ipv4-static-routing-helper.cc	2023-09-27 13:30:37.650839000 -0700
@@ -97,7 +97,7 @@
     // We need to convert the NetDeviceContainer to an array of interface
     // numbers
     std::vector<uint32_t> outputInterfaces;
-    for (NetDeviceContainer::Iterator i = output.Begin(); i != output.End(); ++i)
+    for (auto i = output.Begin(); i != output.End(); ++i)
     {
         Ptr<NetDevice> nd = *i;
         int32_t interface = ipv4->GetInterfaceForDevice(nd);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv4-static-routing-helper.h ns-3.40/src/internet/helper/ipv4-static-routing-helper.h
--- ns-3.39/src/internet/helper/ipv4-static-routing-helper.h	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/ipv4-static-routing-helper.h	2023-09-27 13:30:37.650839000 -0700
@@ -18,8 +18,9 @@
 #ifndef IPV4_STATIC_ROUTING_HELPER_H
 #define IPV4_STATIC_ROUTING_HELPER_H
 
+#include "ipv4-routing-helper.h"
+
 #include "ns3/ipv4-address.h"
-#include "ns3/ipv4-routing-helper.h"
 #include "ns3/ipv4-static-routing.h"
 #include "ns3/ipv4.h"
 #include "ns3/net-device-container.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv6-address-helper.cc ns-3.40/src/internet/helper/ipv6-address-helper.cc
--- ns-3.39/src/internet/helper/ipv6-address-helper.cc	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/ipv6-address-helper.cc	2023-09-27 13:30:37.650839000 -0700
@@ -220,11 +220,7 @@
 Ipv6AddressHelper::Assign(const NetDeviceContainer& c)
 {
     NS_LOG_FUNCTION(this);
-    std::vector<bool> withConfiguration;
-    for (uint32_t i = 0; i < c.GetN(); ++i)
-    {
-        withConfiguration.push_back(true);
-    }
+    std::vector<bool> withConfiguration(c.GetN(), true);
     return Assign(c, withConfiguration);
 }
 
@@ -232,11 +228,7 @@
 Ipv6AddressHelper::Assign(const NetDeviceContainer& c, std::vector<bool> withConfiguration)
 {
     NS_LOG_FUNCTION(this);
-    std::vector<bool> onLink;
-    for (uint32_t i = 0; i < c.GetN(); ++i)
-    {
-        onLink.push_back(true);
-    }
+    std::vector<bool> onLink(c.GetN(), true);
     return Assign(c, withConfiguration, onLink);
 }
 
@@ -312,11 +304,7 @@
 Ipv6AddressHelper::AssignWithoutAddress(const NetDeviceContainer& c)
 {
     NS_LOG_FUNCTION(this);
-    std::vector<bool> withConfiguration;
-    for (uint32_t i = 0; i < c.GetN(); ++i)
-    {
-        withConfiguration.push_back(false);
-    }
+    std::vector<bool> withConfiguration(c.GetN(), false);
     return Assign(c, withConfiguration);
 }
 
@@ -324,13 +312,10 @@
 Ipv6AddressHelper::AssignWithoutOnLink(const NetDeviceContainer& c)
 {
     NS_LOG_FUNCTION(this);
-    std::vector<bool> withConfiguration;
-    std::vector<bool> onLink;
-    for (uint32_t i = 0; i < c.GetN(); ++i)
-    {
-        withConfiguration.push_back(true);
-        onLink.push_back(false);
-    }
+
+    std::vector<bool> withConfiguration(c.GetN(), true);
+    std::vector<bool> onLink(c.GetN(), false);
+
     return Assign(c, withConfiguration, onLink);
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv6-interface-container.cc ns-3.40/src/internet/helper/ipv6-interface-container.cc
--- ns-3.39/src/internet/helper/ipv6-interface-container.cc	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/ipv6-interface-container.cc	2023-09-27 13:30:37.650839000 -0700
@@ -81,8 +81,7 @@
 void
 Ipv6InterfaceContainer::Add(const Ipv6InterfaceContainer& c)
 {
-    for (InterfaceVector::const_iterator it = c.m_interfaces.begin(); it != c.m_interfaces.end();
-         it++)
+    for (auto it = c.m_interfaces.begin(); it != c.m_interfaces.end(); it++)
     {
         m_interfaces.push_back(*it);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv6-list-routing-helper.cc ns-3.40/src/internet/helper/ipv6-list-routing-helper.cc
--- ns-3.39/src/internet/helper/ipv6-list-routing-helper.cc	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/ipv6-list-routing-helper.cc	2023-09-27 13:30:37.654839000 -0700
@@ -31,9 +31,7 @@
 
 Ipv6ListRoutingHelper::~Ipv6ListRoutingHelper()
 {
-    for (std::list<std::pair<const Ipv6RoutingHelper*, int16_t>>::iterator i = m_list.begin();
-         i != m_list.end();
-         ++i)
+    for (auto i = m_list.begin(); i != m_list.end(); ++i)
     {
         delete i->first;
     }
@@ -41,8 +39,7 @@
 
 Ipv6ListRoutingHelper::Ipv6ListRoutingHelper(const Ipv6ListRoutingHelper& o)
 {
-    std::list<std::pair<const Ipv6RoutingHelper*, int16_t>>::const_iterator i;
-    for (i = o.m_list.begin(); i != o.m_list.end(); ++i)
+    for (auto i = o.m_list.begin(); i != o.m_list.end(); ++i)
     {
         m_list.emplace_back(const_cast<const Ipv6RoutingHelper*>(i->first->Copy()), i->second);
     }
@@ -64,9 +61,7 @@
 Ipv6ListRoutingHelper::Create(Ptr<Node> node) const
 {
     Ptr<Ipv6ListRouting> list = CreateObject<Ipv6ListRouting>();
-    for (std::list<std::pair<const Ipv6RoutingHelper*, int16_t>>::const_iterator i = m_list.begin();
-         i != m_list.end();
-         ++i)
+    for (auto i = m_list.begin(); i != m_list.end(); ++i)
     {
         Ptr<Ipv6RoutingProtocol> prot = i->first->Create(node);
         list->AddRoutingProtocol(prot, i->second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv6-list-routing-helper.h ns-3.40/src/internet/helper/ipv6-list-routing-helper.h
--- ns-3.39/src/internet/helper/ipv6-list-routing-helper.h	2023-07-05 14:23:47.837427400 -0700
+++ ns-3.40/src/internet/helper/ipv6-list-routing-helper.h	2023-09-27 13:30:37.654839000 -0700
@@ -19,7 +19,7 @@
 #ifndef IPV6_LIST_ROUTING_HELPER_H
 #define IPV6_LIST_ROUTING_HELPER_H
 
-#include "ns3/ipv6-routing-helper.h"
+#include "ipv6-routing-helper.h"
 
 #include <list>
 #include <stdint.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv6-static-routing-helper.cc ns-3.40/src/internet/helper/ipv6-static-routing-helper.cc
--- ns-3.39/src/internet/helper/ipv6-static-routing-helper.cc	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/helper/ipv6-static-routing-helper.cc	2023-09-27 13:30:37.654839000 -0700
@@ -97,7 +97,7 @@
     // We need to convert the NetDeviceContainer to an array of interface
     // numbers
     std::vector<uint32_t> outputInterfaces;
-    for (NetDeviceContainer::Iterator i = output.Begin(); i != output.End(); ++i)
+    for (auto i = output.Begin(); i != output.End(); ++i)
     {
         Ptr<NetDevice> nd = *i;
         int32_t interface = ipv6->GetInterfaceForDevice(nd);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ipv6-static-routing-helper.h ns-3.40/src/internet/helper/ipv6-static-routing-helper.h
--- ns-3.39/src/internet/helper/ipv6-static-routing-helper.h	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/helper/ipv6-static-routing-helper.h	2023-09-27 13:30:37.654839000 -0700
@@ -18,8 +18,9 @@
 #ifndef IPV6_STATIC_ROUTING_HELPER_H
 #define IPV6_STATIC_ROUTING_HELPER_H
 
+#include "ipv6-routing-helper.h"
+
 #include "ns3/ipv6-address.h"
-#include "ns3/ipv6-routing-helper.h"
 #include "ns3/ipv6-static-routing.h"
 #include "ns3/ipv6.h"
 #include "ns3/net-device-container.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/neighbor-cache-helper.h ns-3.40/src/internet/helper/neighbor-cache-helper.h
--- ns-3.39/src/internet/helper/neighbor-cache-helper.h	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/helper/neighbor-cache-helper.h	2023-09-27 13:30:37.654839000 -0700
@@ -20,16 +20,17 @@
 #ifndef NEIGHBOR_CACHE_HELPER_H
 #define NEIGHBOR_CACHE_HELPER_H
 
+#include "ipv4-interface-container.h"
+#include "ipv6-interface-container.h"
+
 #include "ns3/arp-cache.h"
 #include "ns3/arp-header.h"
 #include "ns3/arp-l3-protocol.h"
 #include "ns3/channel.h"
 #include "ns3/icmpv6-l4-protocol.h"
 #include "ns3/ipv4-address.h"
-#include "ns3/ipv4-interface-container.h"
 #include "ns3/ipv4-interface.h"
 #include "ns3/ipv4-l3-protocol.h"
-#include "ns3/ipv6-interface-container.h"
 #include "ns3/ipv6-interface.h"
 #include "ns3/ipv6-l3-protocol.h"
 #include "ns3/net-device-container.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/rip-helper.cc ns-3.40/src/internet/helper/rip-helper.cc
--- ns-3.39/src/internet/helper/rip-helper.cc	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/helper/rip-helper.cc	2023-09-27 13:30:37.654839000 -0700
@@ -56,20 +56,18 @@
 {
     Ptr<Rip> rip = m_factory.Create<Rip>();
 
-    std::map<Ptr<Node>, std::set<uint32_t>>::const_iterator it = m_interfaceExclusions.find(node);
+    auto it = m_interfaceExclusions.find(node);
 
     if (it != m_interfaceExclusions.end())
     {
         rip->SetInterfaceExclusions(it->second);
     }
 
-    std::map<Ptr<Node>, std::map<uint32_t, uint8_t>>::const_iterator iter =
-        m_interfaceMetrics.find(node);
+    auto iter = m_interfaceMetrics.find(node);
 
     if (iter != m_interfaceMetrics.end())
     {
-        std::map<uint32_t, uint8_t>::const_iterator subiter;
-        for (subiter = iter->second.begin(); subiter != iter->second.end(); subiter++)
+        for (auto subiter = iter->second.begin(); subiter != iter->second.end(); subiter++)
         {
             rip->SetInterfaceMetric(subiter->first, subiter->second);
         }
@@ -90,7 +88,7 @@
 {
     int64_t currentStream = stream;
     Ptr<Node> node;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         node = (*i);
         Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
@@ -160,7 +158,7 @@
 void
 RipHelper::ExcludeInterface(Ptr<Node> node, uint32_t interface)
 {
-    std::map<Ptr<Node>, std::set<uint32_t>>::iterator it = m_interfaceExclusions.find(node);
+    auto it = m_interfaceExclusions.find(node);
 
     if (it == m_interfaceExclusions.end())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/rip-helper.h ns-3.40/src/internet/helper/rip-helper.h
--- ns-3.39/src/internet/helper/rip-helper.h	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/helper/rip-helper.h	2023-09-27 13:30:37.654839000 -0700
@@ -20,7 +20,8 @@
 #ifndef RIP_HELPER_H
 #define RIP_HELPER_H
 
-#include "ns3/ipv4-routing-helper.h"
+#include "ipv4-routing-helper.h"
+
 #include "ns3/node-container.h"
 #include "ns3/node.h"
 #include "ns3/object-factory.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ripng-helper.cc ns-3.40/src/internet/helper/ripng-helper.cc
--- ns-3.39/src/internet/helper/ripng-helper.cc	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/helper/ripng-helper.cc	2023-09-27 13:30:37.654839000 -0700
@@ -58,20 +58,18 @@
 {
     Ptr<RipNg> ripng = m_factory.Create<RipNg>();
 
-    std::map<Ptr<Node>, std::set<uint32_t>>::const_iterator it = m_interfaceExclusions.find(node);
+    auto it = m_interfaceExclusions.find(node);
 
     if (it != m_interfaceExclusions.end())
     {
         ripng->SetInterfaceExclusions(it->second);
     }
 
-    std::map<Ptr<Node>, std::map<uint32_t, uint8_t>>::const_iterator iter =
-        m_interfaceMetrics.find(node);
+    auto iter = m_interfaceMetrics.find(node);
 
     if (iter != m_interfaceMetrics.end())
     {
-        std::map<uint32_t, uint8_t>::const_iterator subiter;
-        for (subiter = iter->second.begin(); subiter != iter->second.end(); subiter++)
+        for (auto subiter = iter->second.begin(); subiter != iter->second.end(); subiter++)
         {
             ripng->SetInterfaceMetric(subiter->first, subiter->second);
         }
@@ -92,7 +90,7 @@
 {
     int64_t currentStream = stream;
     Ptr<Node> node;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         node = (*i);
         Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
@@ -162,7 +160,7 @@
 void
 RipNgHelper::ExcludeInterface(Ptr<Node> node, uint32_t interface)
 {
-    std::map<Ptr<Node>, std::set<uint32_t>>::iterator it = m_interfaceExclusions.find(node);
+    auto it = m_interfaceExclusions.find(node);
 
     if (it == m_interfaceExclusions.end())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/helper/ripng-helper.h ns-3.40/src/internet/helper/ripng-helper.h
--- ns-3.39/src/internet/helper/ripng-helper.h	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/helper/ripng-helper.h	2023-09-27 13:30:37.654839000 -0700
@@ -20,7 +20,8 @@
 #ifndef RIPNG_HELPER_H
 #define RIPNG_HELPER_H
 
-#include "ns3/ipv6-routing-helper.h"
+#include "ipv6-routing-helper.h"
+
 #include "ns3/node-container.h"
 #include "ns3/node.h"
 #include "ns3/object-factory.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/arp-cache.cc ns-3.40/src/internet/model/arp-cache.cc
--- ns-3.39/src/internet/model/arp-cache.cc	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/model/arp-cache.cc	2023-09-27 13:30:37.654839000 -0700
@@ -199,7 +199,7 @@
     NS_LOG_FUNCTION(this);
     ArpCache::Entry* entry;
     bool restartWaitReplyTimer = false;
-    for (CacheI i = m_arpCache.begin(); i != m_arpCache.end(); i++)
+    for (auto i = m_arpCache.begin(); i != m_arpCache.end(); i++)
     {
         entry = (*i).second;
         if (entry != nullptr && entry->IsWaitReply())
@@ -245,7 +245,7 @@
 ArpCache::Flush()
 {
     NS_LOG_FUNCTION(this);
-    for (CacheI i = m_arpCache.begin(); i != m_arpCache.end(); i++)
+    for (auto i = m_arpCache.begin(); i != m_arpCache.end(); i++)
     {
         delete (*i).second;
     }
@@ -264,7 +264,7 @@
     NS_LOG_FUNCTION(this << stream);
     std::ostream* os = stream->GetStream();
 
-    for (CacheI i = m_arpCache.begin(); i != m_arpCache.end(); i++)
+    for (auto i = m_arpCache.begin(); i != m_arpCache.end(); i++)
     {
         *os << i->first << " dev ";
         std::string found = Names::FindName(m_device);
@@ -306,7 +306,7 @@
 ArpCache::RemoveAutoGeneratedEntries()
 {
     NS_LOG_FUNCTION(this);
-    for (CacheI i = m_arpCache.begin(); i != m_arpCache.end();)
+    for (auto i = m_arpCache.begin(); i != m_arpCache.end();)
     {
         if (i->second->IsAutoGenerated())
         {
@@ -325,7 +325,7 @@
     NS_LOG_FUNCTION(this << to);
 
     std::list<ArpCache::Entry*> entryList;
-    for (CacheI i = m_arpCache.begin(); i != m_arpCache.end(); i++)
+    for (auto i = m_arpCache.begin(); i != m_arpCache.end(); i++)
     {
         ArpCache::Entry* entry = (*i).second;
         if (entry->GetMacAddress() == to)
@@ -340,7 +340,7 @@
 ArpCache::Lookup(Ipv4Address to)
 {
     NS_LOG_FUNCTION(this << to);
-    CacheI it = m_arpCache.find(to);
+    auto it = m_arpCache.find(to);
     if (it != m_arpCache.end())
     {
         return it->second;
@@ -354,7 +354,7 @@
     NS_LOG_FUNCTION(this << to);
     NS_ASSERT(m_arpCache.find(to) == m_arpCache.end());
 
-    ArpCache::Entry* entry = new ArpCache::Entry(this);
+    auto entry = new ArpCache::Entry(this);
     m_arpCache[to] = entry;
     entry->SetIpv4Address(to);
     return entry;
@@ -365,7 +365,7 @@
 {
     NS_LOG_FUNCTION(this << entry);
 
-    for (CacheI i = m_arpCache.begin(); i != m_arpCache.end(); i++)
+    for (auto i = m_arpCache.begin(); i != m_arpCache.end(); i++)
     {
         if ((*i).second == entry)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/arp-l3-protocol.cc ns-3.40/src/internet/model/arp-l3-protocol.cc
--- ns-3.39/src/internet/model/arp-l3-protocol.cc	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/model/arp-l3-protocol.cc	2023-09-27 13:30:37.654839000 -0700
@@ -131,7 +131,7 @@
 ArpL3Protocol::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (CacheList::iterator i = m_cacheList.begin(); i != m_cacheList.end(); ++i)
+    for (auto i = m_cacheList.begin(); i != m_cacheList.end(); ++i)
     {
         Ptr<ArpCache> cache = *i;
         cache->Dispose();
@@ -160,7 +160,7 @@
 ArpL3Protocol::FindCache(Ptr<NetDevice> device)
 {
     NS_LOG_FUNCTION(this << device);
-    for (CacheList::const_iterator i = m_cacheList.begin(); i != m_cacheList.end(); i++)
+    for (auto i = m_cacheList.begin(); i != m_cacheList.end(); i++)
     {
         if ((*i)->GetDevice() == device)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/arp-l3-protocol.h ns-3.40/src/internet/model/arp-l3-protocol.h
--- ns-3.39/src/internet/model/arp-l3-protocol.h	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/model/arp-l3-protocol.h	2023-09-27 13:30:37.654839000 -0700
@@ -19,8 +19,9 @@
 #ifndef ARP_L3_PROTOCOL_H
 #define ARP_L3_PROTOCOL_H
 
+#include "ipv4-header.h"
+
 #include "ns3/address.h"
-#include "ns3/ipv4-header.h"
 #include "ns3/net-device.h"
 #include "ns3/ptr.h"
 #include "ns3/random-variable-stream.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/candidate-queue.cc ns-3.40/src/internet/model/candidate-queue.cc
--- ns-3.39/src/internet/model/candidate-queue.cc	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/model/candidate-queue.cc	2023-09-27 13:30:37.654839000 -0700
@@ -58,12 +58,10 @@
 std::ostream&
 operator<<(std::ostream& os, const CandidateQueue& q)
 {
-    typedef CandidateQueue::CandidateList_t List_t;
-    typedef List_t::const_iterator CIter_t;
     const CandidateQueue::CandidateList_t& list = q.m_candidates;
 
     os << "*** CandidateQueue Begin (<id, distance, LSA-type>) ***" << std::endl;
-    for (CIter_t iter = list.begin(); iter != list.end(); iter++)
+    for (auto iter = list.begin(); iter != list.end(); iter++)
     {
         os << "<" << (*iter)->GetVertexId() << ", " << (*iter)->GetDistanceFromRoot() << ", "
            << (*iter)->GetVertexType() << ">" << std::endl;
@@ -101,10 +99,10 @@
 {
     NS_LOG_FUNCTION(this << vNew);
 
-    CandidateList_t::iterator i = std::upper_bound(m_candidates.begin(),
-                                                   m_candidates.end(),
-                                                   vNew,
-                                                   &CandidateQueue::CompareSPFVertex);
+    auto i = std::upper_bound(m_candidates.begin(),
+                              m_candidates.end(),
+                              vNew,
+                              &CandidateQueue::CompareSPFVertex);
     m_candidates.insert(i, vNew);
 }
 
@@ -152,7 +150,7 @@
 CandidateQueue::Find(const Ipv4Address addr) const
 {
     NS_LOG_FUNCTION(this);
-    CandidateList_t::const_iterator i = m_candidates.begin();
+    auto i = m_candidates.begin();
 
     for (; i != m_candidates.end(); i++)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/global-route-manager-impl.cc ns-3.40/src/internet/model/global-route-manager-impl.cc
--- ns-3.39/src/internet/model/global-route-manager-impl.cc	2023-07-05 14:23:47.841427300 -0700
+++ ns-3.40/src/internet/model/global-route-manager-impl.cc	2023-09-27 13:30:37.654839000 -0700
@@ -62,9 +62,8 @@
 std::ostream&
 operator<<(std::ostream& os, const SPFVertex::ListOfSPFVertex_t& vs)
 {
-    typedef SPFVertex::ListOfSPFVertex_t::const_iterator CIter_t;
     os << "{";
-    for (CIter_t iter = vs.begin(); iter != vs.end();)
+    for (auto iter = vs.begin(); iter != vs.end();)
     {
         os << (*iter)->m_vertexId;
         if (++iter != vs.end())
@@ -133,7 +132,7 @@
 
     // find this node from all its parents and remove the entry of this node
     // from all its parents
-    for (ListOfSPFVertex_t::iterator piter = m_parents.begin(); piter != m_parents.end(); piter++)
+    for (auto piter = m_parents.begin(); piter != m_parents.end(); piter++)
     {
         // remove the current vertex from its parent's children list. Check
         // if the size of the list is reduced, or the child<->parent relation
@@ -255,7 +254,7 @@
         NS_LOG_LOGIC("Index to SPFVertex's parent is out-of-range.");
         return nullptr;
     }
-    ListOfSPFVertex_t::const_iterator iter = m_parents.begin();
+    auto iter = m_parents.begin();
     while (i-- > 0)
     {
         iter++;
@@ -302,11 +301,10 @@
 SPFVertex::GetRootExitDirection(uint32_t i) const
 {
     NS_LOG_FUNCTION(this << i);
-    typedef ListOfNodeExit_t::const_iterator CIter_t;
 
     NS_ASSERT_MSG(i < m_ecmpRootExits.size(),
                   "Index out-of-range when accessing SPFVertex::m_ecmpRootExits!");
-    CIter_t iter = m_ecmpRootExits.begin();
+    auto iter = m_ecmpRootExits.begin();
     while (i-- > 0)
     {
         iter++;
@@ -376,7 +374,7 @@
     NS_LOG_FUNCTION(this << n);
     uint32_t j = 0;
 
-    for (ListOfSPFVertex_t::const_iterator i = m_children.begin(); i != m_children.end(); i++, j++)
+    for (auto i = m_children.begin(); i != m_children.end(); i++, j++)
     {
         if (j == n)
         {
@@ -436,8 +434,7 @@
 GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB()
 {
     NS_LOG_FUNCTION(this);
-    LSDBMap_t::iterator i;
-    for (i = m_database.begin(); i != m_database.end(); i++)
+    for (auto i = m_database.begin(); i != m_database.end(); i++)
     {
         NS_LOG_LOGIC("free LSA");
         GlobalRoutingLSA* temp = i->second;
@@ -457,8 +454,7 @@
 GlobalRouteManagerLSDB::Initialize()
 {
     NS_LOG_FUNCTION(this);
-    LSDBMap_t::iterator i;
-    for (i = m_database.begin(); i != m_database.end(); i++)
+    for (auto i = m_database.begin(); i != m_database.end(); i++)
     {
         GlobalRoutingLSA* temp = i->second;
         temp->SetStatus(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
@@ -500,8 +496,7 @@
     //
     // Look up an LSA by its address.
     //
-    LSDBMap_t::const_iterator i;
-    for (i = m_database.begin(); i != m_database.end(); i++)
+    for (auto i = m_database.begin(); i != m_database.end(); i++)
     {
         if (i->first == addr)
         {
@@ -518,8 +513,7 @@
     //
     // Look up an LSA by its address.
     //
-    LSDBMap_t::const_iterator i;
-    for (i = m_database.begin(); i != m_database.end(); i++)
+    for (auto i = m_database.begin(); i != m_database.end(); i++)
     {
         GlobalRoutingLSA* temp = i->second;
         // Iterate among temp's Link Records
@@ -573,8 +567,7 @@
 GlobalRouteManagerImpl::DeleteGlobalRoutes()
 {
     NS_LOG_FUNCTION(this);
-    NodeList::Iterator listEnd = NodeList::End();
-    for (NodeList::Iterator i = NodeList::Begin(); i != listEnd; i++)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
     {
         Ptr<Node> node = *i;
         Ptr<GlobalRouter> router = node->GetObject<GlobalRouter>();
@@ -621,8 +614,7 @@
     // Walk the list of nodes looking for the GlobalRouter Interface.  Nodes with
     // global router interfaces are, not too surprisingly, our routers.
     //
-    NodeList::Iterator listEnd = NodeList::End();
-    for (NodeList::Iterator i = NodeList::Begin(); i != listEnd; i++)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
     {
         Ptr<Node> node = *i;
 
@@ -648,7 +640,7 @@
 
         for (uint32_t j = 0; j < numLSAs; ++j)
         {
-            GlobalRoutingLSA* lsa = new GlobalRoutingLSA();
+            auto lsa = new GlobalRoutingLSA();
             //
             // This is the call to actually fetch a Link State Advertisement from the
             // router.
@@ -704,8 +696,7 @@
     // Walk the list of nodes in the system.
     //
     NS_LOG_INFO("About to start SPF calculation");
-    NodeList::Iterator listEnd = NodeList::End();
-    for (NodeList::Iterator i = NodeList::Begin(); i != listEnd; i++)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
     {
         Ptr<Node> node = *i;
         //
@@ -1561,9 +1552,7 @@
     // ID corresponding to the root vertex.  This is the one we're going to write
     // the routing information to.
     //
-    NodeList::Iterator i = NodeList::Begin();
-    NodeList::Iterator listEnd = NodeList::End();
-    for (; i != listEnd; i++)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
     {
         Ptr<Node> node = *i;
         //
@@ -1727,9 +1716,7 @@
     // ID corresponding to the root vertex.  This is the one we're going to write
     // the routing information to.
     //
-    NodeList::Iterator i = NodeList::Begin();
-    NodeList::Iterator listEnd = NodeList::End();
-    for (; i != listEnd; i++)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
     {
         Ptr<Node> node = *i;
         //
@@ -1849,9 +1836,7 @@
     // the node at the root of the SPF tree.  This is the node for which we are
     // building the routing table.
     //
-    NodeList::Iterator i = NodeList::Begin();
-    NodeList::Iterator listEnd = NodeList::End();
-    for (; i != listEnd; i++)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
     {
         Ptr<Node> node = *i;
 
@@ -1938,9 +1923,7 @@
     // ID corresponding to the root vertex.  This is the one we're going to write
     // the routing information to.
     //
-    NodeList::Iterator i = NodeList::Begin();
-    NodeList::Iterator listEnd = NodeList::End();
-    for (; i != listEnd; i++)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
     {
         Ptr<Node> node = *i;
         //
@@ -2082,9 +2065,7 @@
     // ID corresponding to the root vertex.  This is the one we're going to write
     // the routing information to.
     //
-    NodeList::Iterator i = NodeList::Begin();
-    NodeList::Iterator listEnd = NodeList::End();
-    for (; i != listEnd; i++)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
     {
         Ptr<Node> node = *i;
         //
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/global-router-interface.cc ns-3.40/src/internet/model/global-router-interface.cc
--- ns-3.39/src/internet/model/global-router-interface.cc	2023-07-05 14:23:47.845427500 -0700
+++ ns-3.40/src/internet/model/global-router-interface.cc	2023-09-27 13:30:37.654839000 -0700
@@ -193,12 +193,10 @@
 GlobalRoutingLSA::CopyLinkRecords(const GlobalRoutingLSA& lsa)
 {
     NS_LOG_FUNCTION(this << &lsa);
-    for (ListOfLinkRecords_t::const_iterator i = lsa.m_linkRecords.begin();
-         i != lsa.m_linkRecords.end();
-         i++)
+    for (auto i = lsa.m_linkRecords.begin(); i != lsa.m_linkRecords.end(); i++)
     {
         GlobalRoutingLinkRecord* pSrc = *i;
-        GlobalRoutingLinkRecord* pDst = new GlobalRoutingLinkRecord;
+        auto pDst = new GlobalRoutingLinkRecord;
 
         pDst->SetLinkType(pSrc->GetLinkType());
         pDst->SetLinkId(pSrc->GetLinkId());
@@ -222,7 +220,7 @@
 GlobalRoutingLSA::ClearLinkRecords()
 {
     NS_LOG_FUNCTION(this);
-    for (ListOfLinkRecords_t::iterator i = m_linkRecords.begin(); i != m_linkRecords.end(); i++)
+    for (auto i = m_linkRecords.begin(); i != m_linkRecords.end(); i++)
     {
         NS_LOG_LOGIC("Free link record");
 
@@ -256,8 +254,7 @@
 {
     NS_LOG_FUNCTION(this << n);
     uint32_t j = 0;
-    for (ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin(); i != m_linkRecords.end();
-         i++, j++)
+    for (auto i = m_linkRecords.begin(); i != m_linkRecords.end(); i++, j++)
     {
         if (j == n)
         {
@@ -358,9 +355,7 @@
 {
     NS_LOG_FUNCTION(this << n);
     uint32_t j = 0;
-    for (ListOfAttachedRouters_t::const_iterator i = m_attachedRouters.begin();
-         i != m_attachedRouters.end();
-         i++, j++)
+    for (auto i = m_attachedRouters.begin(); i != m_attachedRouters.end(); i++, j++)
     {
         if (j == n)
         {
@@ -422,9 +417,7 @@
 
     if (m_lsType == GlobalRoutingLSA::RouterLSA)
     {
-        for (ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin();
-             i != m_linkRecords.end();
-             i++)
+        for (auto i = m_linkRecords.begin(); i != m_linkRecords.end(); i++)
         {
             GlobalRoutingLinkRecord* p = *i;
 
@@ -469,9 +462,7 @@
     {
         os << "---------- NetworkLSA Link Record ----------" << std::endl;
         os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask << std::endl;
-        for (ListOfAttachedRouters_t::const_iterator i = m_attachedRouters.begin();
-             i != m_attachedRouters.end();
-             i++)
+        for (auto i = m_attachedRouters.begin(); i != m_attachedRouters.end(); i++)
         {
             Ipv4Address p = *i;
             os << "attachedRouter = " << p << std::endl;
@@ -545,7 +536,7 @@
 {
     NS_LOG_FUNCTION(this);
     m_routingProtocol = nullptr;
-    for (InjectedRoutesI k = m_injectedRoutes.begin(); k != m_injectedRoutes.end();
+    for (auto k = m_injectedRoutes.begin(); k != m_injectedRoutes.end();
          k = m_injectedRoutes.erase(k))
     {
         delete (*k);
@@ -557,7 +548,7 @@
 GlobalRouter::ClearLSAs()
 {
     NS_LOG_FUNCTION(this);
-    for (ListOfLSAs_t::iterator i = m_LSAs.begin(); i != m_LSAs.end(); i++)
+    for (auto i = m_LSAs.begin(); i != m_LSAs.end(); i++)
     {
         NS_LOG_LOGIC("Free LSA");
 
@@ -614,7 +605,7 @@
     //
     // Every router node originates a Router-LSA
     //
-    GlobalRoutingLSA* pLSA = new GlobalRoutingLSA;
+    auto pLSA = new GlobalRoutingLSA;
     pLSA->SetLSType(GlobalRoutingLSA::RouterLSA);
     pLSA->SetLinkStateId(m_routerId);
     pLSA->SetAdvertisingRouter(m_routerId);
@@ -717,9 +708,9 @@
     // Build injected route LSAs as external routes
     // RFC 2328, section 12.4.4
     //
-    for (InjectedRoutesCI i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
+    for (auto i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
     {
-        GlobalRoutingLSA* pLSA = new GlobalRoutingLSA;
+        auto pLSA = new GlobalRoutingLSA;
         pLSA->SetLSType(GlobalRoutingLSA::ASExternalLSAs);
         pLSA->SetLinkStateId((*i)->GetDestNetwork());
         pLSA->SetAdvertisingRouter(m_routerId);
@@ -752,7 +743,7 @@
 {
     NS_LOG_FUNCTION(this << nd << pLSA << &c);
 
-    GlobalRoutingLinkRecord* plr = new GlobalRoutingLinkRecord;
+    auto plr = new GlobalRoutingLinkRecord;
     NS_ABORT_MSG_IF(plr == nullptr,
                     "GlobalRouter::ProcessSingleBroadcastLink(): Can't alloc link record");
 
@@ -1193,7 +1184,7 @@
         Ipv4Address addrLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetLocal();
         Ipv4Mask maskLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetMask();
 
-        GlobalRoutingLSA* pLSA = new GlobalRoutingLSA;
+        auto pLSA = new GlobalRoutingLSA;
         NS_ABORT_MSG_IF(pLSA == nullptr,
                         "GlobalRouter::BuildNetworkLSAs(): Can't alloc link record");
 
@@ -1604,7 +1595,7 @@
     // walk the list of link state advertisements created there and return the
     // one the client is interested in.
     //
-    ListOfLSAs_t::const_iterator i = m_LSAs.begin();
+    auto i = m_LSAs.begin();
     uint32_t j = 0;
 
     for (; i != m_LSAs.end(); i++, j++)
@@ -1624,7 +1615,7 @@
 GlobalRouter::InjectRoute(Ipv4Address network, Ipv4Mask networkMask)
 {
     NS_LOG_FUNCTION(this << network << networkMask);
-    Ipv4RoutingTableEntry* route = new Ipv4RoutingTableEntry();
+    auto route = new Ipv4RoutingTableEntry();
     //
     // Interface number does not matter here, using 1.
     //
@@ -1639,7 +1630,7 @@
     if (index < m_injectedRoutes.size())
     {
         uint32_t tmp = 0;
-        for (InjectedRoutesCI i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
+        for (auto i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
         {
             if (tmp == index)
             {
@@ -1666,7 +1657,7 @@
     NS_LOG_FUNCTION(this << index);
     NS_ASSERT(index < m_injectedRoutes.size());
     uint32_t tmp = 0;
-    for (InjectedRoutesI i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
+    for (auto i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
     {
         if (tmp == index)
         {
@@ -1683,7 +1674,7 @@
 GlobalRouter::WithdrawRoute(Ipv4Address network, Ipv4Mask networkMask)
 {
     NS_LOG_FUNCTION(this << network << networkMask);
-    for (InjectedRoutesI i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
+    for (auto i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
     {
         if ((*i)->GetDestNetwork() == network && (*i)->GetDestNetworkMask() == networkMask)
         {
@@ -1791,8 +1782,7 @@
 bool
 GlobalRouter::BridgeHasAlreadyBeenVisited(Ptr<BridgeNetDevice> bridgeNetDevice) const
 {
-    std::vector<Ptr<BridgeNetDevice>>::iterator iter;
-    for (iter = m_bridgesVisited.begin(); iter != m_bridgesVisited.end(); ++iter)
+    for (auto iter = m_bridgesVisited.begin(); iter != m_bridgesVisited.end(); ++iter)
     {
         if (bridgeNetDevice == *iter)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/global-router-interface.h ns-3.40/src/internet/model/global-router-interface.h
--- ns-3.39/src/internet/model/global-router-interface.h	2023-07-05 14:23:47.845427500 -0700
+++ ns-3.40/src/internet/model/global-router-interface.h	2023-09-27 13:30:37.654839000 -0700
@@ -21,11 +21,12 @@
 #ifndef GLOBAL_ROUTER_INTERFACE_H
 #define GLOBAL_ROUTER_INTERFACE_H
 
+#include "global-route-manager.h"
+#include "ipv4-routing-table-entry.h"
+
 #include "ns3/bridge-net-device.h"
 #include "ns3/channel.h"
-#include "ns3/global-route-manager.h"
 #include "ns3/ipv4-address.h"
-#include "ns3/ipv4-routing-table-entry.h"
 #include "ns3/net-device-container.h"
 #include "ns3/node.h"
 #include "ns3/object.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/icmpv4.h ns-3.40/src/internet/model/icmpv4.h
--- ns-3.39/src/internet/model/icmpv4.h	2023-07-05 14:23:47.845427500 -0700
+++ ns-3.40/src/internet/model/icmpv4.h	2023-09-27 13:30:37.654839000 -0700
@@ -20,8 +20,9 @@
 #ifndef ICMPV4_H
 #define ICMPV4_H
 
+#include "ipv4-header.h"
+
 #include "ns3/header.h"
-#include "ns3/ipv4-header.h"
 #include "ns3/ptr.h"
 
 #include <stdint.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/icmpv6-header.cc ns-3.40/src/internet/model/icmpv6-header.cc
--- ns-3.39/src/internet/model/icmpv6-header.cc	2023-07-05 14:23:47.845427500 -0700
+++ ns-3.40/src/internet/model/icmpv6-header.cc	2023-09-27 13:30:37.654839000 -0700
@@ -346,9 +346,9 @@
     SetType(ICMPV6_ND_NEIGHBOR_ADVERTISEMENT);
     SetCode(0);
     SetReserved(0);
-    SetFlagR(0);
-    SetFlagS(0);
-    SetFlagO(0);
+    SetFlagR(false);
+    SetFlagS(false);
+    SetFlagO(false);
     m_checksum = 0;
 }
 
@@ -545,9 +545,9 @@
     NS_LOG_FUNCTION(this);
     SetType(ICMPV6_ND_ROUTER_ADVERTISEMENT);
     SetCode(0);
-    SetFlagM(0);
-    SetFlagO(0);
-    SetFlagH(0);
+    SetFlagM(false);
+    SetFlagO(false);
+    SetFlagH(false);
     SetCurHopLimit(0);
     SetLifeTime(0);
     SetRetransmissionTime(0);
@@ -1192,7 +1192,7 @@
     iter.WriteU32(0);
 
     uint32_t size = m_packet->GetSize();
-    uint8_t* buf = new uint8_t[size];
+    auto buf = new uint8_t[size];
     m_packet->CopyData(buf, size);
     iter.Write(buf, size);
     delete[] buf;
@@ -1308,7 +1308,7 @@
     iter.WriteHtonU32(GetMtu());
 
     uint32_t size = m_packet->GetSize();
-    uint8_t* buf = new uint8_t[size];
+    auto buf = new uint8_t[size];
     m_packet->CopyData(buf, size);
     iter.Write(buf, size);
     delete[] buf;
@@ -1410,7 +1410,7 @@
     iter.WriteU32(0);
 
     uint32_t size = m_packet->GetSize();
-    uint8_t* buf = new uint8_t[size];
+    auto buf = new uint8_t[size];
     m_packet->CopyData(buf, size);
     iter.Write(buf, size);
     delete[] buf;
@@ -1527,7 +1527,7 @@
     iter.WriteHtonU32(GetPtr());
 
     uint32_t size = m_packet->GetSize();
-    uint8_t* buf = new uint8_t[size];
+    auto buf = new uint8_t[size];
     m_packet->CopyData(buf, size);
     iter.Write(buf, size);
     delete[] buf;
@@ -2128,7 +2128,7 @@
     i.WriteU32(0);
 
     uint32_t size = m_packet->GetSize();
-    uint8_t* buf = new uint8_t[size];
+    auto buf = new uint8_t[size];
     m_packet->CopyData(buf, size);
     i.Write(buf, size);
     delete[] buf;
@@ -2147,7 +2147,7 @@
     i.ReadU32();
 
     uint32_t len2 = (GetLength() - 1) * 8;
-    uint8_t* buff = new uint8_t[len2];
+    auto buff = new uint8_t[len2];
     i.Read(buff, len2);
     m_packet = Create<Packet>(buff, len2);
     delete[] buff;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/icmpv6-l4-protocol.cc ns-3.40/src/internet/model/icmpv6-l4-protocol.cc
--- ns-3.39/src/internet/model/icmpv6-l4-protocol.cc	2023-07-05 14:23:47.845427500 -0700
+++ ns-3.40/src/internet/model/icmpv6-l4-protocol.cc	2023-09-27 13:30:37.654839000 -0700
@@ -168,7 +168,7 @@
 Icmpv6L4Protocol::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (CacheList::const_iterator it = m_cacheList.begin(); it != m_cacheList.end(); it++)
+    for (auto it = m_cacheList.begin(); it != m_cacheList.end(); it++)
     {
         Ptr<NdiscCache> cache = *it;
         cache->Dispose();
@@ -397,7 +397,7 @@
 {
     NS_LOG_FUNCTION(this << packet << src << dst << interface);
     Icmpv6Echo request;
-    uint8_t* buf = new uint8_t[packet->GetSize()];
+    auto buf = new uint8_t[packet->GetSize()];
 
     packet->RemoveHeader(request);
     /* XXX IPv6 extension: obtain a fresh copy of data otherwise it crash... */
@@ -522,9 +522,7 @@
             waiting = entry->MarkReachable(lla.GetAddress());
             entry->StartReachableTimer();
             // send out waiting packet
-            for (std::list<NdiscCache::Ipv6PayloadHeaderPair>::const_iterator it = waiting.begin();
-                 it != waiting.end();
-                 it++)
+            for (auto it = waiting.begin(); it != waiting.end(); it++)
             {
                 cache->GetInterface()->Send(it->first, it->second, src);
             }
@@ -558,10 +556,7 @@
             {
                 entry->StopNudTimer();
                 waiting = entry->MarkReachable(lla.GetAddress());
-                for (std::list<NdiscCache::Ipv6PayloadHeaderPair>::const_iterator it =
-                         waiting.begin();
-                     it != waiting.end();
-                     it++)
+                for (auto it = waiting.begin(); it != waiting.end(); it++)
                 {
                     cache->GetInterface()->Send(it->first, it->second, src);
                 }
@@ -605,7 +600,7 @@
     Icmpv6RS rsHeader;
     packet->RemoveHeader(rsHeader);
     Address hardwareAddress;
-    Icmpv6OptionLinkLayerAddress lla(1);
+    Icmpv6OptionLinkLayerAddress lla(true);
     NdiscCache::Entry* entry = nullptr;
     Ptr<NdiscCache> cache = FindCache(interface->GetDevice());
 
@@ -786,7 +781,7 @@
     if (!src.IsAny())
     {
         Icmpv6OptionLinkLayerAddress llOption(
-            1,
+            true,
             hardwareAddress); /* we give our mac address in response */
         p->AddHeader(llOption);
     }
@@ -813,7 +808,7 @@
     NS_LOG_FUNCTION(this << src << dst << id << seq << data);
     Ptr<Packet> p = data->Copy();
     Ipv6Header ipHeader;
-    Icmpv6Echo req(1);
+    Icmpv6Echo req(true);
 
     req.SetId(id);
     req.SetSeq(seq);
@@ -841,7 +836,7 @@
 {
     NS_LOG_FUNCTION(this << packet << src << dst << interface);
     Icmpv6NA naHeader;
-    Icmpv6OptionLinkLayerAddress lla(1);
+    Icmpv6OptionLinkLayerAddress lla(true);
 
     packet->RemoveHeader(naHeader);
     Ipv6Address target = naHeader.GetIpv6Target();
@@ -911,9 +906,7 @@
             waiting = entry->MarkReachable(lla.GetAddress());
             entry->StartReachableTimer();
             /* send out waiting packet */
-            for (std::list<NdiscCache::Ipv6PayloadHeaderPair>::const_iterator it = waiting.begin();
-                 it != waiting.end();
-                 it++)
+            for (auto it = waiting.begin(); it != waiting.end(); it++)
             {
                 cache->GetInterface()->Send(it->first, it->second, src);
             }
@@ -978,10 +971,7 @@
             if (naHeader.GetFlagS())
             {
                 waiting = entry->MarkReachable(lla.GetAddress());
-                for (std::list<NdiscCache::Ipv6PayloadHeaderPair>::const_iterator it =
-                         waiting.begin();
-                     it != waiting.end();
-                     it++)
+                for (auto it = waiting.begin(); it != waiting.end(); it++)
                 {
                     cache->GetInterface()->Send(it->first, it->second, src);
                 }
@@ -1022,7 +1012,7 @@
     NS_LOG_FUNCTION(this << packet << src << dst << interface);
     bool hasLla = false;
     Ptr<Packet> p = packet->Copy();
-    Icmpv6OptionLinkLayerAddress llOptionHeader(0);
+    Icmpv6OptionLinkLayerAddress llOptionHeader(false);
 
     Icmpv6Redirection redirectionHeader;
     p->RemoveHeader(redirectionHeader);
@@ -1255,7 +1245,7 @@
     NS_LOG_FUNCTION(this << src << dst << hardwareAddress << static_cast<uint32_t>(flags));
     Ptr<Packet> p = Create<Packet>();
     Icmpv6NA na;
-    Icmpv6OptionLinkLayerAddress llOption(0, *hardwareAddress); /* not a source link layer */
+    Icmpv6OptionLinkLayerAddress llOption(false, *hardwareAddress); /* not a source link layer */
 
     NS_LOG_LOGIC("Send NA ( from " << src << " to " << dst << " target " << src << ")");
     na.SetIpv6Target(src);
@@ -1289,7 +1279,7 @@
 {
     NS_LOG_FUNCTION(this << src << dst << id << seq << data);
     Ptr<Packet> p = data->Copy();
-    Icmpv6Echo reply(0); /* echo reply */
+    Icmpv6Echo reply(false); /* echo reply */
 
     reply.SetId(id);
     reply.SetSeq(seq);
@@ -1313,7 +1303,7 @@
     /* Ipv6Header ipHeader; */
     Icmpv6NS ns(target);
     Icmpv6OptionLinkLayerAddress llOption(
-        1,
+        true,
         hardwareAddress); /* we give our mac address in response */
 
     /* if the source is unspec, multicast the NA to all-nodes multicast */
@@ -1356,10 +1346,21 @@
     // unspecified address. Otherwise, it SHOULD be included on link layers that have addresses.
     if (!src.IsAny())
     {
-        Icmpv6OptionLinkLayerAddress llOption(1, hardwareAddress);
+        Icmpv6OptionLinkLayerAddress llOption(true, hardwareAddress);
         p->AddHeader(llOption);
     }
 
+    if (!src.IsAny())
+    {
+        Ptr<Ipv6L3Protocol> ipv6 = m_node->GetObject<Ipv6L3Protocol>();
+        if (ipv6->GetInterfaceForAddress(src) == -1)
+        {
+            NS_LOG_INFO("Preventing RS from being sent or rescheduled because the source address "
+                        << src << " has been removed");
+            return;
+        }
+    }
+
     NS_LOG_LOGIC("Send RS (from " << src << " to " << dst << ")");
 
     rs.CalculatePseudoHeaderChecksum(src, dst, p->GetSize() + rs.GetSerializedSize(), PROT_NUMBER);
@@ -1548,7 +1549,7 @@
     uint32_t llaSize = 0;
     Ptr<Packet> p = Create<Packet>();
     uint32_t redirectedPacketSize = redirectedPacket->GetSize();
-    Icmpv6OptionLinkLayerAddress llOption(0);
+    Icmpv6OptionLinkLayerAddress llOption(false);
 
     NS_LOG_LOGIC("Send Redirection ( to " << dst << " target " << redirTarget << " destination "
                                           << redirDestination << " )");
@@ -1606,7 +1607,7 @@
     Ipv6Header ipHeader;
     Icmpv6NA na;
     Icmpv6OptionLinkLayerAddress llOption(
-        0,
+        false,
         *hardwareAddress); /* we give our mac address in response */
 
     NS_LOG_LOGIC("Send NA ( from " << src << " to " << dst << ")");
@@ -1653,7 +1654,7 @@
     Ipv6Header ipHeader;
     Icmpv6NS ns(target);
     Icmpv6OptionLinkLayerAddress llOption(
-        1,
+        true,
         hardwareAddress); /* we give our mac address in response */
 
     NS_LOG_LOGIC("Send NS ( from " << src << " to " << dst << " target " << target << ")");
@@ -1676,7 +1677,7 @@
 {
     NS_LOG_FUNCTION(this << device);
 
-    for (CacheList::const_iterator i = m_cacheList.begin(); i != m_cacheList.end(); i++)
+    for (auto i = m_cacheList.begin(); i != m_cacheList.end(); i++)
     {
         if ((*i)->GetDevice() == device)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-address-generator.cc ns-3.40/src/internet/model/ipv4-address-generator.cc
--- ns-3.39/src/internet/model/ipv4-address-generator.cc	2023-07-05 14:23:47.845427500 -0700
+++ ns-3.40/src/internet/model/ipv4-address-generator.cc	2023-09-27 13:30:37.654839000 -0700
@@ -342,8 +342,8 @@
     NS_ABORT_MSG_UNLESS(m_netTable[index].addr <= m_netTable[index].addrMax,
                         "Ipv4AddressGeneratorImpl::NextAddress(): Address overflow");
 
-    Ipv4Address addr = Ipv4Address((m_netTable[index].network << m_netTable[index].shift) |
-                                   m_netTable[index].addr);
+    Ipv4Address addr((m_netTable[index].network << m_netTable[index].shift) |
+                     m_netTable[index].addr);
 
     ++m_netTable[index].addr;
     //
@@ -404,7 +404,7 @@
         //
         if (addr == (*i).addrHigh + 1)
         {
-            std::list<Entry>::iterator j = i;
+            auto j = i;
             ++j;
 
             if (j != m_entries.end())
@@ -459,9 +459,7 @@
         addr,
         "Ipv4AddressGeneratorImpl::IsAddressAllocated(): Don't check for the broadcast address...");
 
-    std::list<Entry>::iterator i;
-
-    for (i = m_entries.begin(); i != m_entries.end(); ++i)
+    for (auto i = m_entries.begin(); i != m_entries.end(); ++i)
     {
         NS_LOG_LOGIC("examine entry: " << Ipv4Address((*i).addrLow) << " to "
                                        << Ipv4Address((*i).addrHigh));
@@ -469,10 +467,10 @@
         {
             NS_LOG_LOGIC("Ipv4AddressGeneratorImpl::IsAddressAllocated(): Address Collision: "
                          << Ipv4Address(addr));
-            return false;
+            return true;
         }
     }
-    return true;
+    return false;
 }
 
 bool
@@ -485,14 +483,12 @@
         "Ipv4AddressGeneratorImpl::IsNetworkAllocated(): network address and mask don't match "
             << address << " " << mask);
 
-    std::list<Entry>::iterator i;
-
-    for (i = m_entries.begin(); i != m_entries.end(); ++i)
+    for (auto i = m_entries.begin(); i != m_entries.end(); ++i)
     {
         NS_LOG_LOGIC("examine entry: " << Ipv4Address((*i).addrLow) << " to "
                                        << Ipv4Address((*i).addrHigh));
-        Ipv4Address low = Ipv4Address((*i).addrLow);
-        Ipv4Address high = Ipv4Address((*i).addrHigh);
+        Ipv4Address low((*i).addrLow);
+        Ipv4Address high((*i).addrHigh);
 
         if (address == low.CombineMask(mask) || address == high.CombineMask(mask))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-end-point-demux.cc ns-3.40/src/internet/model/ipv4-end-point-demux.cc
--- ns-3.39/src/internet/model/ipv4-end-point-demux.cc	2023-07-05 14:23:47.845427500 -0700
+++ ns-3.40/src/internet/model/ipv4-end-point-demux.cc	2023-09-27 13:30:37.654839000 -0700
@@ -40,7 +40,7 @@
 Ipv4EndPointDemux::~Ipv4EndPointDemux()
 {
     NS_LOG_FUNCTION(this);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         Ipv4EndPoint* endPoint = *i;
         delete endPoint;
@@ -52,7 +52,7 @@
 Ipv4EndPointDemux::LookupPortLocal(uint16_t port)
 {
     NS_LOG_FUNCTION(this << port);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         if ((*i)->GetLocalPort() == port)
         {
@@ -66,7 +66,7 @@
 Ipv4EndPointDemux::LookupLocal(Ptr<NetDevice> boundNetDevice, Ipv4Address addr, uint16_t port)
 {
     NS_LOG_FUNCTION(this << addr << port);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         if ((*i)->GetLocalPort() == port && (*i)->GetLocalAddress() == addr &&
             (*i)->GetBoundNetDevice() == boundNetDevice)
@@ -87,7 +87,7 @@
         NS_LOG_WARN("Ephemeral port allocation failed.");
         return nullptr;
     }
-    Ipv4EndPoint* endPoint = new Ipv4EndPoint(Ipv4Address::GetAny(), port);
+    auto endPoint = new Ipv4EndPoint(Ipv4Address::GetAny(), port);
     m_endPoints.push_back(endPoint);
     NS_LOG_DEBUG("Now have >>" << m_endPoints.size() << "<< endpoints.");
     return endPoint;
@@ -103,7 +103,7 @@
         NS_LOG_WARN("Ephemeral port allocation failed.");
         return nullptr;
     }
-    Ipv4EndPoint* endPoint = new Ipv4EndPoint(address, port);
+    auto endPoint = new Ipv4EndPoint(address, port);
     m_endPoints.push_back(endPoint);
     NS_LOG_DEBUG("Now have >>" << m_endPoints.size() << "<< endpoints.");
     return endPoint;
@@ -126,7 +126,7 @@
         NS_LOG_WARN("Duplicated endpoint.");
         return nullptr;
     }
-    Ipv4EndPoint* endPoint = new Ipv4EndPoint(address, port);
+    auto endPoint = new Ipv4EndPoint(address, port);
     m_endPoints.push_back(endPoint);
     NS_LOG_DEBUG("Now have >>" << m_endPoints.size() << "<< endpoints.");
     return endPoint;
@@ -140,7 +140,7 @@
                             uint16_t peerPort)
 {
     NS_LOG_FUNCTION(this << localAddress << localPort << peerAddress << peerPort << boundNetDevice);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         if ((*i)->GetLocalPort() == localPort && (*i)->GetLocalAddress() == localAddress &&
             (*i)->GetPeerPort() == peerPort && (*i)->GetPeerAddress() == peerAddress &&
@@ -150,7 +150,7 @@
             return nullptr;
         }
     }
-    Ipv4EndPoint* endPoint = new Ipv4EndPoint(localAddress, localPort);
+    auto endPoint = new Ipv4EndPoint(localAddress, localPort);
     endPoint->SetPeer(peerAddress, peerPort);
     m_endPoints.push_back(endPoint);
 
@@ -163,7 +163,7 @@
 Ipv4EndPointDemux::DeAllocate(Ipv4EndPoint* endPoint)
 {
     NS_LOG_FUNCTION(this << endPoint);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         if (*i == endPoint)
         {
@@ -183,7 +183,7 @@
     NS_LOG_FUNCTION(this);
     EndPoints ret;
 
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         Ipv4EndPoint* endP = *i;
         ret.push_back(endP);
@@ -211,7 +211,7 @@
     EndPoints retval4; // Exact match on all 4
 
     NS_LOG_DEBUG("Looking up endpoint for destination address " << daddr << ":" << dport);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         Ipv4EndPoint* endP = *i;
 
@@ -376,7 +376,7 @@
     // function.
     uint32_t genericity = 3;
     Ipv4EndPoint* generic = nullptr;
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         if ((*i)->GetLocalPort() != dport)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-end-point.h ns-3.40/src/internet/model/ipv4-end-point.h
--- ns-3.39/src/internet/model/ipv4-end-point.h	2023-07-05 14:23:47.845427500 -0700
+++ ns-3.40/src/internet/model/ipv4-end-point.h	2023-09-27 13:30:37.654839000 -0700
@@ -20,10 +20,11 @@
 #ifndef IPV4_END_POINT_H
 #define IPV4_END_POINT_H
 
+#include "ipv4-header.h"
+#include "ipv4-interface.h"
+
 #include "ns3/callback.h"
 #include "ns3/ipv4-address.h"
-#include "ns3/ipv4-header.h"
-#include "ns3/ipv4-interface.h"
 #include "ns3/net-device.h"
 
 #include <stdint.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-global-routing.cc ns-3.40/src/internet/model/ipv4-global-routing.cc
--- ns-3.39/src/internet/model/ipv4-global-routing.cc	2023-07-05 14:23:47.845427500 -0700
+++ ns-3.40/src/internet/model/ipv4-global-routing.cc	2023-09-27 13:30:37.654839000 -0700
@@ -80,7 +80,7 @@
 Ipv4GlobalRouting::AddHostRouteTo(Ipv4Address dest, Ipv4Address nextHop, uint32_t interface)
 {
     NS_LOG_FUNCTION(this << dest << nextHop << interface);
-    Ipv4RoutingTableEntry* route = new Ipv4RoutingTableEntry();
+    auto route = new Ipv4RoutingTableEntry();
     *route = Ipv4RoutingTableEntry::CreateHostRouteTo(dest, nextHop, interface);
     m_hostRoutes.push_back(route);
 }
@@ -89,7 +89,7 @@
 Ipv4GlobalRouting::AddHostRouteTo(Ipv4Address dest, uint32_t interface)
 {
     NS_LOG_FUNCTION(this << dest << interface);
-    Ipv4RoutingTableEntry* route = new Ipv4RoutingTableEntry();
+    auto route = new Ipv4RoutingTableEntry();
     *route = Ipv4RoutingTableEntry::CreateHostRouteTo(dest, interface);
     m_hostRoutes.push_back(route);
 }
@@ -101,7 +101,7 @@
                                      uint32_t interface)
 {
     NS_LOG_FUNCTION(this << network << networkMask << nextHop << interface);
-    Ipv4RoutingTableEntry* route = new Ipv4RoutingTableEntry();
+    auto route = new Ipv4RoutingTableEntry();
     *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, nextHop, interface);
     m_networkRoutes.push_back(route);
 }
@@ -110,7 +110,7 @@
 Ipv4GlobalRouting::AddNetworkRouteTo(Ipv4Address network, Ipv4Mask networkMask, uint32_t interface)
 {
     NS_LOG_FUNCTION(this << network << networkMask << interface);
-    Ipv4RoutingTableEntry* route = new Ipv4RoutingTableEntry();
+    auto route = new Ipv4RoutingTableEntry();
     *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, interface);
     m_networkRoutes.push_back(route);
 }
@@ -122,7 +122,7 @@
                                         uint32_t interface)
 {
     NS_LOG_FUNCTION(this << network << networkMask << nextHop << interface);
-    Ipv4RoutingTableEntry* route = new Ipv4RoutingTableEntry();
+    auto route = new Ipv4RoutingTableEntry();
     *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, nextHop, interface);
     m_ASexternalRoutes.push_back(route);
 }
@@ -138,7 +138,7 @@
     RouteVec_t allRoutes;
 
     NS_LOG_LOGIC("Number of m_hostRoutes = " << m_hostRoutes.size());
-    for (HostRoutesCI i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i++)
+    for (auto i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i++)
     {
         NS_ASSERT((*i)->IsHost());
         if ((*i)->GetDest() == dest)
@@ -158,7 +158,7 @@
     if (allRoutes.empty()) // if no host route is found
     {
         NS_LOG_LOGIC("Number of m_networkRoutes" << m_networkRoutes.size());
-        for (NetworkRoutesI j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
+        for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
         {
             Ipv4Mask mask = (*j)->GetDestNetworkMask();
             Ipv4Address entry = (*j)->GetDestNetwork();
@@ -179,7 +179,7 @@
     }
     if (allRoutes.empty()) // consider external if no host/network found
     {
-        for (ASExternalRoutesI k = m_ASexternalRoutes.begin(); k != m_ASexternalRoutes.end(); k++)
+        for (auto k = m_ASexternalRoutes.begin(); k != m_ASexternalRoutes.end(); k++)
         {
             Ipv4Mask mask = (*k)->GetDestNetworkMask();
             Ipv4Address entry = (*k)->GetDestNetwork();
@@ -248,7 +248,7 @@
     if (index < m_hostRoutes.size())
     {
         uint32_t tmp = 0;
-        for (HostRoutesCI i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i++)
+        for (auto i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i++)
         {
             if (tmp == index)
             {
@@ -261,7 +261,7 @@
     uint32_t tmp = 0;
     if (index < m_networkRoutes.size())
     {
-        for (NetworkRoutesCI j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
+        for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
         {
             if (tmp == index)
             {
@@ -272,7 +272,7 @@
     }
     index -= m_networkRoutes.size();
     tmp = 0;
-    for (ASExternalRoutesCI k = m_ASexternalRoutes.begin(); k != m_ASexternalRoutes.end(); k++)
+    for (auto k = m_ASexternalRoutes.begin(); k != m_ASexternalRoutes.end(); k++)
     {
         if (tmp == index)
         {
@@ -292,7 +292,7 @@
     if (index < m_hostRoutes.size())
     {
         uint32_t tmp = 0;
-        for (HostRoutesI i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i++)
+        for (auto i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i++)
         {
             if (tmp == index)
             {
@@ -308,7 +308,7 @@
     }
     index -= m_hostRoutes.size();
     uint32_t tmp = 0;
-    for (NetworkRoutesI j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
+    for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
     {
         if (tmp == index)
         {
@@ -323,7 +323,7 @@
     }
     index -= m_networkRoutes.size();
     tmp = 0;
-    for (ASExternalRoutesI k = m_ASexternalRoutes.begin(); k != m_ASexternalRoutes.end(); k++)
+    for (auto k = m_ASexternalRoutes.begin(); k != m_ASexternalRoutes.end(); k++)
     {
         if (tmp == index)
         {
@@ -351,16 +351,15 @@
 Ipv4GlobalRouting::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (HostRoutesI i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i = m_hostRoutes.erase(i))
+    for (auto i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i = m_hostRoutes.erase(i))
     {
         delete (*i);
     }
-    for (NetworkRoutesI j = m_networkRoutes.begin(); j != m_networkRoutes.end();
-         j = m_networkRoutes.erase(j))
+    for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j = m_networkRoutes.erase(j))
     {
         delete (*j);
     }
-    for (ASExternalRoutesI l = m_ASexternalRoutes.begin(); l != m_ASexternalRoutes.end();
+    for (auto l = m_ASexternalRoutes.begin(); l != m_ASexternalRoutes.end();
          l = m_ASexternalRoutes.erase(l))
     {
         delete (*l);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-global-routing.h ns-3.40/src/internet/model/ipv4-global-routing.h
--- ns-3.39/src/internet/model/ipv4-global-routing.h	2023-07-05 14:23:47.845427500 -0700
+++ ns-3.40/src/internet/model/ipv4-global-routing.h	2023-09-27 13:30:37.654839000 -0700
@@ -19,10 +19,11 @@
 #ifndef IPV4_GLOBAL_ROUTING_H
 #define IPV4_GLOBAL_ROUTING_H
 
+#include "ipv4-header.h"
+#include "ipv4-routing-protocol.h"
+#include "ipv4.h"
+
 #include "ns3/ipv4-address.h"
-#include "ns3/ipv4-header.h"
-#include "ns3/ipv4-routing-protocol.h"
-#include "ns3/ipv4.h"
 #include "ns3/ptr.h"
 #include "ns3/random-variable-stream.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-interface.cc ns-3.40/src/internet/model/ipv4-interface.cc
--- ns-3.39/src/internet/model/ipv4-interface.cc	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-interface.cc	2023-09-27 13:30:37.654839000 -0700
@@ -232,7 +232,7 @@
     NS_ASSERT(m_tc);
 
     // is this packet aimed at a local interface ?
-    for (Ipv4InterfaceAddressListCI i = m_ifaddrs.begin(); i != m_ifaddrs.end(); ++i)
+    for (auto i = m_ifaddrs.begin(); i != m_ifaddrs.end(); ++i)
     {
         if (dest == (*i).GetLocal())
         {
@@ -271,7 +271,7 @@
         }
         else
         {
-            for (Ipv4InterfaceAddressListCI i = m_ifaddrs.begin(); i != m_ifaddrs.end(); ++i)
+            for (auto i = m_ifaddrs.begin(); i != m_ifaddrs.end(); ++i)
             {
                 if (dest.IsSubnetDirectedBroadcast((*i).GetMask()))
                 {
@@ -335,7 +335,7 @@
     if (index < m_ifaddrs.size())
     {
         uint32_t tmp = 0;
-        for (Ipv4InterfaceAddressListCI i = m_ifaddrs.begin(); i != m_ifaddrs.end(); i++)
+        for (auto i = m_ifaddrs.begin(); i != m_ifaddrs.end(); i++)
         {
             if (tmp == index)
             {
@@ -360,7 +360,7 @@
     {
         NS_FATAL_ERROR("Bug in Ipv4Interface::RemoveAddress");
     }
-    Ipv4InterfaceAddressListI i = m_ifaddrs.begin();
+    auto i = m_ifaddrs.begin();
     uint32_t tmp = 0;
     while (i != m_ifaddrs.end())
     {
@@ -393,7 +393,7 @@
         return Ipv4InterfaceAddress();
     }
 
-    for (Ipv4InterfaceAddressListI it = m_ifaddrs.begin(); it != m_ifaddrs.end(); it++)
+    for (auto it = m_ifaddrs.begin(); it != m_ifaddrs.end(); it++)
     {
         if ((*it).GetLocal() == address)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-l3-protocol.cc ns-3.40/src/internet/model/ipv4-l3-protocol.cc
--- ns-3.39/src/internet/model/ipv4-l3-protocol.cc	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-l3-protocol.cc	2023-09-27 13:30:37.654839000 -0700
@@ -176,7 +176,7 @@
     NS_LOG_FUNCTION(this << protocol);
 
     L4ListKey_t key = std::make_pair(protocol->GetProtocolNumber(), -1);
-    L4List_t::iterator iter = m_protocols.find(key);
+    auto iter = m_protocols.find(key);
     if (iter == m_protocols.end())
     {
         NS_LOG_WARN("Trying to remove an non-existent default protocol "
@@ -194,7 +194,7 @@
     NS_LOG_FUNCTION(this << protocol << interfaceIndex);
 
     L4ListKey_t key = std::make_pair(protocol->GetProtocolNumber(), interfaceIndex);
-    L4List_t::iterator iter = m_protocols.find(key);
+    auto iter = m_protocols.find(key);
     if (iter == m_protocols.end())
     {
         NS_LOG_WARN("Trying to remove an non-existent protocol "
@@ -220,21 +220,19 @@
 {
     NS_LOG_FUNCTION(this << protocolNumber << interfaceIndex);
 
-    L4ListKey_t key;
-    L4List_t::const_iterator i;
     if (interfaceIndex >= 0)
     {
         // try the interface-specific protocol.
-        key = std::make_pair(protocolNumber, interfaceIndex);
-        i = m_protocols.find(key);
+        auto key = std::make_pair(protocolNumber, interfaceIndex);
+        auto i = m_protocols.find(key);
         if (i != m_protocols.end())
         {
             return i->second;
         }
     }
     // try the generic protocol.
-    key = std::make_pair(protocolNumber, -1);
-    i = m_protocols.find(key);
+    auto key = std::make_pair(protocolNumber, -1);
+    auto i = m_protocols.find(key);
     if (i != m_protocols.end())
     {
         return i->second;
@@ -266,7 +264,7 @@
 Ipv4L3Protocol::DeleteRawSocket(Ptr<Socket> socket)
 {
     NS_LOG_FUNCTION(this << socket);
-    for (SocketList::iterator i = m_sockets.begin(); i != m_sockets.end(); ++i)
+    for (auto i = m_sockets.begin(); i != m_sockets.end(); ++i)
     {
         if ((*i) == socket)
         {
@@ -316,13 +314,13 @@
 Ipv4L3Protocol::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
+    for (auto i = m_protocols.begin(); i != m_protocols.end(); ++i)
     {
         i->second = nullptr;
     }
     m_protocols.clear();
 
-    for (Ipv4InterfaceList::iterator i = m_interfaces.begin(); i != m_interfaces.end(); ++i)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); ++i)
     {
         *i = nullptr;
     }
@@ -333,7 +331,7 @@
     m_node = nullptr;
     m_routingProtocol = nullptr;
 
-    for (MapFragments_t::iterator it = m_fragments.begin(); it != m_fragments.end(); it++)
+    for (auto it = m_fragments.begin(); it != m_fragments.end(); it++)
     {
         it->second = nullptr;
     }
@@ -464,8 +462,7 @@
 {
     NS_LOG_FUNCTION(this << address);
     int32_t interface = 0;
-    for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin(); i != m_interfaces.end();
-         i++, interface++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++, interface++)
     {
         for (uint32_t j = 0; j < (*i)->GetNAddresses(); j++)
         {
@@ -484,8 +481,7 @@
 {
     NS_LOG_FUNCTION(this << address << mask);
     int32_t interface = 0;
-    for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin(); i != m_interfaces.end();
-         i++, interface++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++, interface++)
     {
         for (uint32_t j = 0; j < (*i)->GetNAddresses(); j++)
         {
@@ -504,7 +500,7 @@
 {
     NS_LOG_FUNCTION(this << device);
 
-    Ipv4InterfaceReverseContainer::const_iterator iter = m_reverseInterfacesContainer.find(device);
+    auto iter = m_reverseInterfacesContainer.find(device);
     if (iter != m_reverseInterfacesContainer.end())
     {
         return (*iter).second;
@@ -650,8 +646,7 @@
             // addresses. In doubt, update all of them. Note: it's a confirmed behavior for Linux
             // routers.
             std::list<ArpCache::Entry*> entryList = arpCache->LookupInverse(from);
-            std::list<ArpCache::Entry*>::iterator iter;
-            for (iter = entryList.begin(); iter != entryList.end(); iter++)
+            for (auto iter = entryList.begin(); iter != entryList.end(); iter++)
             {
                 if ((*iter)->IsAlive())
                 {
@@ -661,7 +656,7 @@
         }
     }
 
-    for (SocketList::iterator i = m_sockets.begin(); i != m_sockets.end(); ++i)
+    for (auto i = m_sockets.begin(); i != m_sockets.end(); ++i)
     {
         NS_LOG_LOGIC("Forwarding to raw socket");
         Ptr<Ipv4RawSocketImpl> socket = *i;
@@ -834,8 +829,7 @@
     {
         NS_LOG_LOGIC("Ipv4L3Protocol::Send case 2:  limited broadcast - no route");
         uint32_t ifaceIndex = 0;
-        for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin();
-             ifaceIter != m_interfaces.end();
+        for (auto ifaceIter = m_interfaces.begin(); ifaceIter != m_interfaces.end();
              ifaceIter++, ifaceIndex++)
         {
             Ptr<Ipv4Interface> outInterface = *ifaceIter;
@@ -866,9 +860,7 @@
     }
 
     // 3) check: packet is destined to a subnet-directed broadcast address
-    for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin();
-         ifaceIter != m_interfaces.end();
-         ifaceIter++)
+    for (auto ifaceIter = m_interfaces.begin(); ifaceIter != m_interfaces.end(); ifaceIter++)
     {
         Ptr<Ipv4Interface> outInterface = *ifaceIter;
         uint32_t ifaceIndex = GetInterfaceForDevice(outInterface->GetDevice());
@@ -1019,9 +1011,7 @@
         {
             std::list<Ipv4PayloadHeaderPair> listFragments;
             DoFragmentation(packet, ipHeader, outInterface->GetDevice()->GetMtu(), listFragments);
-            for (std::list<Ipv4PayloadHeaderPair>::iterator it = listFragments.begin();
-                 it != listFragments.end();
-                 it++)
+            for (auto it = listFragments.begin(); it != listFragments.end(); it++)
             {
                 NS_LOG_LOGIC("Sending fragment " << *(it->first));
                 CallTxTrace(it->second, it->first, this, interface);
@@ -1046,9 +1036,8 @@
     NS_LOG_LOGIC("Multicast forwarding logic for node: " << m_node->GetId());
 
     std::map<uint32_t, uint32_t> ttlMap = mrtentry->GetOutputTtlMap();
-    std::map<uint32_t, uint32_t>::iterator mapIter;
 
-    for (mapIter = ttlMap.begin(); mapIter != ttlMap.end(); mapIter++)
+    for (auto mapIter = ttlMap.begin(); mapIter != ttlMap.end(); mapIter++)
     {
         uint32_t interface = mapIter->first;
         // uint32_t outputTtl = mapIter->second;  // Unused for now
@@ -1435,7 +1424,7 @@
 {
     NS_LOG_FUNCTION(this << forward);
     m_ipForward = forward;
-    for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin(); i != m_interfaces.end(); i++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++)
     {
         (*i)->SetForwarding(forward);
     }
@@ -1577,13 +1566,13 @@
 
     Ptr<Fragments> fragments;
 
-    MapFragments_t::iterator it = m_fragments.find(key);
+    auto it = m_fragments.find(key);
     if (it == m_fragments.end())
     {
         fragments = Create<Fragments>();
         m_fragments.insert(std::make_pair(key, fragments));
 
-        FragmentsTimeoutsListI_t iter = SetTimeout(key, ipHeader, iif);
+        auto iter = SetTimeout(key, ipHeader, iif);
         fragments->SetTimeoutIter(iter);
     }
     else
@@ -1609,7 +1598,7 @@
 }
 
 Ipv4L3Protocol::Fragments::Fragments()
-    : m_moreFragment(0)
+    : m_moreFragment(false)
 {
     NS_LOG_FUNCTION(this);
 }
@@ -1650,9 +1639,7 @@
     {
         uint16_t lastEndOffset = 0;
 
-        for (std::list<std::pair<Ptr<Packet>, uint16_t>>::const_iterator it = m_fragments.begin();
-             it != m_fragments.end();
-             it++)
+        for (auto it = m_fragments.begin(); it != m_fragments.end(); it++)
         {
             // overlapping fragments do exist
             NS_LOG_LOGIC("Checking overlaps " << lastEndOffset << " - " << it->second);
@@ -1676,7 +1663,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::list<std::pair<Ptr<Packet>, uint16_t>>::const_iterator it = m_fragments.begin();
+    auto it = m_fragments.begin();
 
     Ptr<Packet> p = it->first->Copy();
     uint16_t lastEndOffset = p->GetSize();
@@ -1714,7 +1701,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::list<std::pair<Ptr<Packet>, uint16_t>>::const_iterator it = m_fragments.begin();
+    auto it = m_fragments.begin();
 
     Ptr<Packet> p = Create<Packet>();
     uint16_t lastEndOffset = 0;
@@ -1761,7 +1748,7 @@
 {
     NS_LOG_FUNCTION(this << &key << &ipHeader << iif);
 
-    MapFragments_t::iterator it = m_fragments.find(key);
+    auto it = m_fragments.find(key);
     Ptr<Packet> packet = it->second->GetPartialPacket();
 
     // if we have at least 8 bytes, we can send an ICMP.
@@ -1837,11 +1824,8 @@
                            << std::get<3>(key) << ")");
 
     // place a new entry, on collision the existing entry iterator is returned
-    DupMap_t::iterator iter;
-    bool inserted;
-    bool isDup;
-    std::tie(iter, inserted) = m_dups.emplace(key, Seconds(0));
-    isDup = !inserted && iter->second > Simulator::Now();
+    auto [iter, inserted] = m_dups.emplace(key, Seconds(0));
+    bool isDup = !inserted && iter->second > Simulator::Now();
 
     // set the expiration event
     iter->second = Simulator::Now() + m_expire;
@@ -1894,7 +1878,7 @@
     }
     m_timeoutEventList.emplace_back(now, key, ipHeader, iif);
 
-    Ipv4L3Protocol::FragmentsTimeoutsListI_t iter = --m_timeoutEventList.end();
+    auto iter = --m_timeoutEventList.end();
 
     return (iter);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-l3-protocol.h ns-3.40/src/internet/model/ipv4-l3-protocol.h
--- ns-3.39/src/internet/model/ipv4-l3-protocol.h	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-l3-protocol.h	2023-09-27 13:30:37.654839000 -0700
@@ -20,10 +20,11 @@
 #ifndef IPV4_L3_PROTOCOL_H
 #define IPV4_L3_PROTOCOL_H
 
+#include "ipv4-header.h"
+#include "ipv4-routing-protocol.h"
+#include "ipv4.h"
+
 #include "ns3/ipv4-address.h"
-#include "ns3/ipv4-header.h"
-#include "ns3/ipv4-routing-protocol.h"
-#include "ns3/ipv4.h"
 #include "ns3/net-device.h"
 #include "ns3/nstime.h"
 #include "ns3/ptr.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-list-routing.cc ns-3.40/src/internet/model/ipv4-list-routing.cc
--- ns-3.39/src/internet/model/ipv4-list-routing.cc	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-list-routing.cc	2023-09-27 13:30:37.654839000 -0700
@@ -56,8 +56,7 @@
 Ipv4ListRouting::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (Ipv4RoutingProtocolList::iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         // Note:  Calling dispose on these protocols causes memory leak
@@ -77,9 +76,7 @@
                          << ", Time: " << Now().As(unit)
                          << ", Local time: " << m_ipv4->GetObject<Node>()->GetLocalTime().As(unit)
                          << ", Ipv4ListRouting table" << std::endl;
-    for (Ipv4RoutingProtocolList::const_iterator i = m_routingProtocols.begin();
-         i != m_routingProtocols.end();
-         i++)
+    for (auto i = m_routingProtocols.begin(); i != m_routingProtocols.end(); i++)
     {
         *stream->GetStream() << "  Priority: " << (*i).first
                              << " Protocol: " << (*i).second->GetInstanceTypeId() << std::endl;
@@ -91,8 +88,7 @@
 Ipv4ListRouting::DoInitialize()
 {
     NS_LOG_FUNCTION(this);
-    for (Ipv4RoutingProtocolList::iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         Ptr<Ipv4RoutingProtocol> protocol = (*rprotoIter).second;
@@ -110,9 +106,7 @@
     NS_LOG_FUNCTION(this << p << header.GetDestination() << header.GetSource() << oif << sockerr);
     Ptr<Ipv4Route> route;
 
-    for (Ipv4RoutingProtocolList::const_iterator i = m_routingProtocols.begin();
-         i != m_routingProtocols.end();
-         i++)
+    for (auto i = m_routingProtocols.begin(); i != m_routingProtocols.end(); i++)
     {
         NS_LOG_LOGIC("Checking protocol " << (*i).second->GetInstanceTypeId() << " with priority "
                                           << (*i).first);
@@ -182,8 +176,7 @@
     {
         downstreamLcb = MakeNullCallback<void, Ptr<const Packet>, const Ipv4Header&, uint32_t>();
     }
-    for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         if ((*rprotoIter).second->RouteInput(p, header, idev, ucb, mcb, downstreamLcb, ecb))
@@ -201,8 +194,7 @@
 Ipv4ListRouting::NotifyInterfaceUp(uint32_t interface)
 {
     NS_LOG_FUNCTION(this << interface);
-    for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->NotifyInterfaceUp(interface);
@@ -213,8 +205,7 @@
 Ipv4ListRouting::NotifyInterfaceDown(uint32_t interface)
 {
     NS_LOG_FUNCTION(this << interface);
-    for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->NotifyInterfaceDown(interface);
@@ -225,8 +216,7 @@
 Ipv4ListRouting::NotifyAddAddress(uint32_t interface, Ipv4InterfaceAddress address)
 {
     NS_LOG_FUNCTION(this << interface << address);
-    for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->NotifyAddAddress(interface, address);
@@ -237,8 +227,7 @@
 Ipv4ListRouting::NotifyRemoveAddress(uint32_t interface, Ipv4InterfaceAddress address)
 {
     NS_LOG_FUNCTION(this << interface << address);
-    for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->NotifyRemoveAddress(interface, address);
@@ -250,8 +239,7 @@
 {
     NS_LOG_FUNCTION(this << ipv4);
     NS_ASSERT(!m_ipv4);
-    for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->SetIpv4(ipv4);
@@ -288,8 +276,7 @@
                                                                         << " out of range");
     }
     uint32_t i = 0;
-    for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++, i++)
     {
         if (i == index)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-list-routing.h ns-3.40/src/internet/model/ipv4-list-routing.h
--- ns-3.39/src/internet/model/ipv4-list-routing.h	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-list-routing.h	2023-09-27 13:30:37.658839200 -0700
@@ -18,7 +18,8 @@
 #ifndef IPV4_LIST_ROUTING_H
 #define IPV4_LIST_ROUTING_H
 
-#include "ns3/ipv4-routing-protocol.h"
+#include "ipv4-routing-protocol.h"
+
 #include "ns3/nstime.h"
 #include "ns3/simulator.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-packet-probe.h ns-3.40/src/internet/model/ipv4-packet-probe.h
--- ns-3.39/src/internet/model/ipv4-packet-probe.h	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-packet-probe.h	2023-09-27 13:30:37.658839200 -0700
@@ -23,9 +23,10 @@
 #ifndef IPV4_PACKET_PROBE_H
 #define IPV4_PACKET_PROBE_H
 
+#include "ipv4.h"
+
 #include "ns3/boolean.h"
 #include "ns3/callback.h"
-#include "ns3/ipv4.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
 #include "ns3/packet.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-raw-socket-factory-impl.h ns-3.40/src/internet/model/ipv4-raw-socket-factory-impl.h
--- ns-3.39/src/internet/model/ipv4-raw-socket-factory-impl.h	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-raw-socket-factory-impl.h	2023-09-27 13:30:37.658839200 -0700
@@ -20,7 +20,7 @@
 #ifndef IPV4_RAW_SOCKET_FACTORY_IMPL_H
 #define IPV4_RAW_SOCKET_FACTORY_IMPL_H
 
-#include "ns3/ipv4-raw-socket-factory.h"
+#include "ipv4-raw-socket-factory.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-raw-socket-impl.cc ns-3.40/src/internet/model/ipv4-raw-socket-impl.cc
--- ns-3.39/src/internet/model/ipv4-raw-socket-impl.cc	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-raw-socket-impl.cc	2023-09-27 13:30:37.658839200 -0700
@@ -400,7 +400,7 @@
 {
     NS_LOG_FUNCTION(this);
     uint32_t rx = 0;
-    for (std::list<Data>::const_iterator i = m_recv.begin(); i != m_recv.end(); ++i)
+    for (auto i = m_recv.begin(); i != m_recv.end(); ++i)
     {
         rx += (i->packet)->GetSize();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-raw-socket-impl.h ns-3.40/src/internet/model/ipv4-raw-socket-impl.h
--- ns-3.39/src/internet/model/ipv4-raw-socket-impl.h	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-raw-socket-impl.h	2023-09-27 13:30:37.658839200 -0700
@@ -1,9 +1,10 @@
 #ifndef IPV4_RAW_SOCKET_IMPL_H
 #define IPV4_RAW_SOCKET_IMPL_H
 
-#include "ns3/ipv4-header.h"
-#include "ns3/ipv4-interface.h"
-#include "ns3/ipv4-route.h"
+#include "ipv4-header.h"
+#include "ipv4-interface.h"
+#include "ipv4-route.h"
+
 #include "ns3/socket.h"
 
 #include <list>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-route.cc ns-3.40/src/internet/model/ipv4-route.cc
--- ns-3.39/src/internet/model/ipv4-route.cc	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-route.cc	2023-09-27 13:30:37.658839200 -0700
@@ -151,8 +151,7 @@
     if (ttl >= MAX_TTL)
     {
         // This TTL value effectively disables the interface
-        std::map<uint32_t, uint32_t>::iterator iter;
-        iter = m_ttls.find(oif);
+        auto iter = m_ttls.find(oif);
         if (iter != m_ttls.end())
         {
             m_ttls.erase(iter);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-routing-protocol.h ns-3.40/src/internet/model/ipv4-routing-protocol.h
--- ns-3.39/src/internet/model/ipv4-routing-protocol.h	2023-07-05 14:23:47.849427500 -0700
+++ ns-3.40/src/internet/model/ipv4-routing-protocol.h	2023-09-27 13:30:37.658839200 -0700
@@ -18,10 +18,10 @@
 #define IPV4_ROUTING_PROTOCOL_H
 
 #include "ipv4-header.h"
+#include "ipv4-interface-address.h"
 #include "ipv4.h"
 
 #include "ns3/callback.h"
-#include "ns3/ipv4-interface-address.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
 #include "ns3/output-stream-wrapper.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-static-routing.cc ns-3.40/src/internet/model/ipv4-static-routing.cc
--- ns-3.39/src/internet/model/ipv4-static-routing.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv4-static-routing.cc	2023-09-27 13:30:37.658839200 -0700
@@ -78,7 +78,7 @@
 
     if (!LookupRoute(route, metric))
     {
-        Ipv4RoutingTableEntry* routePtr = new Ipv4RoutingTableEntry(route);
+        auto routePtr = new Ipv4RoutingTableEntry(route);
         m_networkRoutes.emplace_back(routePtr, metric);
     }
 }
@@ -95,7 +95,7 @@
         Ipv4RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, interface);
     if (!LookupRoute(route, metric))
     {
-        Ipv4RoutingTableEntry* routePtr = new Ipv4RoutingTableEntry(route);
+        auto routePtr = new Ipv4RoutingTableEntry(route);
 
         m_networkRoutes.emplace_back(routePtr, metric);
     }
@@ -133,7 +133,7 @@
 {
     NS_LOG_FUNCTION(this << origin << " " << group << " " << inputInterface << " "
                          << &outputInterfaces);
-    Ipv4MulticastRoutingTableEntry* route = new Ipv4MulticastRoutingTableEntry();
+    auto route = new Ipv4MulticastRoutingTableEntry();
     *route = Ipv4MulticastRoutingTableEntry::CreateMulticastRoute(origin,
                                                                   group,
                                                                   inputInterface,
@@ -148,9 +148,9 @@
 Ipv4StaticRouting::SetDefaultMulticastRoute(uint32_t outputInterface)
 {
     NS_LOG_FUNCTION(this << outputInterface);
-    Ipv4RoutingTableEntry* route = new Ipv4RoutingTableEntry();
-    Ipv4Address network = Ipv4Address("224.0.0.0");
-    Ipv4Mask networkMask = Ipv4Mask("240.0.0.0");
+    auto route = new Ipv4RoutingTableEntry();
+    Ipv4Address network("224.0.0.0");
+    Ipv4Mask networkMask("240.0.0.0");
     *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, outputInterface);
     m_networkRoutes.emplace_back(route, 0);
 }
@@ -172,7 +172,7 @@
     if (index < m_multicastRoutes.size())
     {
         uint32_t tmp = 0;
-        for (MulticastRoutesCI i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
+        for (auto i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
         {
             if (tmp == index)
             {
@@ -190,7 +190,7 @@
                                         uint32_t inputInterface)
 {
     NS_LOG_FUNCTION(this << origin << " " << group << " " << inputInterface);
-    for (MulticastRoutesI i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
+    for (auto i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
     {
         Ipv4MulticastRoutingTableEntry* route = *i;
         if (origin == route->GetOrigin() && group == route->GetGroup() &&
@@ -209,7 +209,7 @@
 {
     NS_LOG_FUNCTION(this << index);
     uint32_t tmp = 0;
-    for (MulticastRoutesI i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
+    for (auto i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
     {
         if (tmp == index)
         {
@@ -224,7 +224,7 @@
 bool
 Ipv4StaticRouting::LookupRoute(const Ipv4RoutingTableEntry& route, uint32_t metric)
 {
-    for (NetworkRoutesI j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
+    for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
     {
         Ipv4RoutingTableEntry* rtentry = j->first;
 
@@ -261,7 +261,7 @@
         return rtentry;
     }
 
-    for (NetworkRoutesI i = m_networkRoutes.begin(); i != m_networkRoutes.end(); i++)
+    for (auto i = m_networkRoutes.begin(); i != m_networkRoutes.end(); i++)
     {
         Ipv4RoutingTableEntry* j = i->first;
         uint32_t metric = i->second;
@@ -328,7 +328,7 @@
     NS_LOG_FUNCTION(this << origin << " " << group << " " << interface);
     Ptr<Ipv4MulticastRoute> mrtentry = nullptr;
 
-    for (MulticastRoutesI i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
+    for (auto i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
     {
         Ipv4MulticastRoutingTableEntry* route = *i;
         //
@@ -385,7 +385,7 @@
     Ipv4Address dest("0.0.0.0");
     uint32_t shortest_metric = 0xffffffff;
     Ipv4RoutingTableEntry* result = nullptr;
-    for (NetworkRoutesI i = m_networkRoutes.begin(); i != m_networkRoutes.end(); i++)
+    for (auto i = m_networkRoutes.begin(); i != m_networkRoutes.end(); i++)
     {
         Ipv4RoutingTableEntry* j = i->first;
         uint32_t metric = i->second;
@@ -417,7 +417,7 @@
 {
     NS_LOG_FUNCTION(this << index);
     uint32_t tmp = 0;
-    for (NetworkRoutesCI j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
+    for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
     {
         if (tmp == index)
         {
@@ -435,7 +435,7 @@
 {
     NS_LOG_FUNCTION(this << index);
     uint32_t tmp = 0;
-    for (NetworkRoutesCI j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
+    for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
     {
         if (tmp == index)
         {
@@ -453,7 +453,7 @@
 {
     NS_LOG_FUNCTION(this << index);
     uint32_t tmp = 0;
-    for (NetworkRoutesI j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
+    for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
     {
         if (tmp == index)
         {
@@ -588,12 +588,11 @@
 Ipv4StaticRouting::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (NetworkRoutesI j = m_networkRoutes.begin(); j != m_networkRoutes.end();
-         j = m_networkRoutes.erase(j))
+    for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j = m_networkRoutes.erase(j))
     {
         delete (j->first);
     }
-    for (MulticastRoutesI i = m_multicastRoutes.begin(); i != m_multicastRoutes.end();
+    for (auto i = m_multicastRoutes.begin(); i != m_multicastRoutes.end();
          i = m_multicastRoutes.erase(i))
     {
         delete (*i);
@@ -628,7 +627,7 @@
 {
     NS_LOG_FUNCTION(this << i);
     // Remove all static routes that are going through this interface
-    for (NetworkRoutesI it = m_networkRoutes.begin(); it != m_networkRoutes.end();)
+    for (auto it = m_networkRoutes.begin(); it != m_networkRoutes.end();)
     {
         if (it->first->GetInterface() == i)
         {
@@ -671,7 +670,7 @@
     Ipv4Mask networkMask = address.GetMask();
     // Remove all static routes that are going through this interface
     // which reference this network
-    for (NetworkRoutesI it = m_networkRoutes.begin(); it != m_networkRoutes.end();)
+    for (auto it = m_networkRoutes.begin(); it != m_networkRoutes.end();)
     {
         if (it->first->GetInterface() == interface && it->first->IsNetwork() &&
             it->first->GetDestNetwork() == networkAddress &&
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv4-static-routing.h ns-3.40/src/internet/model/ipv4-static-routing.h
--- ns-3.39/src/internet/model/ipv4-static-routing.h	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv4-static-routing.h	2023-09-27 13:30:37.658839200 -0700
@@ -21,10 +21,11 @@
 #ifndef IPV4_STATIC_ROUTING_H
 #define IPV4_STATIC_ROUTING_H
 
+#include "ipv4-header.h"
+#include "ipv4-routing-protocol.h"
+#include "ipv4.h"
+
 #include "ns3/ipv4-address.h"
-#include "ns3/ipv4-header.h"
-#include "ns3/ipv4-routing-protocol.h"
-#include "ns3/ipv4.h"
 #include "ns3/ptr.h"
 #include "ns3/socket.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-address-generator.cc ns-3.40/src/internet/model/ipv6-address-generator.cc
--- ns-3.39/src/internet/model/ipv6-address-generator.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-address-generator.cc	2023-09-27 13:30:37.658839200 -0700
@@ -515,7 +515,7 @@
         taddr[15] += 1;
         if (Ipv6Address(addr) == Ipv6Address(taddr))
         {
-            std::list<Entry>::iterator j = i;
+            auto j = i;
             ++j;
 
             if (j != m_entries.end())
@@ -581,9 +581,7 @@
     uint8_t addr[16];
     address.GetBytes(addr);
 
-    std::list<Entry>::iterator i;
-
-    for (i = m_entries.begin(); i != m_entries.end(); ++i)
+    for (auto i = m_entries.begin(); i != m_entries.end(); ++i)
     {
         NS_LOG_LOGIC("examine entry: " << Ipv6Address((*i).addrLow) << " to "
                                        << Ipv6Address((*i).addrHigh));
@@ -594,10 +592,10 @@
         {
             NS_LOG_LOGIC("Ipv6AddressGeneratorImpl::IsAddressAllocated(): Address Collision: "
                          << Ipv6Address(addr));
-            return false;
+            return true;
         }
     }
-    return true;
+    return false;
 }
 
 bool
@@ -610,9 +608,7 @@
         "Ipv6AddressGeneratorImpl::IsNetworkAllocated(): network address and mask don't match "
             << address << " " << prefix);
 
-    std::list<Entry>::iterator i;
-
-    for (i = m_entries.begin(); i != m_entries.end(); ++i)
+    for (auto i = m_entries.begin(); i != m_entries.end(); ++i)
     {
         NS_LOG_LOGIC("examine entry: " << Ipv6Address((*i).addrLow) << " to "
                                        << Ipv6Address((*i).addrHigh));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-end-point-demux.cc ns-3.40/src/internet/model/ipv6-end-point-demux.cc
--- ns-3.39/src/internet/model/ipv6-end-point-demux.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-end-point-demux.cc	2023-09-27 13:30:37.658839200 -0700
@@ -39,7 +39,7 @@
 Ipv6EndPointDemux::~Ipv6EndPointDemux()
 {
     NS_LOG_FUNCTION(this);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         Ipv6EndPoint* endPoint = *i;
         delete endPoint;
@@ -51,7 +51,7 @@
 Ipv6EndPointDemux::LookupPortLocal(uint16_t port)
 {
     NS_LOG_FUNCTION(this << port);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         if ((*i)->GetLocalPort() == port)
         {
@@ -65,7 +65,7 @@
 Ipv6EndPointDemux::LookupLocal(Ptr<NetDevice> boundNetDevice, Ipv6Address addr, uint16_t port)
 {
     NS_LOG_FUNCTION(this << addr << port);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         if ((*i)->GetLocalPort() == port && (*i)->GetLocalAddress() == addr &&
             (*i)->GetBoundNetDevice() == boundNetDevice)
@@ -86,7 +86,7 @@
         NS_LOG_WARN("Ephemeral port allocation failed.");
         return nullptr;
     }
-    Ipv6EndPoint* endPoint = new Ipv6EndPoint(Ipv6Address::GetAny(), port);
+    auto endPoint = new Ipv6EndPoint(Ipv6Address::GetAny(), port);
     m_endPoints.push_back(endPoint);
     NS_LOG_DEBUG("Now have >>" << m_endPoints.size() << "<< endpoints.");
     return endPoint;
@@ -102,7 +102,7 @@
         NS_LOG_WARN("Ephemeral port allocation failed.");
         return nullptr;
     }
-    Ipv6EndPoint* endPoint = new Ipv6EndPoint(address, port);
+    auto endPoint = new Ipv6EndPoint(address, port);
     m_endPoints.push_back(endPoint);
     NS_LOG_DEBUG("Now have >>" << m_endPoints.size() << "<< endpoints.");
     return endPoint;
@@ -125,7 +125,7 @@
         NS_LOG_WARN("Duplicated endpoint.");
         return nullptr;
     }
-    Ipv6EndPoint* endPoint = new Ipv6EndPoint(address, port);
+    auto endPoint = new Ipv6EndPoint(address, port);
     m_endPoints.push_back(endPoint);
     NS_LOG_DEBUG("Now have >>" << m_endPoints.size() << "<< endpoints.");
     return endPoint;
@@ -139,7 +139,7 @@
                             uint16_t peerPort)
 {
     NS_LOG_FUNCTION(this << boundNetDevice << localAddress << localPort << peerAddress << peerPort);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         if ((*i)->GetLocalPort() == localPort && (*i)->GetLocalAddress() == localAddress &&
             (*i)->GetPeerPort() == peerPort && (*i)->GetPeerAddress() == peerAddress &&
@@ -149,7 +149,7 @@
             return nullptr;
         }
     }
-    Ipv6EndPoint* endPoint = new Ipv6EndPoint(localAddress, localPort);
+    auto endPoint = new Ipv6EndPoint(localAddress, localPort);
     endPoint->SetPeer(peerAddress, peerPort);
     m_endPoints.push_back(endPoint);
 
@@ -162,7 +162,7 @@
 Ipv6EndPointDemux::DeAllocate(Ipv6EndPoint* endPoint)
 {
     NS_LOG_FUNCTION(this);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         if (*i == endPoint)
         {
@@ -193,7 +193,7 @@
     EndPoints retval4; /* Exact match on all 4 */
 
     NS_LOG_DEBUG("Looking up endpoint for destination address " << daddr);
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         Ipv6EndPoint* endP = *i;
 
@@ -313,7 +313,7 @@
     uint32_t genericity = 3;
     Ipv6EndPoint* generic = nullptr;
 
-    for (EndPointsI i = m_endPoints.begin(); i != m_endPoints.end(); i++)
+    for (auto i = m_endPoints.begin(); i != m_endPoints.end(); i++)
     {
         uint32_t tmp = 0;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-end-point.h ns-3.40/src/internet/model/ipv6-end-point.h
--- ns-3.39/src/internet/model/ipv6-end-point.h	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-end-point.h	2023-09-27 13:30:37.658839200 -0700
@@ -20,10 +20,11 @@
 #ifndef IPV6_END_POINT_H
 #define IPV6_END_POINT_H
 
+#include "ipv6-header.h"
+#include "ipv6-interface.h"
+
 #include "ns3/callback.h"
 #include "ns3/ipv6-address.h"
-#include "ns3/ipv6-header.h"
-#include "ns3/ipv6-interface.h"
 #include "ns3/net-device.h"
 
 #include <stdint.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-extension.cc ns-3.40/src/internet/model/ipv6-extension.cc
--- ns-3.39/src/internet/model/ipv6-extension.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-extension.cc	2023-09-27 13:30:37.658839200 -0700
@@ -109,7 +109,7 @@
 
     uint8_t processedSize = 0;
     uint32_t size = p->GetSize();
-    uint8_t* data = new uint8_t[size];
+    auto data = new uint8_t[size];
     p->CopyData(data, size);
 
     uint8_t optionType = 0;
@@ -354,7 +354,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    for (MapFragments_t::iterator it = m_fragments.begin(); it != m_fragments.end(); it++)
+    for (auto it = m_fragments.begin(); it != m_fragments.end(); it++)
     {
         it->second = nullptr;
     }
@@ -408,7 +408,7 @@
     Ipv6Header ipHeader = ipv6Header;
     ipHeader.SetNextHeader(fragmentHeader.GetNextHeader());
 
-    MapFragments_t::iterator it = m_fragments.find(fragmentKey);
+    auto it = m_fragments.find(fragmentKey);
     if (it == m_fragments.end())
     {
         fragments = Create<Fragments>();
@@ -416,7 +416,7 @@
         NS_LOG_DEBUG("Insert new fragment key: src: "
                      << src << " IP hdr id " << identification << " m_fragments.size() "
                      << m_fragments.size() << " offset " << fragmentOffset);
-        FragmentsTimeoutsListI_t iter = SetTimeout(fragmentKey, ipHeader);
+        auto iter = SetTimeout(fragmentKey, ipHeader);
         fragments->SetTimeoutIter(iter);
     }
     else
@@ -487,7 +487,7 @@
     {
         if (nextHeader == Ipv6Header::IPV6_EXT_HOP_BY_HOP)
         {
-            Ipv6ExtensionHopByHopHeader* hopbyhopHeader = new Ipv6ExtensionHopByHopHeader();
+            auto hopbyhopHeader = new Ipv6ExtensionHopByHopHeader();
             p->RemoveHeader(*hopbyhopHeader);
 
             nextHeader = hopbyhopHeader->GetNextHeader();
@@ -541,8 +541,7 @@
         }
         else if (nextHeader == Ipv6Header::IPV6_EXT_DESTINATION)
         {
-            Ipv6ExtensionDestinationHeader* destinationHeader =
-                new Ipv6ExtensionDestinationHeader();
+            auto destinationHeader = new Ipv6ExtensionDestinationHeader();
             p->RemoveHeader(*destinationHeader);
 
             nextHeader = destinationHeader->GetNextHeader();
@@ -572,7 +571,7 @@
     uint32_t currentFragmentablePartSize = 0;
 
     bool moreFragment = true;
-    uint32_t identification = (uint32_t)m_uvar->GetValue(0, (uint32_t)-1);
+    auto identification = (uint32_t)m_uvar->GetValue(0, (uint32_t)-1);
     uint16_t offset = 0;
 
     do
@@ -599,29 +598,23 @@
 
         fragment->AddHeader(fragmentHeader);
 
-        for (std::list<std::pair<Ipv6ExtensionHeader*, uint8_t>>::iterator it =
-                 unfragmentablePart.begin();
-             it != unfragmentablePart.end();
-             it++)
+        for (auto it = unfragmentablePart.begin(); it != unfragmentablePart.end(); it++)
         {
             if (it->second == Ipv6Header::IPV6_EXT_HOP_BY_HOP)
             {
-                Ipv6ExtensionHopByHopHeader* p =
-                    dynamic_cast<Ipv6ExtensionHopByHopHeader*>(it->first);
+                auto p = dynamic_cast<Ipv6ExtensionHopByHopHeader*>(it->first);
                 NS_ASSERT(p != nullptr);
                 fragment->AddHeader(*p);
             }
             else if (it->second == Ipv6Header::IPV6_EXT_ROUTING)
             {
-                Ipv6ExtensionLooseRoutingHeader* p =
-                    dynamic_cast<Ipv6ExtensionLooseRoutingHeader*>(it->first);
+                auto p = dynamic_cast<Ipv6ExtensionLooseRoutingHeader*>(it->first);
                 NS_ASSERT(p != nullptr);
                 fragment->AddHeader(*p);
             }
             else if (it->second == Ipv6Header::IPV6_EXT_DESTINATION)
             {
-                Ipv6ExtensionDestinationHeader* p =
-                    dynamic_cast<Ipv6ExtensionDestinationHeader*>(it->first);
+                auto p = dynamic_cast<Ipv6ExtensionDestinationHeader*>(it->first);
                 NS_ASSERT(p != nullptr);
                 fragment->AddHeader(*p);
             }
@@ -636,10 +629,7 @@
         listFragments.emplace_back(fragment, ipv6Header);
     } while (moreFragment);
 
-    for (std::list<std::pair<Ipv6ExtensionHeader*, uint8_t>>::iterator it =
-             unfragmentablePart.begin();
-         it != unfragmentablePart.end();
-         it++)
+    for (auto it = unfragmentablePart.begin(); it != unfragmentablePart.end(); it++)
     {
         delete it->first;
     }
@@ -653,7 +643,7 @@
     NS_LOG_FUNCTION(this << fragmentKey.first << fragmentKey.second << ipHeader);
     Ptr<Fragments> fragments;
 
-    MapFragments_t::iterator it = m_fragments.find(fragmentKey);
+    auto it = m_fragments.find(fragmentKey);
     NS_ASSERT_MSG(it != m_fragments.end(),
                   "IPv6 Fragment timeout reached for non-existent fragment");
     fragments = it->second;
@@ -694,7 +684,7 @@
                  << key.second);
     m_timeoutEventList.emplace_back(Simulator::Now() + m_fragmentExpirationTimeout, key, ipHeader);
 
-    Ipv6ExtensionFragment::FragmentsTimeoutsListI_t iter = --m_timeoutEventList.end();
+    auto iter = --m_timeoutEventList.end();
 
     return (iter);
 }
@@ -730,7 +720,7 @@
 }
 
 Ipv6ExtensionFragment::Fragments::Fragments()
-    : m_moreFragment(0)
+    : m_moreFragment(false)
 {
 }
 
@@ -778,10 +768,7 @@
     {
         uint16_t lastEndOffset = 0;
 
-        for (std::list<std::pair<Ptr<Packet>, uint16_t>>::const_iterator it =
-                 m_packetFragments.begin();
-             it != m_packetFragments.end();
-             it++)
+        for (auto it = m_packetFragments.begin(); it != m_packetFragments.end(); it++)
         {
             if (lastEndOffset != it->second)
             {
@@ -801,9 +788,7 @@
 {
     Ptr<Packet> p = m_unfragmentable->Copy();
 
-    for (std::list<std::pair<Ptr<Packet>, uint16_t>>::const_iterator it = m_packetFragments.begin();
-         it != m_packetFragments.end();
-         it++)
+    for (auto it = m_packetFragments.begin(); it != m_packetFragments.end(); it++)
     {
         p->AddAtEnd(it->first);
     }
@@ -827,9 +812,7 @@
 
     uint16_t lastEndOffset = 0;
 
-    for (std::list<std::pair<Ptr<Packet>, uint16_t>>::const_iterator it = m_packetFragments.begin();
-         it != m_packetFragments.end();
-         it++)
+    for (auto it = m_packetFragments.begin(); it != m_packetFragments.end(); it++)
     {
         if (lastEndOffset != it->second)
         {
@@ -993,9 +976,7 @@
 Ipv6ExtensionRoutingDemux::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (Ipv6ExtensionRoutingList_t::iterator it = m_extensionsRouting.begin();
-         it != m_extensionsRouting.end();
-         it++)
+    for (auto it = m_extensionsRouting.begin(); it != m_extensionsRouting.end(); it++)
     {
         (*it)->Dispose();
         *it = nullptr;
@@ -1310,7 +1291,7 @@
 
     /** \todo */
 
-    return true;
+    return 1;
 }
 
 } /* namespace ns3 */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-extension-demux.cc ns-3.40/src/internet/model/ipv6-extension-demux.cc
--- ns-3.39/src/internet/model/ipv6-extension-demux.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-extension-demux.cc	2023-09-27 13:30:37.658839200 -0700
@@ -58,7 +58,7 @@
 void
 Ipv6ExtensionDemux::DoDispose()
 {
-    for (Ipv6ExtensionList_t::iterator it = m_extensions.begin(); it != m_extensions.end(); it++)
+    for (auto it = m_extensions.begin(); it != m_extensions.end(); it++)
     {
         (*it)->Dispose();
         *it = nullptr;
@@ -83,7 +83,7 @@
 Ptr<Ipv6Extension>
 Ipv6ExtensionDemux::GetExtension(uint8_t extensionNumber)
 {
-    for (Ipv6ExtensionList_t::iterator i = m_extensions.begin(); i != m_extensions.end(); ++i)
+    for (auto i = m_extensions.begin(); i != m_extensions.end(); ++i)
     {
         if ((*i)->GetExtensionNumber() == extensionNumber)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-extension.h ns-3.40/src/internet/model/ipv6-extension.h
--- ns-3.39/src/internet/model/ipv6-extension.h	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-extension.h	2023-09-27 13:30:37.658839200 -0700
@@ -21,12 +21,12 @@
 #define IPV6_EXTENSION_H
 
 #include "ipv6-extension-header.h"
+#include "ipv6-header.h"
 #include "ipv6-interface.h"
+#include "ipv6-l3-protocol.h"
 
 #include "ns3/buffer.h"
 #include "ns3/ipv6-address.h"
-#include "ns3/ipv6-header.h"
-#include "ns3/ipv6-l3-protocol.h"
 #include "ns3/node.h"
 #include "ns3/object.h"
 #include "ns3/packet.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-extension-header.cc ns-3.40/src/internet/model/ipv6-extension-header.cc
--- ns-3.39/src/internet/model/ipv6-extension-header.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-extension-header.cc	2023-09-27 13:30:37.658839200 -0700
@@ -118,7 +118,7 @@
     m_length = i.ReadU8();
 
     uint32_t dataLength = GetLength() - 2;
-    uint8_t* data = new uint8_t[dataLength];
+    auto data = new uint8_t[dataLength];
     i.Read(data, dataLength);
 
     if (dataLength > m_data.GetSize())
@@ -175,7 +175,7 @@
 uint32_t
 OptionField::Deserialize(Buffer::Iterator start, uint32_t length)
 {
-    uint8_t* buf = new uint8_t[length];
+    auto buf = new uint8_t[length];
     start.Read(buf, length);
     m_optionData = Buffer();
     m_optionData.AddAtEnd(length);
@@ -613,9 +613,7 @@
        << " typeRouting = " << (uint32_t)GetTypeRouting()
        << " segmentsLeft = " << (uint32_t)GetSegmentsLeft() << " ";
 
-    for (std::vector<Ipv6Address>::const_iterator it = m_routersAddress.begin();
-         it != m_routersAddress.end();
-         it++)
+    for (auto it = m_routersAddress.begin(); it != m_routersAddress.end(); it++)
     {
         os << *it << " ";
     }
@@ -643,9 +641,7 @@
     i.WriteU8(GetSegmentsLeft());
     i.WriteU32(0);
 
-    for (VectorIpv6Address_t::const_iterator it = m_routersAddress.begin();
-         it != m_routersAddress.end();
-         it++)
+    for (auto it = m_routersAddress.begin(); it != m_routersAddress.end(); it++)
     {
         it->Serialize(buff);
         i.Write(buff, 16);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-interface.cc ns-3.40/src/internet/model/ipv6-interface.cc
--- ns-3.39/src/internet/model/ipv6-interface.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-interface.cc	2023-09-27 13:30:37.658839200 -0700
@@ -215,7 +215,7 @@
     /* DAD handling */
     if (!addr.IsAny())
     {
-        for (Ipv6InterfaceAddressListCI it = m_addresses.begin(); it != m_addresses.end(); ++it)
+        for (auto it = m_addresses.begin(); it != m_addresses.end(); ++it)
         {
             if (it->first.GetAddress() == addr)
             {
@@ -282,7 +282,7 @@
     /* IPv6 interface has always at least one IPv6 Solicited Multicast address */
     NS_LOG_FUNCTION(this << address);
 
-    for (Ipv6InterfaceAddressListCI it = m_addresses.begin(); it != m_addresses.end(); ++it)
+    for (auto it = m_addresses.begin(); it != m_addresses.end(); ++it)
     {
         if (it->second == address)
         {
@@ -301,7 +301,7 @@
 
     if (m_addresses.size() > index)
     {
-        for (Ipv6InterfaceAddressListCI it = m_addresses.begin(); it != m_addresses.end(); ++it)
+        for (auto it = m_addresses.begin(); it != m_addresses.end(); ++it)
         {
             if (i == index)
             {
@@ -336,7 +336,7 @@
         NS_FATAL_ERROR("Removing index that does not exist in Ipv6Interface::RemoveAddress");
     }
 
-    for (Ipv6InterfaceAddressListI it = m_addresses.begin(); it != m_addresses.end(); ++it)
+    for (auto it = m_addresses.begin(); it != m_addresses.end(); ++it)
     {
         if (i == index)
         {
@@ -367,7 +367,7 @@
         return Ipv6InterfaceAddress();
     }
 
-    for (Ipv6InterfaceAddressListI it = m_addresses.begin(); it != m_addresses.end(); ++it)
+    for (auto it = m_addresses.begin(); it != m_addresses.end(); ++it)
     {
         if (it->first.GetAddress() == address)
         {
@@ -388,8 +388,7 @@
 {
     NS_LOG_FUNCTION(this << dst);
 
-    for (Ipv6InterfaceAddressList::const_iterator it = m_addresses.begin(); it != m_addresses.end();
-         ++it)
+    for (auto it = m_addresses.begin(); it != m_addresses.end(); ++it)
     {
         Ipv6InterfaceAddress ifaddr = it->first;
 
@@ -431,7 +430,7 @@
     NS_ASSERT(m_tc);
 
     /* check if destination is for one of our interface */
-    for (Ipv6InterfaceAddressListCI it = m_addresses.begin(); it != m_addresses.end(); ++it)
+    for (auto it = m_addresses.begin(); it != m_addresses.end(); ++it)
     {
         if (dest == it->first.GetAddress())
         {
@@ -559,7 +558,7 @@
 {
     NS_LOG_FUNCTION(this << address << state);
 
-    for (Ipv6InterfaceAddressListI it = m_addresses.begin(); it != m_addresses.end(); ++it)
+    for (auto it = m_addresses.begin(); it != m_addresses.end(); ++it)
     {
         if (it->first.GetAddress() == address)
         {
@@ -575,7 +574,7 @@
 {
     NS_LOG_FUNCTION(this << address << uid);
 
-    for (Ipv6InterfaceAddressListI it = m_addresses.begin(); it != m_addresses.end(); ++it)
+    for (auto it = m_addresses.begin(); it != m_addresses.end(); ++it)
     {
         if (it->first.GetAddress() == address)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-l3-protocol.cc ns-3.40/src/internet/model/ipv6-l3-protocol.cc
--- ns-3.39/src/internet/model/ipv6-l3-protocol.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-l3-protocol.cc	2023-09-27 13:30:37.658839200 -0700
@@ -150,14 +150,14 @@
     NS_LOG_FUNCTION(this);
 
     /* clear protocol and interface list */
-    for (L4List_t::iterator it = m_protocols.begin(); it != m_protocols.end(); ++it)
+    for (auto it = m_protocols.begin(); it != m_protocols.end(); ++it)
     {
         it->second = nullptr;
     }
     m_protocols.clear();
 
     /* remove interfaces */
-    for (Ipv6InterfaceList::iterator it = m_interfaces.begin(); it != m_interfaces.end(); ++it)
+    for (auto it = m_interfaces.begin(); it != m_interfaces.end(); ++it)
     {
         *it = nullptr;
     }
@@ -165,14 +165,14 @@
     m_reverseInterfacesContainer.clear();
 
     /* remove raw sockets */
-    for (SocketList::iterator it = m_sockets.begin(); it != m_sockets.end(); ++it)
+    for (auto it = m_sockets.begin(); it != m_sockets.end(); ++it)
     {
         *it = nullptr;
     }
     m_sockets.clear();
 
     /* remove list of prefix */
-    for (Ipv6AutoconfiguredPrefixListI it = m_prefixes.begin(); it != m_prefixes.end(); ++it)
+    for (auto it = m_prefixes.begin(); it != m_prefixes.end(); ++it)
     {
         (*it)->StopValidTimer();
         (*it)->StopPreferredTimer();
@@ -263,8 +263,7 @@
     NS_LOG_FUNCTION(this << address);
     int32_t index = 0;
 
-    for (Ipv6InterfaceList::const_iterator it = m_interfaces.begin(); it != m_interfaces.end();
-         it++)
+    for (auto it = m_interfaces.begin(); it != m_interfaces.end(); it++)
     {
         uint32_t j = 0;
         uint32_t max = (*it)->GetNAddresses();
@@ -287,8 +286,7 @@
     NS_LOG_FUNCTION(this << address << mask);
     int32_t index = 0;
 
-    for (Ipv6InterfaceList::const_iterator it = m_interfaces.begin(); it != m_interfaces.end();
-         it++)
+    for (auto it = m_interfaces.begin(); it != m_interfaces.end(); it++)
     {
         uint32_t j = 0;
         for (j = 0; j < (*it)->GetNAddresses(); j++)
@@ -316,7 +314,7 @@
 {
     NS_LOG_FUNCTION(this << device);
 
-    Ipv6InterfaceReverseContainer::const_iterator iter = m_reverseInterfacesContainer.find(device);
+    auto iter = m_reverseInterfacesContainer.find(device);
     if (iter != m_reverseInterfacesContainer.end())
     {
         return (*iter).second;
@@ -361,7 +359,7 @@
         address.SetOnLink(onLink);
 
         /* see if we have already the prefix */
-        for (Ipv6AutoconfiguredPrefixListI it = m_prefixes.begin(); it != m_prefixes.end(); ++it)
+        for (auto it = m_prefixes.begin(); it != m_prefixes.end(); ++it)
         {
             if ((*it)->GetInterface() == interface && (*it)->GetPrefix() == network &&
                 (*it)->GetMask() == mask)
@@ -421,7 +419,7 @@
     }
 
     /* remove from list of autoconfigured address */
-    for (Ipv6AutoconfiguredPrefixListI it = m_prefixes.begin(); it != m_prefixes.end(); ++it)
+    for (auto it = m_prefixes.begin(); it != m_prefixes.end(); ++it)
     {
         if ((*it)->GetInterface() == interface && (*it)->GetPrefix() == network &&
             (*it)->GetMask() == mask)
@@ -721,8 +719,7 @@
     NS_LOG_FUNCTION(this << forward);
     m_ipForward = forward;
 
-    for (Ipv6InterfaceList::const_iterator it = m_interfaces.begin(); it != m_interfaces.end();
-         it++)
+    for (auto it = m_interfaces.begin(); it != m_interfaces.end(); it++)
     {
         (*it)->SetForwarding(forward);
     }
@@ -823,7 +820,7 @@
     NS_LOG_FUNCTION(this << protocol);
 
     L4ListKey_t key = std::make_pair(protocol->GetProtocolNumber(), -1);
-    L4List_t::iterator iter = m_protocols.find(key);
+    auto iter = m_protocols.find(key);
     if (iter == m_protocols.end())
     {
         NS_LOG_WARN("Trying to remove an non-existent default protocol "
@@ -841,7 +838,7 @@
     NS_LOG_FUNCTION(this << protocol << interfaceIndex);
 
     L4ListKey_t key = std::make_pair(protocol->GetProtocolNumber(), interfaceIndex);
-    L4List_t::iterator iter = m_protocols.find(key);
+    auto iter = m_protocols.find(key);
     if (iter == m_protocols.end())
     {
         NS_LOG_WARN("Trying to remove an non-existent protocol "
@@ -867,21 +864,19 @@
 {
     NS_LOG_FUNCTION(this << protocolNumber << interfaceIndex);
 
-    L4ListKey_t key;
-    L4List_t::const_iterator i;
     if (interfaceIndex >= 0)
     {
         // try the interface-specific protocol.
-        key = std::make_pair(protocolNumber, interfaceIndex);
-        i = m_protocols.find(key);
+        auto key = std::make_pair(protocolNumber, interfaceIndex);
+        auto i = m_protocols.find(key);
         if (i != m_protocols.end())
         {
             return i->second;
         }
     }
     // try the generic protocol.
-    key = std::make_pair(protocolNumber, -1);
-    i = m_protocols.find(key);
+    auto key = std::make_pair(protocolNumber, -1);
+    auto i = m_protocols.find(key);
     if (i != m_protocols.end())
     {
         return i->second;
@@ -905,7 +900,7 @@
 {
     NS_LOG_FUNCTION(this << socket);
 
-    for (SocketList::iterator it = m_sockets.begin(); it != m_sockets.end(); ++it)
+    for (auto it = m_sockets.begin(); it != m_sockets.end(); ++it)
     {
         if ((*it) == socket)
         {
@@ -1089,8 +1084,7 @@
             // addresses. In doubt, update all of them. Note: it's a confirmed behavior for Linux
             // routers.
             std::list<NdiscCache::Entry*> entryList = ndiscCache->LookupInverse(from);
-            std::list<NdiscCache::Entry*>::iterator iter;
-            for (iter = entryList.begin(); iter != entryList.end(); iter++)
+            for (auto iter = entryList.begin(); iter != entryList.end(); iter++)
             {
                 (*iter)->UpdateReachableTimer();
             }
@@ -1098,7 +1092,7 @@
     }
 
     /* forward up to IPv6 raw sockets */
-    for (SocketList::iterator it = m_sockets.begin(); it != m_sockets.end(); ++it)
+    for (auto it = m_sockets.begin(); it != m_sockets.end(); ++it)
     {
         Ptr<Ipv6RawSocketImpl> socket = *it;
         socket->ForwardUp(packet, hdr, device);
@@ -1301,10 +1295,7 @@
             {
                 std::ostringstream oss;
 
-                for (std::list<Ipv6ExtensionFragment::Ipv6PayloadHeaderPair>::const_iterator it =
-                         fragments.begin();
-                     it != fragments.end();
-                     it++)
+                for (auto it = fragments.begin(); it != fragments.end(); it++)
                 {
                     CallTxTrace(it->second, it->first, this, interface);
                     outInterface->Send(it->first, it->second, route->GetGateway());
@@ -1332,10 +1323,7 @@
             {
                 std::ostringstream oss;
 
-                for (std::list<Ipv6ExtensionFragment::Ipv6PayloadHeaderPair>::const_iterator it =
-                         fragments.begin();
-                     it != fragments.end();
-                     it++)
+                for (auto it = fragments.begin(); it != fragments.end(); it++)
                 {
                     CallTxTrace(it->second, it->first, this, interface);
                     outInterface->Send(it->first, it->second, ipHeader.GetDestination());
@@ -1458,9 +1446,8 @@
     NS_LOG_LOGIC("Multicast forwarding logic for node: " << m_node->GetId());
 
     std::map<uint32_t, uint32_t> ttlMap = mrtentry->GetOutputTtlMap();
-    std::map<uint32_t, uint32_t>::iterator mapIter;
 
-    for (mapIter = ttlMap.begin(); mapIter != ttlMap.end(); mapIter++)
+    for (auto mapIter = ttlMap.begin(); mapIter != ttlMap.end(); mapIter++)
     {
         uint32_t interfaceId = mapIter->first;
         // uint32_t outputTtl = mapIter->second;  // Unused for now
@@ -1788,7 +1775,7 @@
     NS_LOG_FUNCTION(address << interface);
 
     Ipv6RegisteredMulticastAddressKey_t key = std::make_pair(address, interface);
-    Ipv6RegisteredMulticastAddressCIter_t iter = m_multicastAddresses.find(key);
+    auto iter = m_multicastAddresses.find(key);
 
     return iter != m_multicastAddresses.end();
 }
@@ -1798,8 +1785,7 @@
 {
     NS_LOG_FUNCTION(address);
 
-    Ipv6RegisteredMulticastAddressNoInterfaceCIter_t iter =
-        m_multicastAddressesNoInterface.find(address);
+    auto iter = m_multicastAddressesNoInterface.find(address);
 
     return iter != m_multicastAddressesNoInterface.end();
 }
@@ -1837,9 +1823,7 @@
         // we just confirm the entry's MAC address to get the waiting packets (if any)
         std::list<NdiscCache::Ipv6PayloadHeaderPair> waiting =
             entry->MarkReachable(entry->GetMacAddress());
-        for (std::list<NdiscCache::Ipv6PayloadHeaderPair>::const_iterator it = waiting.begin();
-             it != waiting.end();
-             it++)
+        for (auto it = waiting.begin(); it != waiting.end(); it++)
         {
             ndiscCache->GetInterface()->Send(it->first, it->second, it->second.GetSource());
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-l3-protocol.h ns-3.40/src/internet/model/ipv6-l3-protocol.h
--- ns-3.39/src/internet/model/ipv6-l3-protocol.h	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-l3-protocol.h	2023-09-27 13:30:37.658839200 -0700
@@ -20,11 +20,12 @@
 #ifndef IPV6_L3_PROTOCOL_H
 #define IPV6_L3_PROTOCOL_H
 
+#include "ipv6-header.h"
+#include "ipv6-pmtu-cache.h"
+#include "ipv6-routing-protocol.h"
+#include "ipv6.h"
+
 #include "ns3/ipv6-address.h"
-#include "ns3/ipv6-header.h"
-#include "ns3/ipv6-pmtu-cache.h"
-#include "ns3/ipv6-routing-protocol.h"
-#include "ns3/ipv6.h"
 #include "ns3/net-device.h"
 #include "ns3/traced-callback.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-list-routing.cc ns-3.40/src/internet/model/ipv6-list-routing.cc
--- ns-3.39/src/internet/model/ipv6-list-routing.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-list-routing.cc	2023-09-27 13:30:37.658839200 -0700
@@ -57,8 +57,7 @@
 Ipv6ListRouting::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (Ipv6RoutingProtocolList::iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         // Note:  Calling dispose on these protocols causes memory leak
@@ -79,9 +78,7 @@
     NS_LOG_FUNCTION(this << header.GetDestination() << header.GetSource() << oif);
     Ptr<Ipv6Route> route;
 
-    for (Ipv6RoutingProtocolList::const_iterator i = m_routingProtocols.begin();
-         i != m_routingProtocols.end();
-         i++)
+    for (auto i = m_routingProtocols.begin(); i != m_routingProtocols.end(); i++)
     {
         NS_LOG_LOGIC("Checking protocol " << (*i).second->GetInstanceTypeId() << " with priority "
                                           << (*i).first);
@@ -131,8 +128,7 @@
     ErrorCallback nullEcb =
         MakeNullCallback<void, Ptr<const Packet>, const Ipv6Header&, Socket::SocketErrno>();
 
-    for (Ipv6RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         if ((*rprotoIter).second->RouteInput(p, header, idev, ucb, mcb, lcb, nullEcb))
@@ -150,8 +146,7 @@
 Ipv6ListRouting::NotifyInterfaceUp(uint32_t interface)
 {
     NS_LOG_FUNCTION(this << interface);
-    for (Ipv6RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->NotifyInterfaceUp(interface);
@@ -162,8 +157,7 @@
 Ipv6ListRouting::NotifyInterfaceDown(uint32_t interface)
 {
     NS_LOG_FUNCTION(this << interface);
-    for (Ipv6RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->NotifyInterfaceDown(interface);
@@ -174,8 +168,7 @@
 Ipv6ListRouting::NotifyAddAddress(uint32_t interface, Ipv6InterfaceAddress address)
 {
     NS_LOG_FUNCTION(this << interface << address);
-    for (Ipv6RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->NotifyAddAddress(interface, address);
@@ -186,8 +179,7 @@
 Ipv6ListRouting::NotifyRemoveAddress(uint32_t interface, Ipv6InterfaceAddress address)
 {
     NS_LOG_FUNCTION(this << interface << address);
-    for (Ipv6RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->NotifyRemoveAddress(interface, address);
@@ -202,8 +194,7 @@
                                 Ipv6Address prefixToUse)
 {
     NS_LOG_FUNCTION(this << dst << mask << nextHop << interface);
-    for (Ipv6RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->NotifyAddRoute(dst, mask, nextHop, interface, prefixToUse);
@@ -218,8 +209,7 @@
                                    Ipv6Address prefixToUse)
 {
     NS_LOG_FUNCTION(this << dst << mask << nextHop << interface);
-    for (Ipv6RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->NotifyRemoveRoute(dst, mask, nextHop, interface, prefixToUse);
@@ -235,9 +225,7 @@
                          << ", Time: " << Now().As(unit)
                          << ", Local time: " << m_ipv6->GetObject<Node>()->GetLocalTime().As(unit)
                          << ", Ipv6ListRouting table" << std::endl;
-    for (Ipv6RoutingProtocolList::const_iterator i = m_routingProtocols.begin();
-         i != m_routingProtocols.end();
-         i++)
+    for (auto i = m_routingProtocols.begin(); i != m_routingProtocols.end(); i++)
     {
         *stream->GetStream() << "  Priority: " << (*i).first
                              << " Protocol: " << (*i).second->GetInstanceTypeId() << std::endl;
@@ -250,8 +238,7 @@
 {
     NS_LOG_FUNCTION(this << ipv6);
     NS_ASSERT(!m_ipv6);
-    for (Ipv6RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++)
     {
         (*rprotoIter).second->SetIpv6(ipv6);
@@ -288,8 +275,7 @@
                                                                          << " out of range");
     }
     uint32_t i = 0;
-    for (Ipv6RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin();
-         rprotoIter != m_routingProtocols.end();
+    for (auto rprotoIter = m_routingProtocols.begin(); rprotoIter != m_routingProtocols.end();
          rprotoIter++, i++)
     {
         if (i == index)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-list-routing.h ns-3.40/src/internet/model/ipv6-list-routing.h
--- ns-3.39/src/internet/model/ipv6-list-routing.h	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-list-routing.h	2023-09-27 13:30:37.658839200 -0700
@@ -18,7 +18,7 @@
 #ifndef IPV6_LIST_ROUTING_H
 #define IPV6_LIST_ROUTING_H
 
-#include "ns3/ipv6-routing-protocol.h"
+#include "ipv6-routing-protocol.h"
 
 #include <list>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-option-demux.cc ns-3.40/src/internet/model/ipv6-option-demux.cc
--- ns-3.39/src/internet/model/ipv6-option-demux.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-option-demux.cc	2023-09-27 13:30:37.658839200 -0700
@@ -57,7 +57,7 @@
 void
 Ipv6OptionDemux::DoDispose()
 {
-    for (Ipv6OptionList_t::iterator it = m_options.begin(); it != m_options.end(); it++)
+    for (auto it = m_options.begin(); it != m_options.end(); it++)
     {
         (*it)->Dispose();
         *it = nullptr;
@@ -82,7 +82,7 @@
 Ptr<Ipv6Option>
 Ipv6OptionDemux::GetOption(int optionNumber)
 {
-    for (Ipv6OptionList_t::iterator i = m_options.begin(); i != m_options.end(); ++i)
+    for (auto i = m_options.begin(); i != m_options.end(); ++i)
     {
         if ((*i)->GetOptionNumber() == optionNumber)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-option.h ns-3.40/src/internet/model/ipv6-option.h
--- ns-3.39/src/internet/model/ipv6-option.h	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-option.h	2023-09-27 13:30:37.658839200 -0700
@@ -20,11 +20,11 @@
 #ifndef IPV6_OPTION_H
 #define IPV6_OPTION_H
 
+#include "ipv6-header.h"
 #include "ipv6-interface.h"
 
 #include "ns3/buffer.h"
 #include "ns3/ipv6-address.h"
-#include "ns3/ipv6-header.h"
 #include "ns3/node.h"
 #include "ns3/object.h"
 #include "ns3/packet.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-packet-probe.h ns-3.40/src/internet/model/ipv6-packet-probe.h
--- ns-3.39/src/internet/model/ipv6-packet-probe.h	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-packet-probe.h	2023-09-27 13:30:37.658839200 -0700
@@ -24,9 +24,10 @@
 #ifndef IPV6_PACKET_PROBE_H
 #define IPV6_PACKET_PROBE_H
 
+#include "ipv6.h"
+
 #include "ns3/boolean.h"
 #include "ns3/callback.h"
-#include "ns3/ipv6.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
 #include "ns3/packet.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-pmtu-cache.cc ns-3.40/src/internet/model/ipv6-pmtu-cache.cc
--- ns-3.39/src/internet/model/ipv6-pmtu-cache.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-pmtu-cache.cc	2023-09-27 13:30:37.658839200 -0700
@@ -56,7 +56,7 @@
 void
 Ipv6PmtuCache::DoDispose()
 {
-    for (pathMtuTimerIter iter = m_pathMtuTimer.begin(); iter != m_pathMtuTimer.end(); iter++)
+    for (auto iter = m_pathMtuTimer.begin(); iter != m_pathMtuTimer.end(); iter++)
     {
         iter->second.Cancel();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-raw-socket-factory-impl.h ns-3.40/src/internet/model/ipv6-raw-socket-factory-impl.h
--- ns-3.39/src/internet/model/ipv6-raw-socket-factory-impl.h	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-raw-socket-factory-impl.h	2023-09-27 13:30:37.658839200 -0700
@@ -20,7 +20,7 @@
 #ifndef IPV6_RAW_SOCKET_FACTORY_IMPL_H
 #define IPV6_RAW_SOCKET_FACTORY_IMPL_H
 
-#include "ns3/ipv6-raw-socket-factory.h"
+#include "ipv6-raw-socket-factory.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-raw-socket-impl.cc ns-3.40/src/internet/model/ipv6-raw-socket-impl.cc
--- ns-3.39/src/internet/model/ipv6-raw-socket-impl.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-raw-socket-impl.cc	2023-09-27 13:30:37.658839200 -0700
@@ -293,7 +293,7 @@
                 p->CopyData(&type, sizeof(type));
                 if (type == Icmpv6Header::ICMPV6_ECHO_REQUEST)
                 {
-                    Icmpv6Echo hdr(1);
+                    Icmpv6Echo hdr(true);
                     p->RemoveHeader(hdr);
                     hdr.CalculatePseudoHeaderChecksum(route->GetSource(),
                                                       dst,
@@ -421,7 +421,7 @@
     NS_LOG_FUNCTION(this);
     uint32_t rx = 0;
 
-    for (std::list<Data>::const_iterator it = m_data.begin(); it != m_data.end(); ++it)
+    for (auto it = m_data.begin(); it != m_data.end(); ++it)
     {
         rx += (it->packet)->GetSize();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-raw-socket-impl.h ns-3.40/src/internet/model/ipv6-raw-socket-impl.h
--- ns-3.39/src/internet/model/ipv6-raw-socket-impl.h	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-raw-socket-impl.h	2023-09-27 13:30:37.658839200 -0700
@@ -20,8 +20,9 @@
 #ifndef IPV6_RAW_SOCKET_IMPL_H
 #define IPV6_RAW_SOCKET_IMPL_H
 
+#include "ipv6-header.h"
+
 #include "ns3/ipv6-address.h"
-#include "ns3/ipv6-header.h"
 #include "ns3/socket.h"
 
 #include <list>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-route.cc ns-3.40/src/internet/model/ipv6-route.cc
--- ns-3.39/src/internet/model/ipv6-route.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-route.cc	2023-09-27 13:30:37.658839200 -0700
@@ -141,8 +141,7 @@
     if (ttl >= MAX_TTL)
     {
         // This TTL value effectively disables the interface
-        std::map<uint32_t, uint32_t>::iterator iter;
-        iter = m_ttls.find(oif);
+        auto iter = m_ttls.find(oif);
         if (iter != m_ttls.end())
         {
             m_ttls.erase(iter);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-static-routing.cc ns-3.40/src/internet/model/ipv6-static-routing.cc
--- ns-3.39/src/internet/model/ipv6-static-routing.cc	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-static-routing.cc	2023-09-27 13:30:37.658839200 -0700
@@ -181,7 +181,7 @@
 
     if (!LookupRoute(route, metric))
     {
-        Ipv6RoutingTableEntry* routePtr = new Ipv6RoutingTableEntry(route);
+        auto routePtr = new Ipv6RoutingTableEntry(route);
         m_networkRoutes.emplace_back(routePtr, metric);
     }
 }
@@ -208,7 +208,7 @@
                                                                               prefixToUse);
     if (!LookupRoute(route, metric))
     {
-        Ipv6RoutingTableEntry* routePtr = new Ipv6RoutingTableEntry(route);
+        auto routePtr = new Ipv6RoutingTableEntry(route);
         m_networkRoutes.emplace_back(routePtr, metric);
     }
 }
@@ -225,7 +225,7 @@
         Ipv6RoutingTableEntry::CreateNetworkRouteTo(network, networkPrefix, interface);
     if (!LookupRoute(route, metric))
     {
-        Ipv6RoutingTableEntry* routePtr = new Ipv6RoutingTableEntry(route);
+        auto routePtr = new Ipv6RoutingTableEntry(route);
         m_networkRoutes.emplace_back(routePtr, metric);
     }
 }
@@ -252,7 +252,7 @@
                                      std::vector<uint32_t> outputInterfaces)
 {
     NS_LOG_FUNCTION(this << origin << group << inputInterface);
-    Ipv6MulticastRoutingTableEntry* route = new Ipv6MulticastRoutingTableEntry();
+    auto route = new Ipv6MulticastRoutingTableEntry();
     *route = Ipv6MulticastRoutingTableEntry::CreateMulticastRoute(origin,
                                                                   group,
                                                                   inputInterface,
@@ -264,7 +264,7 @@
 Ipv6StaticRouting::SetDefaultMulticastRoute(uint32_t outputInterface)
 {
     NS_LOG_FUNCTION(this << outputInterface);
-    Ipv6RoutingTableEntry* route = new Ipv6RoutingTableEntry();
+    auto route = new Ipv6RoutingTableEntry();
     Ipv6Address network = Ipv6Address("ff00::"); /* RFC 3513 */
     Ipv6Prefix networkMask = Ipv6Prefix(8);
     *route = Ipv6RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, outputInterface);
@@ -288,7 +288,7 @@
     if (index < m_multicastRoutes.size())
     {
         uint32_t tmp = 0;
-        for (MulticastRoutesCI i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
+        for (auto i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
         {
             if (tmp == index)
             {
@@ -306,7 +306,7 @@
                                         uint32_t inputInterface)
 {
     NS_LOG_FUNCTION(this << origin << group << inputInterface);
-    for (MulticastRoutesI i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
+    for (auto i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
     {
         Ipv6MulticastRoutingTableEntry* route = *i;
         if (origin == route->GetOrigin() && group == route->GetGroup() &&
@@ -326,7 +326,7 @@
     NS_LOG_FUNCTION(this << index);
     uint32_t tmp = 0;
 
-    for (MulticastRoutesI i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
+    for (auto i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
     {
         if (tmp == index)
         {
@@ -344,7 +344,7 @@
     NS_LOG_FUNCTION(this << network << interfaceIndex);
 
     /* in the network table */
-    for (NetworkRoutesI j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
+    for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
     {
         Ipv6RoutingTableEntry* rtentry = j->first;
         Ipv6Prefix prefix = rtentry->GetDestNetworkPrefix();
@@ -363,7 +363,7 @@
 bool
 Ipv6StaticRouting::LookupRoute(const Ipv6RoutingTableEntry& route, uint32_t metric)
 {
-    for (NetworkRoutesI j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
+    for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
     {
         Ipv6RoutingTableEntry* rtentry = j->first;
 
@@ -402,7 +402,7 @@
         return rtentry;
     }
 
-    for (NetworkRoutesI it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
+    for (auto it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
     {
         Ipv6RoutingTableEntry* j = it->first;
         uint32_t metric = it->second;
@@ -485,14 +485,13 @@
 {
     NS_LOG_FUNCTION(this);
 
-    for (NetworkRoutesI j = m_networkRoutes.begin(); j != m_networkRoutes.end();
-         j = m_networkRoutes.erase(j))
+    for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j = m_networkRoutes.erase(j))
     {
         delete j->first;
     }
     m_networkRoutes.clear();
 
-    for (MulticastRoutesI i = m_multicastRoutes.begin(); i != m_multicastRoutes.end();
+    for (auto i = m_multicastRoutes.begin(); i != m_multicastRoutes.end();
          i = m_multicastRoutes.erase(i))
     {
         delete (*i);
@@ -509,7 +508,7 @@
     NS_LOG_FUNCTION(this << origin << group << interface);
     Ptr<Ipv6MulticastRoute> mrtentry = nullptr;
 
-    for (MulticastRoutesI i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
+    for (auto i = m_multicastRoutes.begin(); i != m_multicastRoutes.end(); i++)
     {
         Ipv6MulticastRoutingTableEntry* route = *i;
 
@@ -569,7 +568,7 @@
     uint32_t shortestMetric = 0xffffffff;
     Ipv6RoutingTableEntry* result = nullptr;
 
-    for (NetworkRoutesI it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
+    for (auto it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
     {
         Ipv6RoutingTableEntry* j = it->first;
         uint32_t metric = it->second;
@@ -606,7 +605,7 @@
     NS_LOG_FUNCTION(this << index);
     uint32_t tmp = 0;
 
-    for (NetworkRoutesCI it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
+    for (auto it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
     {
         if (tmp == index)
         {
@@ -625,7 +624,7 @@
     NS_LOG_FUNCTION(this << index);
     uint32_t tmp = 0;
 
-    for (NetworkRoutesCI it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
+    for (auto it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
     {
         if (tmp == index)
         {
@@ -644,7 +643,7 @@
     NS_LOG_FUNCTION(this << index);
     uint32_t tmp = 0;
 
-    for (NetworkRoutesI it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
+    for (auto it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
     {
         if (tmp == index)
         {
@@ -665,7 +664,7 @@
 {
     NS_LOG_FUNCTION(this << network << prefix << ifIndex);
 
-    for (NetworkRoutesI it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
+    for (auto it = m_networkRoutes.begin(); it != m_networkRoutes.end(); it++)
     {
         Ipv6RoutingTableEntry* rtentry = it->first;
         if (network == rtentry->GetDest() && rtentry->GetInterface() == ifIndex &&
@@ -809,7 +808,7 @@
     NS_LOG_FUNCTION(this << i);
 
     /* remove all static routes that are going through this interface */
-    for (NetworkRoutesI it = m_networkRoutes.begin(); it != m_networkRoutes.end();)
+    for (auto it = m_networkRoutes.begin(); it != m_networkRoutes.end();)
     {
         if (it->first->GetInterface() == i)
         {
@@ -845,7 +844,7 @@
 
     // Remove all static routes that are going through this interface
     // which reference this network
-    for (NetworkRoutesI it = m_networkRoutes.begin(); it != m_networkRoutes.end();)
+    for (auto it = m_networkRoutes.begin(); it != m_networkRoutes.end();)
     {
         if (it->first->GetInterface() == interface && it->first->IsNetwork() &&
             it->first->GetDestNetwork() == networkAddress &&
@@ -868,7 +867,7 @@
                                   uint32_t interface,
                                   Ipv6Address prefixToUse)
 {
-    NS_LOG_INFO(this << dst << mask << nextHop << interface << prefixToUse);
+    NS_LOG_FUNCTION(this << dst << mask << nextHop << interface << prefixToUse);
     if (nextHop == Ipv6Address::GetZero())
     {
         AddNetworkRouteTo(dst, mask, interface);
@@ -901,7 +900,7 @@
     NS_LOG_FUNCTION(this << dst << mask << nextHop << interface);
     if (dst != Ipv6Address::GetZero())
     {
-        for (NetworkRoutesI j = m_networkRoutes.begin(); j != m_networkRoutes.end();)
+        for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end();)
         {
             Ipv6RoutingTableEntry* rtentry = j->first;
             Ipv6Prefix prefix = rtentry->GetDestNetworkPrefix();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ipv6-static-routing.h ns-3.40/src/internet/model/ipv6-static-routing.h
--- ns-3.39/src/internet/model/ipv6-static-routing.h	2023-07-05 14:23:47.853427400 -0700
+++ ns-3.40/src/internet/model/ipv6-static-routing.h	2023-09-27 13:30:37.658839200 -0700
@@ -20,10 +20,11 @@
 #ifndef IPV6_STATIC_ROUTING_H
 #define IPV6_STATIC_ROUTING_H
 
+#include "ipv6-header.h"
+#include "ipv6-routing-protocol.h"
+#include "ipv6.h"
+
 #include "ns3/ipv6-address.h"
-#include "ns3/ipv6-header.h"
-#include "ns3/ipv6-routing-protocol.h"
-#include "ns3/ipv6.h"
 #include "ns3/ptr.h"
 
 #include <list>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ndisc-cache.cc ns-3.40/src/internet/model/ndisc-cache.cc
--- ns-3.39/src/internet/model/ndisc-cache.cc	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/ndisc-cache.cc	2023-09-27 13:30:37.662839200 -0700
@@ -118,7 +118,7 @@
     NS_LOG_FUNCTION(this << dst);
 
     std::list<NdiscCache::Entry*> entryList;
-    for (CacheI i = m_ndCache.begin(); i != m_ndCache.end(); i++)
+    for (auto i = m_ndCache.begin(); i != m_ndCache.end(); i++)
     {
         NdiscCache::Entry* entry = (*i).second;
         if (entry->GetMacAddress() == dst)
@@ -136,7 +136,7 @@
     NS_LOG_FUNCTION(this << to);
     NS_ASSERT(m_ndCache.find(to) == m_ndCache.end());
 
-    NdiscCache::Entry* entry = new NdiscCache::Entry(this);
+    auto entry = new NdiscCache::Entry(this);
     entry->SetIpv6Address(to);
     m_ndCache[to] = entry;
     return entry;
@@ -147,7 +147,7 @@
 {
     NS_LOG_FUNCTION(this << entry);
 
-    for (CacheI i = m_ndCache.begin(); i != m_ndCache.end(); i++)
+    for (auto i = m_ndCache.begin(); i != m_ndCache.end(); i++)
     {
         if ((*i).second == entry)
         {
@@ -164,7 +164,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    for (CacheI i = m_ndCache.begin(); i != m_ndCache.end(); i++)
+    for (auto i = m_ndCache.begin(); i != m_ndCache.end(); i++)
     {
         delete (*i).second; /* delete the pointer NdiscCache::Entry */
     }
@@ -192,7 +192,7 @@
     NS_LOG_FUNCTION(this << stream);
     std::ostream* os = stream->GetStream();
 
-    for (CacheI i = m_ndCache.begin(); i != m_ndCache.end(); i++)
+    for (auto i = m_ndCache.begin(); i != m_ndCache.end(); i++)
     {
         *os << i->first << " dev ";
         std::string found = Names::FindName(m_device);
@@ -717,7 +717,7 @@
 NdiscCache::RemoveAutoGeneratedEntries()
 {
     NS_LOG_FUNCTION(this);
-    for (CacheI i = m_ndCache.begin(); i != m_ndCache.end();)
+    for (auto i = m_ndCache.begin(); i != m_ndCache.end();)
     {
         if (i->second->IsAutoGenerated())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/rip.cc ns-3.40/src/internet/model/rip.cc
--- ns-3.39/src/internet/model/rip.cc	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/rip.cc	2023-09-27 13:30:37.662839200 -0700
@@ -346,7 +346,7 @@
     }
 
     bool sendSocketFound = false;
-    for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
+    for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
     {
         if (iter->second == i)
         {
@@ -406,7 +406,7 @@
     NS_LOG_FUNCTION(this << interface);
 
     /* remove all routes that are going through this interface */
-    for (RoutesI it = m_routes.begin(); it != m_routes.end(); it++)
+    for (auto it = m_routes.begin(); it != m_routes.end(); it++)
     {
         if (it->first->GetInterface() == interface)
         {
@@ -414,7 +414,7 @@
         }
     }
 
-    for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
+    for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
     {
         NS_LOG_INFO("Checking socket for interface " << interface);
         if (iter->second == interface)
@@ -478,7 +478,7 @@
 
     // Remove all routes that are going through this interface
     // which reference this network
-    for (RoutesI it = m_routes.begin(); it != m_routes.end(); it++)
+    for (auto it = m_routes.begin(); it != m_routes.end(); it++)
     {
         if (it->first->GetInterface() == interface && it->first->IsNetwork() &&
             it->first->GetDestNetwork() == networkAddress &&
@@ -536,7 +536,7 @@
     {
         *os << "Destination     Gateway         Genmask         Flags Metric Ref    Use Iface"
             << std::endl;
-        for (RoutesCI it = m_routes.begin(); it != m_routes.end(); it++)
+        for (auto it = m_routes.begin(); it != m_routes.end(); it++)
         {
             RipRoutingTableEntry* route = it->first;
             RipRoutingTableEntry::Status_e status = route->GetRouteStatus();
@@ -592,7 +592,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    for (RoutesI j = m_routes.begin(); j != m_routes.end(); j = m_routes.erase(j))
+    for (auto j = m_routes.begin(); j != m_routes.end(); j = m_routes.erase(j))
     {
         delete j->first;
     }
@@ -603,7 +603,7 @@
     m_nextTriggeredUpdate = EventId();
     m_nextUnsolicitedUpdate = EventId();
 
-    for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
+    for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
     {
         iter->first->Close();
     }
@@ -639,7 +639,7 @@
         return rtentry;
     }
 
-    for (RoutesI it = m_routes.begin(); it != m_routes.end(); it++)
+    for (auto it = m_routes.begin(); it != m_routes.end(); it++)
     {
         RipRoutingTableEntry* j = it->first;
 
@@ -708,8 +708,7 @@
 {
     NS_LOG_FUNCTION(this << network << networkPrefix << nextHop << interface);
 
-    RipRoutingTableEntry* route =
-        new RipRoutingTableEntry(network, networkPrefix, nextHop, interface);
+    auto route = new RipRoutingTableEntry(network, networkPrefix, nextHop, interface);
     route->SetRouteMetric(1);
     route->SetRouteStatus(RipRoutingTableEntry::RIP_VALID);
     route->SetRouteChanged(true);
@@ -722,7 +721,7 @@
 {
     NS_LOG_FUNCTION(this << network << networkPrefix << interface);
 
-    RipRoutingTableEntry* route = new RipRoutingTableEntry(network, networkPrefix, interface);
+    auto route = new RipRoutingTableEntry(network, networkPrefix, interface);
     route->SetRouteMetric(1);
     route->SetRouteStatus(RipRoutingTableEntry::RIP_VALID);
     route->SetRouteChanged(true);
@@ -735,7 +734,7 @@
 {
     NS_LOG_FUNCTION(this << *route);
 
-    for (RoutesI it = m_routes.begin(); it != m_routes.end(); it++)
+    for (auto it = m_routes.begin(); it != m_routes.end(); it++)
     {
         if (it->first == route)
         {
@@ -759,7 +758,7 @@
 {
     NS_LOG_FUNCTION(this << *route);
 
-    for (RoutesI it = m_routes.begin(); it != m_routes.end(); it++)
+    for (auto it = m_routes.begin(); it != m_routes.end(); it++)
     {
         if (it->first == route)
         {
@@ -869,8 +868,7 @@
                 // we use one of the sending sockets, as they're bound to the right interface
                 // and the local address might be used on different interfaces.
                 Ptr<Socket> sendingSocket;
-                for (SocketListI iter = m_unicastSocketList.begin();
-                     iter != m_unicastSocketList.end();
+                for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end();
                      iter++)
                 {
                     if (iter->second == incomingInterface)
@@ -903,7 +901,7 @@
                 RipHeader hdr;
                 hdr.SetCommand(RipHeader::RESPONSE);
 
-                for (RoutesI rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
+                for (auto rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
                 {
                     bool splitHorizoning = (rtIter->first->GetInterface() == incomingInterface);
 
@@ -976,10 +974,10 @@
         RipHeader hdr;
         hdr.SetCommand(RipHeader::RESPONSE);
 
-        for (std::list<RipRte>::iterator iter = rtes.begin(); iter != rtes.end(); iter++)
+        for (auto iter = rtes.begin(); iter != rtes.end(); iter++)
         {
             bool found = false;
-            for (RoutesI rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
+            for (auto rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
             {
                 Ipv4InterfaceAddress rtDestAddr =
                     Ipv4InterfaceAddress(rtIter->first->GetDestNetwork(),
@@ -1033,7 +1031,7 @@
     std::list<RipRte> rtes = hdr.GetRteList();
 
     // validate the RTEs before processing
-    for (std::list<RipRte>::iterator iter = rtes.begin(); iter != rtes.end(); iter++)
+    for (auto iter = rtes.begin(); iter != rtes.end(); iter++)
     {
         if (iter->GetRouteMetric() == 0 || iter->GetRouteMetric() > m_linkDown)
         {
@@ -1051,7 +1049,7 @@
 
     bool changed = false;
 
-    for (std::list<RipRte>::iterator iter = rtes.begin(); iter != rtes.end(); iter++)
+    for (auto iter = rtes.begin(); iter != rtes.end(); iter++)
     {
         Ipv4Mask rtePrefixMask = iter->GetSubnetMask();
         Ipv4Address rteAddr = iter->GetPrefix().CombineMask(rtePrefixMask);
@@ -1081,10 +1079,10 @@
                 {
                     if (senderAddress != it->first->GetGateway())
                     {
-                        RipRoutingTableEntry* route = new RipRoutingTableEntry(rteAddr,
-                                                                               rtePrefixMask,
-                                                                               senderAddress,
-                                                                               incomingInterface);
+                        auto route = new RipRoutingTableEntry(rteAddr,
+                                                              rtePrefixMask,
+                                                              senderAddress,
+                                                              incomingInterface);
                         delete it->first;
                         it->first = route;
                     }
@@ -1111,11 +1109,10 @@
                     {
                         if (Simulator::GetDelayLeft(it->second) < m_timeoutDelay / 2)
                         {
-                            RipRoutingTableEntry* route =
-                                new RipRoutingTableEntry(rteAddr,
-                                                         rtePrefixMask,
-                                                         senderAddress,
-                                                         incomingInterface);
+                            auto route = new RipRoutingTableEntry(rteAddr,
+                                                                  rtePrefixMask,
+                                                                  senderAddress,
+                                                                  incomingInterface);
                             route->SetRouteMetric(rteMetric);
                             route->SetRouteStatus(RipRoutingTableEntry::RIP_VALID);
                             route->SetRouteTag(iter->GetRouteTag());
@@ -1159,7 +1156,7 @@
         {
             NS_LOG_LOGIC("Received a RTE with new route, adding.");
 
-            RipRoutingTableEntry* route =
+            auto route =
                 new RipRoutingTableEntry(rteAddr, rtePrefixMask, senderAddress, incomingInterface);
             route->SetRouteMetric(rteMetric);
             route->SetRouteStatus(RipRoutingTableEntry::RIP_VALID);
@@ -1183,7 +1180,7 @@
 {
     NS_LOG_FUNCTION(this << (periodic ? " periodic" : " triggered"));
 
-    for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
+    for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
     {
         uint32_t interface = iter->second;
 
@@ -1202,7 +1199,7 @@
             RipHeader hdr;
             hdr.SetCommand(RipHeader::RESPONSE);
 
-            for (RoutesI rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
+            for (auto rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
             {
                 bool splitHorizoning = (rtIter->first->GetInterface() == interface);
                 Ipv4InterfaceAddress rtDestAddr =
@@ -1270,7 +1267,7 @@
             }
         }
     }
-    for (RoutesI rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
+    for (auto rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
     {
         rtIter->first->SetRouteChanged(false);
     }
@@ -1344,7 +1341,7 @@
 {
     NS_LOG_FUNCTION(this << interface);
 
-    std::map<uint32_t, uint8_t>::const_iterator iter = m_interfaceMetrics.find(interface);
+    auto iter = m_interfaceMetrics.find(interface);
     if (iter != m_interfaceMetrics.end())
     {
         return iter->second;
@@ -1385,7 +1382,7 @@
     hdr.AddRte(rte);
     p->AddHeader(hdr);
 
-    for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
+    for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
     {
         uint32_t interface = iter->second;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/rip.h ns-3.40/src/internet/model/rip.h
--- ns-3.39/src/internet/model/rip.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/rip.h	2023-09-27 13:30:37.662839200 -0700
@@ -20,13 +20,14 @@
 #ifndef RIP_H
 #define RIP_H
 
+#include "ipv4-interface.h"
+#include "ipv4-l3-protocol.h"
+#include "ipv4-routing-protocol.h"
+#include "ipv4-routing-table-entry.h"
+#include "rip-header.h"
+
 #include "ns3/inet-socket-address.h"
-#include "ns3/ipv4-interface.h"
-#include "ns3/ipv4-l3-protocol.h"
-#include "ns3/ipv4-routing-protocol.h"
-#include "ns3/ipv4-routing-table-entry.h"
 #include "ns3/random-variable-stream.h"
-#include "ns3/rip-header.h"
 
 #include <list>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/rip-header.cc ns-3.40/src/internet/model/rip-header.cc
--- ns-3.39/src/internet/model/rip-header.cc	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/rip-header.cc	2023-09-27 13:30:37.662839200 -0700
@@ -197,8 +197,7 @@
 RipHeader::Print(std::ostream& os) const
 {
     os << "command " << int(m_command);
-    for (std::list<RipRte>::const_iterator iter = m_rteList.begin(); iter != m_rteList.end();
-         iter++)
+    for (auto iter = m_rteList.begin(); iter != m_rteList.end(); iter++)
     {
         os << " | ";
         iter->Print(os);
@@ -221,8 +220,7 @@
     i.WriteU8(2);
     i.WriteU16(0);
 
-    for (std::list<RipRte>::const_iterator iter = m_rteList.begin(); iter != m_rteList.end();
-         iter++)
+    for (auto iter = m_rteList.begin(); iter != m_rteList.end(); iter++)
     {
         iter->Serialize(i);
         i.Next(iter->GetSerializedSize());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/rip-header.h ns-3.40/src/internet/model/rip-header.h
--- ns-3.39/src/internet/model/rip-header.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/rip-header.h	2023-09-27 13:30:37.662839200 -0700
@@ -20,9 +20,10 @@
 #ifndef RIP_HEADER_H
 #define RIP_HEADER_H
 
+#include "ipv4-header.h"
+
 #include "ns3/header.h"
 #include "ns3/ipv4-address.h"
-#include "ns3/ipv4-header.h"
 #include "ns3/packet.h"
 
 #include <list>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ripng.cc ns-3.40/src/internet/model/ripng.cc
--- ns-3.39/src/internet/model/ripng.cc	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/ripng.cc	2023-09-27 13:30:37.662839200 -0700
@@ -313,7 +313,7 @@
     }
 
     bool sendSocketFound = false;
-    for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
+    for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
     {
         if (iter->second == i)
         {
@@ -374,7 +374,7 @@
     NS_LOG_FUNCTION(this << interface);
 
     /* remove all routes that are going through this interface */
-    for (RoutesI it = m_routes.begin(); it != m_routes.end(); it++)
+    for (auto it = m_routes.begin(); it != m_routes.end(); it++)
     {
         if (it->first->GetInterface() == interface)
         {
@@ -382,7 +382,7 @@
         }
     }
 
-    for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
+    for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
     {
         NS_LOG_INFO("Checking socket for interface " << interface);
         if (iter->second == interface)
@@ -446,7 +446,7 @@
 
     // Remove all routes that are going through this interface
     // which reference this network
-    for (RoutesI it = m_routes.begin(); it != m_routes.end(); it++)
+    for (auto it = m_routes.begin(); it != m_routes.end(); it++)
     {
         if (it->first->GetInterface() == interface && it->first->IsNetwork() &&
             it->first->GetDestNetwork() == networkAddress &&
@@ -522,7 +522,7 @@
     {
         *os << "Destination                    Next Hop                   Flag Met Ref Use If"
             << std::endl;
-        for (RoutesCI it = m_routes.begin(); it != m_routes.end(); it++)
+        for (auto it = m_routes.begin(); it != m_routes.end(); it++)
         {
             RipNgRoutingTableEntry* route = it->first;
             RipNgRoutingTableEntry::Status_e status = route->GetRouteStatus();
@@ -576,7 +576,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    for (RoutesI j = m_routes.begin(); j != m_routes.end(); j = m_routes.erase(j))
+    for (auto j = m_routes.begin(); j != m_routes.end(); j = m_routes.erase(j))
     {
         delete j->first;
     }
@@ -587,7 +587,7 @@
     m_nextTriggeredUpdate = EventId();
     m_nextUnsolicitedUpdate = EventId();
 
-    for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
+    for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
     {
         iter->first->Close();
     }
@@ -624,7 +624,7 @@
         return rtentry;
     }
 
-    for (RoutesI it = m_routes.begin(); it != m_routes.end(); it++)
+    for (auto it = m_routes.begin(); it != m_routes.end(); it++)
     {
         RipNgRoutingTableEntry* j = it->first;
 
@@ -705,7 +705,7 @@
         NS_LOG_WARN("Ripng::AddNetworkRouteTo - Next hop should be link-local");
     }
 
-    RipNgRoutingTableEntry* route =
+    auto route =
         new RipNgRoutingTableEntry(network, networkPrefix, nextHop, interface, prefixToUse);
     route->SetRouteMetric(1);
     route->SetRouteStatus(RipNgRoutingTableEntry::RIPNG_VALID);
@@ -719,7 +719,7 @@
 {
     NS_LOG_FUNCTION(this << network << networkPrefix << interface);
 
-    RipNgRoutingTableEntry* route = new RipNgRoutingTableEntry(network, networkPrefix, interface);
+    auto route = new RipNgRoutingTableEntry(network, networkPrefix, interface);
     route->SetRouteMetric(1);
     route->SetRouteStatus(RipNgRoutingTableEntry::RIPNG_VALID);
     route->SetRouteChanged(true);
@@ -732,7 +732,7 @@
 {
     NS_LOG_FUNCTION(this << *route);
 
-    for (RoutesI it = m_routes.begin(); it != m_routes.end(); it++)
+    for (auto it = m_routes.begin(); it != m_routes.end(); it++)
     {
         if (it->first == route)
         {
@@ -756,7 +756,7 @@
 {
     NS_LOG_FUNCTION(this << *route);
 
-    for (RoutesI it = m_routes.begin(); it != m_routes.end(); it++)
+    for (auto it = m_routes.begin(); it != m_routes.end(); it++)
     {
         if (it->first == route)
         {
@@ -851,8 +851,7 @@
                 // we use one of the sending sockets, as they're bound to the right interface
                 // and the local address might be used on different interfaces.
                 Ptr<Socket> sendingSocket;
-                for (SocketListI iter = m_unicastSocketList.begin();
-                     iter != m_unicastSocketList.end();
+                for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end();
                      iter++)
                 {
                     if (iter->second == incomingInterface)
@@ -878,7 +877,7 @@
                 RipNgHeader hdr;
                 hdr.SetCommand(RipNgHeader::RESPONSE);
 
-                for (RoutesI rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
+                for (auto rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
                 {
                     bool splitHorizoning = (rtIter->first->GetInterface() == incomingInterface);
 
@@ -940,8 +939,7 @@
         Ptr<Socket> sendingSocket;
         if (senderAddress.IsLinkLocal())
         {
-            for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end();
-                 iter++)
+            for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
             {
                 if (iter->second == incomingInterface)
                 {
@@ -963,10 +961,10 @@
         RipNgHeader hdr;
         hdr.SetCommand(RipNgHeader::RESPONSE);
 
-        for (std::list<RipNgRte>::iterator iter = rtes.begin(); iter != rtes.end(); iter++)
+        for (auto iter = rtes.begin(); iter != rtes.end(); iter++)
         {
             bool found = false;
-            for (RoutesI rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
+            for (auto rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
             {
                 Ipv6InterfaceAddress rtDestAddr =
                     Ipv6InterfaceAddress(rtIter->first->GetDestNetwork(),
@@ -1032,7 +1030,7 @@
     std::list<RipNgRte> rtes = hdr.GetRteList();
 
     // validate the RTEs before processing
-    for (std::list<RipNgRte>::iterator iter = rtes.begin(); iter != rtes.end(); iter++)
+    for (auto iter = rtes.begin(); iter != rtes.end(); iter++)
     {
         if (iter->GetRouteMetric() == 0 || iter->GetRouteMetric() > m_linkDown)
         {
@@ -1056,7 +1054,7 @@
 
     bool changed = false;
 
-    for (std::list<RipNgRte>::iterator iter = rtes.begin(); iter != rtes.end(); iter++)
+    for (auto iter = rtes.begin(); iter != rtes.end(); iter++)
     {
         Ipv6Prefix rtePrefix = Ipv6Prefix(iter->GetPrefixLen());
         Ipv6Address rteAddr = iter->GetPrefix().CombinePrefix(rtePrefix);
@@ -1085,12 +1083,11 @@
                 {
                     if (senderAddress != it->first->GetGateway())
                     {
-                        RipNgRoutingTableEntry* route =
-                            new RipNgRoutingTableEntry(rteAddr,
-                                                       rtePrefix,
-                                                       senderAddress,
-                                                       incomingInterface,
-                                                       Ipv6Address::GetAny());
+                        auto route = new RipNgRoutingTableEntry(rteAddr,
+                                                                rtePrefix,
+                                                                senderAddress,
+                                                                incomingInterface,
+                                                                Ipv6Address::GetAny());
                         delete it->first;
                         it->first = route;
                     }
@@ -1119,12 +1116,11 @@
                     {
                         if (Simulator::GetDelayLeft(it->second) < m_timeoutDelay / 2)
                         {
-                            RipNgRoutingTableEntry* route =
-                                new RipNgRoutingTableEntry(rteAddr,
-                                                           rtePrefix,
-                                                           senderAddress,
-                                                           incomingInterface,
-                                                           Ipv6Address::GetAny());
+                            auto route = new RipNgRoutingTableEntry(rteAddr,
+                                                                    rtePrefix,
+                                                                    senderAddress,
+                                                                    incomingInterface,
+                                                                    Ipv6Address::GetAny());
                             route->SetRouteMetric(rteMetric);
                             route->SetRouteStatus(RipNgRoutingTableEntry::RIPNG_VALID);
                             route->SetRouteTag(iter->GetRouteTag());
@@ -1168,11 +1164,11 @@
         {
             NS_LOG_LOGIC("Received a RTE with new route, adding.");
 
-            RipNgRoutingTableEntry* route = new RipNgRoutingTableEntry(rteAddr,
-                                                                       rtePrefix,
-                                                                       senderAddress,
-                                                                       incomingInterface,
-                                                                       Ipv6Address::GetAny());
+            auto route = new RipNgRoutingTableEntry(rteAddr,
+                                                    rtePrefix,
+                                                    senderAddress,
+                                                    incomingInterface,
+                                                    Ipv6Address::GetAny());
             route->SetRouteMetric(rteMetric);
             route->SetRouteStatus(RipNgRoutingTableEntry::RIPNG_VALID);
             route->SetRouteChanged(true);
@@ -1195,7 +1191,7 @@
 {
     NS_LOG_FUNCTION(this << (periodic ? " periodic" : " triggered"));
 
-    for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
+    for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
     {
         uint32_t interface = iter->second;
 
@@ -1215,7 +1211,7 @@
             RipNgHeader hdr;
             hdr.SetCommand(RipNgHeader::RESPONSE);
 
-            for (RoutesI rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
+            for (auto rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
             {
                 bool splitHorizoning = (rtIter->first->GetInterface() == interface);
                 Ipv6InterfaceAddress rtDestAddr =
@@ -1271,7 +1267,7 @@
             }
         }
     }
-    for (RoutesI rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
+    for (auto rtIter = m_routes.begin(); rtIter != m_routes.end(); rtIter++)
     {
         rtIter->first->SetRouteChanged(false);
     }
@@ -1345,7 +1341,7 @@
 {
     NS_LOG_FUNCTION(this << interface);
 
-    std::map<uint32_t, uint8_t>::const_iterator iter = m_interfaceMetrics.find(interface);
+    auto iter = m_interfaceMetrics.find(interface);
     if (iter != m_interfaceMetrics.end())
     {
         return iter->second;
@@ -1386,7 +1382,7 @@
     hdr.AddRte(rte);
     p->AddHeader(hdr);
 
-    for (SocketListI iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
+    for (auto iter = m_unicastSocketList.begin(); iter != m_unicastSocketList.end(); iter++)
     {
         uint32_t interface = iter->second;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ripng.h ns-3.40/src/internet/model/ripng.h
--- ns-3.39/src/internet/model/ripng.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/ripng.h	2023-09-27 13:30:37.662839200 -0700
@@ -20,13 +20,14 @@
 #ifndef RIPNG_H
 #define RIPNG_H
 
+#include "ipv6-interface.h"
+#include "ipv6-l3-protocol.h"
+#include "ipv6-routing-protocol.h"
+#include "ipv6-routing-table-entry.h"
+#include "ripng-header.h"
+
 #include "ns3/inet6-socket-address.h"
-#include "ns3/ipv6-interface.h"
-#include "ns3/ipv6-l3-protocol.h"
-#include "ns3/ipv6-routing-protocol.h"
-#include "ns3/ipv6-routing-table-entry.h"
 #include "ns3/random-variable-stream.h"
-#include "ns3/ripng-header.h"
 
 #include <list>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ripng-header.cc ns-3.40/src/internet/model/ripng-header.cc
--- ns-3.39/src/internet/model/ripng-header.cc	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/ripng-header.cc	2023-09-27 13:30:37.662839200 -0700
@@ -179,8 +179,7 @@
 RipNgHeader::Print(std::ostream& os) const
 {
     os << "command " << int(m_command);
-    for (std::list<RipNgRte>::const_iterator iter = m_rteList.begin(); iter != m_rteList.end();
-         iter++)
+    for (auto iter = m_rteList.begin(); iter != m_rteList.end(); iter++)
     {
         os << " | ";
         iter->Print(os);
@@ -203,8 +202,7 @@
     i.WriteU8(1);
     i.WriteU16(0);
 
-    for (std::list<RipNgRte>::const_iterator iter = m_rteList.begin(); iter != m_rteList.end();
-         iter++)
+    for (auto iter = m_rteList.begin(); iter != m_rteList.end(); iter++)
     {
         iter->Serialize(i);
         i.Next(iter->GetSerializedSize());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/ripng-header.h ns-3.40/src/internet/model/ripng-header.h
--- ns-3.39/src/internet/model/ripng-header.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/ripng-header.h	2023-09-27 13:30:37.662839200 -0700
@@ -20,9 +20,10 @@
 #ifndef RIPNG_HEADER_H
 #define RIPNG_HEADER_H
 
+#include "ipv6-header.h"
+
 #include "ns3/header.h"
 #include "ns3/ipv6-address.h"
-#include "ns3/ipv6-header.h"
 #include "ns3/packet.h"
 
 #include <list>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-bbr.h ns-3.40/src/internet/model/tcp-bbr.h
--- ns-3.39/src/internet/model/tcp-bbr.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-bbr.h	2023-09-27 13:30:37.662839200 -0700
@@ -22,11 +22,12 @@
 #ifndef TCPBBR_H
 #define TCPBBR_H
 
+#include "tcp-congestion-ops.h"
+#include "windowed-filter.h"
+
 #include "ns3/data-rate.h"
 #include "ns3/random-variable-stream.h"
-#include "ns3/tcp-congestion-ops.h"
 #include "ns3/traced-value.h"
-#include "ns3/windowed-filter.h"
 
 class TcpBbrCheckGainValuesTest;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-bic.h ns-3.40/src/internet/model/tcp-bic.h
--- ns-3.39/src/internet/model/tcp-bic.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-bic.h	2023-09-27 13:30:37.662839200 -0700
@@ -19,8 +19,8 @@
 #ifndef TCPBIC_H
 #define TCPBIC_H
 
-#include "ns3/tcp-congestion-ops.h"
-#include "ns3/tcp-recovery-ops.h"
+#include "tcp-congestion-ops.h"
+#include "tcp-recovery-ops.h"
 
 class TcpBicIncrementTest;
 class TcpBicDecrementTest;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-cubic.h ns-3.40/src/internet/model/tcp-cubic.h
--- ns-3.39/src/internet/model/tcp-cubic.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-cubic.h	2023-09-27 13:30:37.662839200 -0700
@@ -19,8 +19,8 @@
 #ifndef TCPCUBIC_H
 #define TCPCUBIC_H
 
-#include "ns3/tcp-congestion-ops.h"
-#include "ns3/tcp-socket-base.h"
+#include "tcp-congestion-ops.h"
+#include "tcp-socket-base.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-dctcp.h ns-3.40/src/internet/model/tcp-dctcp.h
--- ns-3.39/src/internet/model/tcp-dctcp.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-dctcp.h	2023-09-27 13:30:37.662839200 -0700
@@ -21,8 +21,9 @@
 #ifndef TCP_DCTCP_H
 #define TCP_DCTCP_H
 
-#include "ns3/tcp-congestion-ops.h"
-#include "ns3/tcp-linux-reno.h"
+#include "tcp-congestion-ops.h"
+#include "tcp-linux-reno.h"
+
 #include "ns3/traced-callback.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-header.cc ns-3.40/src/internet/model/tcp-header.cc
--- ns-3.39/src/internet/model/tcp-header.cc	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-header.cc	2023-09-27 13:30:37.662839200 -0700
@@ -35,25 +35,6 @@
 
 NS_OBJECT_ENSURE_REGISTERED(TcpHeader);
 
-TcpHeader::TcpHeader()
-    : m_sourcePort(0),
-      m_destinationPort(0),
-      m_sequenceNumber(0),
-      m_ackNumber(0),
-      m_length(5),
-      m_flags(0),
-      m_windowSize(0xffff),
-      m_urgentPointer(0),
-      m_calcChecksum(false),
-      m_goodChecksum(true),
-      m_optionsLen(0)
-{
-}
-
-TcpHeader::~TcpHeader()
-{
-}
-
 std::string
 TcpHeader::FlagsToString(uint8_t flags, const std::string& delimiter)
 {
@@ -63,7 +44,7 @@
     {
         if (flags & (1 << i))
         {
-            if (flagsDescription.length() > 0)
+            if (!flagsDescription.empty())
             {
                 flagsDescription += delimiter;
             }
@@ -286,9 +267,7 @@
 
     os << " Seq=" << m_sequenceNumber << " Ack=" << m_ackNumber << " Win=" << m_windowSize;
 
-    TcpOptionList::const_iterator op;
-
-    for (op = m_options.begin(); op != m_options.end(); ++op)
+    for (auto op = m_options.begin(); op != m_options.end(); ++op)
     {
         os << " " << (*op)->GetInstanceTypeId().GetName() << "(";
         (*op)->Print(os);
@@ -319,8 +298,8 @@
     // This implementation does not presently try to align options on word
     // boundaries using NOP options
     uint32_t optionLen = 0;
-    TcpOptionList::const_iterator op;
-    for (op = m_options.begin(); op != m_options.end(); ++op)
+
+    for (auto op = m_options.begin(); op != m_options.end(); ++op)
     {
         optionLen += (*op)->GetSerializedSize();
         (*op)->Serialize(i);
@@ -436,9 +415,8 @@
 TcpHeader::CalculateHeaderLength() const
 {
     uint32_t len = 20;
-    TcpOptionList::const_iterator i;
 
-    for (i = m_options.begin(); i != m_options.end(); ++i)
+    for (auto i = m_options.begin(); i != m_options.end(); ++i)
     {
         len += (*i)->GetSerializedSize();
     }
@@ -485,9 +463,7 @@
 Ptr<const TcpOption>
 TcpHeader::GetOption(uint8_t kind) const
 {
-    TcpOptionList::const_iterator i;
-
-    for (i = m_options.begin(); i != m_options.end(); ++i)
+    for (auto i = m_options.begin(); i != m_options.end(); ++i)
     {
         if ((*i)->GetKind() == kind)
         {
@@ -501,9 +477,7 @@
 bool
 TcpHeader::HasOption(uint8_t kind) const
 {
-    TcpOptionList::const_iterator i;
-
-    for (i = m_options.begin(); i != m_options.end(); ++i)
+    for (auto i = m_options.begin(); i != m_options.end(); ++i)
     {
         if ((*i)->GetKind() == kind)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-header.h ns-3.40/src/internet/model/tcp-header.h
--- ns-3.39/src/internet/model/tcp-header.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-header.h	2023-09-27 13:30:37.662839200 -0700
@@ -20,13 +20,14 @@
 #ifndef TCP_HEADER_H
 #define TCP_HEADER_H
 
+#include "tcp-option.h"
+#include "tcp-socket-factory.h"
+
 #include "ns3/buffer.h"
 #include "ns3/header.h"
 #include "ns3/ipv4-address.h"
 #include "ns3/ipv6-address.h"
 #include "ns3/sequence-number.h"
-#include "ns3/tcp-option.h"
-#include "ns3/tcp-socket-factory.h"
 
 #include <stdint.h>
 
@@ -45,9 +46,6 @@
 class TcpHeader : public Header
 {
   public:
-    TcpHeader();
-    ~TcpHeader() override;
-
     typedef std::list<Ptr<const TcpOption>> TcpOptionList; //!< List of TcpOption
 
     /**
@@ -331,25 +329,25 @@
      */
     uint8_t CalculateHeaderLength() const;
 
-    uint16_t m_sourcePort;             //!< Source port
-    uint16_t m_destinationPort;        //!< Destination port
-    SequenceNumber32 m_sequenceNumber; //!< Sequence number
-    SequenceNumber32 m_ackNumber;      //!< ACK number
-    uint8_t m_length;                  //!< Length (really a uint4_t) in words.
-    uint8_t m_flags;                   //!< Flags (really a uint6_t)
-    uint16_t m_windowSize;             //!< Window size
-    uint16_t m_urgentPointer;          //!< Urgent pointer
+    uint16_t m_sourcePort{0};             //!< Source port
+    uint16_t m_destinationPort{0};        //!< Destination port
+    SequenceNumber32 m_sequenceNumber{0}; //!< Sequence number
+    SequenceNumber32 m_ackNumber{0};      //!< ACK number
+    uint8_t m_length{5};                  //!< Length (really a uint4_t) in words.
+    uint8_t m_flags{0};                   //!< Flags (really a uint6_t)
+    uint16_t m_windowSize{0xffff};        //!< Window size
+    uint16_t m_urgentPointer{0};          //!< Urgent pointer
 
     Address m_source;      //!< Source IP address
     Address m_destination; //!< Destination IP address
-    uint8_t m_protocol;    //!< Protocol number
+    uint8_t m_protocol{6}; //!< Protocol number
 
-    bool m_calcChecksum; //!< Flag to calculate checksum
-    bool m_goodChecksum; //!< Flag to indicate that checksum is correct
+    bool m_calcChecksum{false}; //!< Flag to calculate checksum
+    bool m_goodChecksum{true};  //!< Flag to indicate that checksum is correct
 
     static const uint8_t m_maxOptionsLen = 40; //!< Maximum options length
     TcpOptionList m_options;                   //!< TcpOption present in the header
-    uint8_t m_optionsLen;                      //!< Tcp options length.
+    uint8_t m_optionsLen{0};                   //!< Tcp options length.
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-htcp.cc ns-3.40/src/internet/model/tcp-htcp.cc
--- ns-3.39/src/internet/model/tcp-htcp.cc	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-htcp.cc	2023-09-27 13:30:37.662839200 -0700
@@ -182,7 +182,7 @@
     UpdateAlpha();
 
     uint32_t segWin = 2 * tcb->m_segmentSize;
-    uint32_t bFlight = static_cast<uint32_t>(bytesInFlight * m_beta);
+    auto bFlight = static_cast<uint32_t>(bytesInFlight * m_beta);
     uint32_t ssThresh = std::max(segWin, bFlight);
     m_minRtt = Time::Max();
     m_maxRtt = Time::Min();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-hybla.cc ns-3.40/src/internet/model/tcp-hybla.cc
--- ns-3.39/src/internet/model/tcp-hybla.cc	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-hybla.cc	2023-09-27 13:30:37.662839200 -0700
@@ -106,7 +106,7 @@
          */
 
         double increment = std::pow(2, m_rho) - 1.0;
-        uint32_t incr = static_cast<uint32_t>(increment * tcb->m_segmentSize);
+        auto incr = static_cast<uint32_t>(increment * tcb->m_segmentSize);
         NS_LOG_INFO("Slow start: inc=" << increment);
 
         tcb->m_cWnd = std::min(tcb->m_cWnd + incr, tcb->m_ssThresh);
@@ -145,7 +145,7 @@
     if (m_cWndCnt >= 1.0)
     {
         // double to int truncates every time.
-        uint32_t inc = static_cast<uint32_t>(m_cWndCnt);
+        auto inc = static_cast<uint32_t>(m_cWndCnt);
         m_cWndCnt -= inc;
 
         NS_ASSERT(m_cWndCnt >= 0.0);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-ledbat.cc ns-3.40/src/internet/model/tcp-ledbat.cc
--- ns-3.39/src/internet/model/tcp-ledbat.cc	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-ledbat.cc	2023-09-27 13:30:37.662839200 -0700
@@ -288,7 +288,7 @@
     }
     else
     {
-        uint32_t last = static_cast<uint32_t>(m_baseHistory.buffer.size() - 1);
+        auto last = static_cast<uint32_t>(m_baseHistory.buffer.size() - 1);
         if (owd < m_baseHistory.buffer[last])
         {
             m_baseHistory.buffer[last] = owd;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-linux-reno.h ns-3.40/src/internet/model/tcp-linux-reno.h
--- ns-3.39/src/internet/model/tcp-linux-reno.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-linux-reno.h	2023-09-27 13:30:37.662839200 -0700
@@ -22,8 +22,8 @@
 #ifndef TCPLINUXRENO_H
 #define TCPLINUXRENO_H
 
-#include "ns3/tcp-congestion-ops.h"
-#include "ns3/tcp-socket-state.h"
+#include "tcp-congestion-ops.h"
+#include "tcp-socket-state.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-option-rfc793.h ns-3.40/src/internet/model/tcp-option-rfc793.h
--- ns-3.39/src/internet/model/tcp-option-rfc793.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-option-rfc793.h	2023-09-27 13:30:37.662839200 -0700
@@ -19,7 +19,7 @@
 #ifndef TCPOPTIONRFC793_H
 #define TCPOPTIONRFC793_H
 
-#include "ns3/tcp-option.h"
+#include "tcp-option.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-option-sack.cc ns-3.40/src/internet/model/tcp-option-sack.cc
--- ns-3.39/src/internet/model/tcp-option-sack.cc	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-option-sack.cc	2023-09-27 13:30:37.662839200 -0700
@@ -62,7 +62,7 @@
 TcpOptionSack::Print(std::ostream& os) const
 {
     os << "blocks: " << GetNumSackBlocks() << ",";
-    for (SackList::const_iterator it = m_sackList.begin(); it != m_sackList.end(); ++it)
+    for (auto it = m_sackList.begin(); it != m_sackList.end(); ++it)
     {
         os << "[" << it->first << "," << it->second << "]";
     }
@@ -82,10 +82,10 @@
     NS_LOG_FUNCTION(this);
     Buffer::Iterator i = start;
     i.WriteU8(GetKind()); // Kind
-    uint8_t length = static_cast<uint8_t>(GetNumSackBlocks() * 8 + 2);
+    auto length = static_cast<uint8_t>(GetNumSackBlocks() * 8 + 2);
     i.WriteU8(length); // Length
 
-    for (SackList::const_iterator it = m_sackList.begin(); it != m_sackList.end(); ++it)
+    for (auto it = m_sackList.begin(); it != m_sackList.end(); ++it)
     {
         SequenceNumber32 leftEdge = it->first;
         SequenceNumber32 rightEdge = it->second;
@@ -112,8 +112,8 @@
     uint8_t sackCount = (size - 2) / 8;
     while (sackCount)
     {
-        SequenceNumber32 leftEdge = SequenceNumber32(i.ReadNtohU32());
-        SequenceNumber32 rightEdge = SequenceNumber32(i.ReadNtohU32());
+        SequenceNumber32 leftEdge(i.ReadNtohU32());
+        SequenceNumber32 rightEdge(i.ReadNtohU32());
         SackBlock s(leftEdge, rightEdge);
         AddSackBlock(s);
         sackCount--;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-option-sack.h ns-3.40/src/internet/model/tcp-option-sack.h
--- ns-3.39/src/internet/model/tcp-option-sack.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-option-sack.h	2023-09-27 13:30:37.662839200 -0700
@@ -25,8 +25,9 @@
 #ifndef TCP_OPTION_SACK_H
 #define TCP_OPTION_SACK_H
 
+#include "tcp-option.h"
+
 #include "ns3/sequence-number.h"
-#include "ns3/tcp-option.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-option-sack-permitted.h ns-3.40/src/internet/model/tcp-option-sack-permitted.h
--- ns-3.39/src/internet/model/tcp-option-sack-permitted.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-option-sack-permitted.h	2023-09-27 13:30:37.662839200 -0700
@@ -25,7 +25,7 @@
 #ifndef TCP_OPTION_SACK_PERMITTED_H
 #define TCP_OPTION_SACK_PERMITTED_H
 
-#include "ns3/tcp-option.h"
+#include "tcp-option.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-option-ts.h ns-3.40/src/internet/model/tcp-option-ts.h
--- ns-3.39/src/internet/model/tcp-option-ts.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-option-ts.h	2023-09-27 13:30:37.662839200 -0700
@@ -20,7 +20,8 @@
 #ifndef TCP_OPTION_TS_H
 #define TCP_OPTION_TS_H
 
-#include "ns3/tcp-option.h"
+#include "tcp-option.h"
+
 #include "ns3/timer.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-option-winscale.h ns-3.40/src/internet/model/tcp-option-winscale.h
--- ns-3.39/src/internet/model/tcp-option-winscale.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-option-winscale.h	2023-09-27 13:30:37.662839200 -0700
@@ -21,7 +21,7 @@
 #ifndef TCP_OPTION_WINSCALE_H
 #define TCP_OPTION_WINSCALE_H
 
-#include "ns3/tcp-option.h"
+#include "tcp-option.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-prr-recovery.h ns-3.40/src/internet/model/tcp-prr-recovery.h
--- ns-3.39/src/internet/model/tcp-prr-recovery.h	2023-07-05 14:23:47.857427600 -0700
+++ ns-3.40/src/internet/model/tcp-prr-recovery.h	2023-09-27 13:30:37.662839200 -0700
@@ -22,7 +22,7 @@
 #ifndef TCP_PRR_RECOVERY_H
 #define TCP_PRR_RECOVERY_H
 
-#include "ns3/tcp-recovery-ops.h"
+#include "tcp-recovery-ops.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-rate-ops.h ns-3.40/src/internet/model/tcp-rate-ops.h
--- ns-3.39/src/internet/model/tcp-rate-ops.h	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-rate-ops.h	2023-09-27 13:30:37.662839200 -0700
@@ -18,9 +18,10 @@
 #ifndef TCP_RATE_OPS_H
 #define TCP_RATE_OPS_H
 
+#include "tcp-tx-item.h"
+
 #include "ns3/data-rate.h"
 #include "ns3/object.h"
-#include "ns3/tcp-tx-item.h"
 #include "ns3/traced-callback.h"
 #include "ns3/traced-value.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-rx-buffer.cc ns-3.40/src/internet/model/tcp-rx-buffer.cc
--- ns-3.39/src/internet/model/tcp-rx-buffer.cc	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-rx-buffer.cc	2023-09-27 13:30:37.662839200 -0700
@@ -172,7 +172,7 @@
         }
     }
     // Remove overlapped bytes from packet
-    BufIterator i = m_data.begin();
+    auto i = m_data.begin();
     while (i != m_data.end() && i->first <= tailSeq)
     {
         SequenceNumber32 lastByteSeq = i->first + SequenceNumber32(i->second->GetSize());
@@ -204,7 +204,7 @@
     else
     {
         uint32_t start = static_cast<uint32_t>(headSeq - tcph.GetSequenceNumber());
-        uint32_t length = static_cast<uint32_t>(tailSeq - headSeq);
+        auto length = static_cast<uint32_t>(tailSeq - headSeq);
         p = p->CreateFragment(start, length);
         NS_ASSERT(length == p->GetSize());
     }
@@ -292,7 +292,7 @@
     // We have inserted the block at the beginning of the list. Now, we should
     // check if any existing blocks overlap with that.
     bool updated = false;
-    TcpOptionSack::SackList::iterator it = m_sackList.begin();
+    auto it = m_sackList.begin();
     TcpOptionSack::SackBlock begin = *it;
     TcpOptionSack::SackBlock merged;
     ++it;
@@ -353,8 +353,7 @@
 {
     NS_LOG_FUNCTION(this << seq);
 
-    TcpOptionSack::SackList::iterator it;
-    for (it = m_sackList.begin(); it != m_sackList.end();)
+    for (auto it = m_sackList.begin(); it != m_sackList.end();)
     {
         TcpOptionSack::SackBlock block = *it;
         NS_ASSERT(block.first < block.second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-rx-buffer.h ns-3.40/src/internet/model/tcp-rx-buffer.h
--- ns-3.39/src/internet/model/tcp-rx-buffer.h	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-rx-buffer.h	2023-09-27 13:30:37.662839200 -0700
@@ -20,10 +20,11 @@
 #ifndef TCP_RX_BUFFER_H
 #define TCP_RX_BUFFER_H
 
+#include "tcp-header.h"
+#include "tcp-option-sack.h"
+
 #include "ns3/ptr.h"
 #include "ns3/sequence-number.h"
-#include "ns3/tcp-header.h"
-#include "ns3/tcp-option-sack.h"
 #include "ns3/trace-source-accessor.h"
 #include "ns3/traced-value.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-socket-base.cc ns-3.40/src/internet/model/tcp-socket-base.cc
--- ns-3.39/src/internet/model/tcp-socket-base.cc	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-socket-base.cc	2023-09-27 13:30:37.662839200 -0700
@@ -1851,7 +1851,7 @@
 
     m_txBuffer->DiscardUpTo(ackNumber, MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
 
-    uint32_t currentDelivered =
+    auto currentDelivered =
         static_cast<uint32_t>(m_rateOps->GetConnectionRate().m_delivered - previousDelivered);
     m_tcb->m_lastAckedSackedBytes = currentDelivered;
 
@@ -3272,7 +3272,7 @@
     }
     else
     { // This is a retransmit, find in list and mark as re-tx
-        for (std::deque<RttHistory>::iterator i = m_history.begin(); i != m_history.end(); ++i)
+        for (auto i = m_history.begin(); i != m_history.end(); ++i)
         {
             if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32(i->count))))
             { // Found it
@@ -3291,13 +3291,13 @@
     NS_LOG_FUNCTION(this << withAck);
     if (m_txBuffer->Size() == 0)
     {
-        return false; // Nothing to send
+        return 0; // Nothing to send
     }
     if (m_endPoint == nullptr && m_endPoint6 == nullptr)
     {
         NS_LOG_INFO(
             "TcpSocketBase::SendPendingData: No endpoint; m_shutdownSend=" << m_shutdownSend);
-        return false; // Is this the right way to handle this condition?
+        return 0; // Is this the right way to handle this condition?
     }
 
     uint32_t nPacketsSent = 0;
@@ -3370,7 +3370,7 @@
 
             uint32_t s = std::min(availableWindow, m_tcb->m_segmentSize);
             // NextSeg () may have further constrained the segment size
-            uint32_t maxSizeToSend = static_cast<uint32_t>(nextHigh - next);
+            auto maxSizeToSend = static_cast<uint32_t>(nextHigh - next);
             s = std::min(s, maxSizeToSend);
 
             // (C.2) If any of the data octets sent in (C.1) are below HighData,
@@ -4317,8 +4317,8 @@
 
     // Append the allowed number of SACK blocks
     Ptr<TcpOptionSack> option = CreateObject<TcpOptionSack>();
-    TcpOptionSack::SackList::iterator i;
-    for (i = sackList.begin(); allowedSackBlocks > 0 && i != sackList.end(); ++i)
+
+    for (auto i = sackList.begin(); allowedSackBlocks > 0 && i != sackList.end(); ++i)
     {
         option->AddSackBlock(*i);
         allowedSackBlocks--;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-socket-base.h ns-3.40/src/internet/model/tcp-socket-base.h
--- ns-3.39/src/internet/model/tcp-socket-base.h	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-socket-base.h	2023-09-27 13:30:37.662839200 -0700
@@ -20,13 +20,14 @@
 #ifndef TCP_SOCKET_BASE_H
 #define TCP_SOCKET_BASE_H
 
+#include "ipv4-header.h"
+#include "ipv6-header.h"
+#include "tcp-socket-state.h"
+#include "tcp-socket.h"
+
 #include "ns3/data-rate.h"
-#include "ns3/ipv4-header.h"
-#include "ns3/ipv6-header.h"
 #include "ns3/node.h"
 #include "ns3/sequence-number.h"
-#include "ns3/tcp-socket-state.h"
-#include "ns3/tcp-socket.h"
 #include "ns3/timer.h"
 #include "ns3/traced-value.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-socket-factory-impl.h ns-3.40/src/internet/model/tcp-socket-factory-impl.h
--- ns-3.39/src/internet/model/tcp-socket-factory-impl.h	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-socket-factory-impl.h	2023-09-27 13:30:37.662839200 -0700
@@ -19,8 +19,9 @@
 #ifndef TCP_SOCKET_FACTORY_IMPL_H
 #define TCP_SOCKET_FACTORY_IMPL_H
 
+#include "tcp-socket-factory.h"
+
 #include "ns3/ptr.h"
-#include "ns3/tcp-socket-factory.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-tx-buffer.cc ns-3.40/src/internet/model/tcp-tx-buffer.cc
--- ns-3.39/src/internet/model/tcp-tx-buffer.cc	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-tx-buffer.cc	2023-09-27 13:30:37.662839200 -0700
@@ -68,16 +68,14 @@
 
 TcpTxBuffer::~TcpTxBuffer()
 {
-    PacketList::iterator it;
-
-    for (it = m_sentList.begin(); it != m_sentList.end(); ++it)
+    for (auto it = m_sentList.begin(); it != m_sentList.end(); ++it)
     {
         TcpTxItem* item = *it;
         m_sentSize -= item->m_packet->GetSize();
         delete item;
     }
 
-    for (it = m_appList.begin(); it != m_appList.end(); ++it)
+    for (auto it = m_appList.begin(); it != m_appList.end(); ++it)
     {
         TcpTxItem* item = *it;
         m_size -= item->m_packet->GetSize();
@@ -189,7 +187,7 @@
     {
         if (p->GetSize() > 0)
         {
-            TcpTxItem* item = new TcpTxItem();
+            auto item = new TcpTxItem();
             item->m_packet = p->Copy();
             m_appList.insert(m_appList.end(), item);
             m_size += p->GetSize();
@@ -437,7 +435,7 @@
     Ptr<Packet> currentPacket = nullptr;
     TcpTxItem* currentItem = nullptr;
     TcpTxItem* outItem = nullptr;
-    PacketList::iterator it = list.begin();
+    auto it = list.begin();
     SequenceNumber32 beginOfCurrentPacket = listStartFrom;
 
     while (it != list.end())
@@ -469,7 +467,7 @@
                 NS_LOG_INFO("we are at " << beginOfCurrentPacket << " searching for " << seq
                                          << " and now we recurse because packet ends at "
                                          << beginOfCurrentPacket + currentPacket->GetSize());
-                TcpTxItem* firstPart = new TcpTxItem();
+                auto firstPart = new TcpTxItem();
                 SplitItems(firstPart, currentItem, seq - beginOfCurrentPacket);
 
                 // insert firstPart before currentItem
@@ -535,7 +533,7 @@
             {
                 // the end is inside the current packet, but it isn't exactly
                 // the packet end. Just fragment, fix the list, and return.
-                TcpTxItem* firstPart = new TcpTxItem();
+                auto firstPart = new TcpTxItem();
                 SplitItems(firstPart, currentItem, numBytes);
 
                 // insert firstPart before currentItem
@@ -603,14 +601,14 @@
     {
         if (t1->m_retrans)
         {
-            TcpTxBuffer* self = const_cast<TcpTxBuffer*>(this);
+            auto self = const_cast<TcpTxBuffer*>(this);
             self->m_retrans -= t1->m_packet->GetSize();
             t1->m_retrans = false;
         }
         else
         {
             NS_ASSERT(t2->m_retrans);
-            TcpTxBuffer* self = const_cast<TcpTxBuffer*>(this);
+            auto self = const_cast<TcpTxBuffer*>(this);
             self->m_retrans -= t2->m_packet->GetSize();
             t2->m_retrans = false;
         }
@@ -681,7 +679,7 @@
     // Scan the buffer and discard packets
     uint32_t offset = seq - m_firstByteSeq.Get(); // Number of bytes to remove
     uint32_t pktSize;
-    PacketList::iterator i = m_sentList.begin();
+    auto i = m_sentList.begin();
     while (m_size > 0 && offset > 0)
     {
         if (i == m_sentList.end())
@@ -790,7 +788,7 @@
 
     for (auto option_it = list.begin(); option_it != list.end(); ++option_it)
     {
-        PacketList::iterator item_it = m_sentList.begin();
+        auto item_it = m_sentList.begin();
         SequenceNumber32 beginOfCurrentPacket = m_firstByteSeq;
 
         if (m_firstByteSeq + m_sentSize < (*option_it).first)
@@ -929,7 +927,6 @@
     NS_LOG_FUNCTION(this << seq);
 
     SequenceNumber32 beginOfCurrentPacket = m_firstByteSeq;
-    PacketList::const_iterator it;
 
     if (seq >= m_highestSack.second)
     {
@@ -938,7 +935,7 @@
 
     // In theory, using a map and hints when inserting elements can improve
     // performance
-    for (it = m_sentList.begin(); it != m_sentList.end(); ++it)
+    for (auto it = m_sentList.begin(); it != m_sentList.end(); ++it)
     {
         // Search for the right iterator before calling IsLost()
         if (beginOfCurrentPacket >= seq)
@@ -980,13 +977,12 @@
      *
      *     (1.c) IsLost (S2) returns true.
      */
-    PacketList::const_iterator it;
     TcpTxItem* item;
     SequenceNumber32 seqPerRule3;
     bool isSeqPerRule3Valid = false;
     SequenceNumber32 beginOfCurrentPkt = m_firstByteSeq;
 
-    for (it = m_sentList.begin(); it != m_sentList.end(); ++it)
+    for (auto it = m_sentList.begin(); it != m_sentList.end(); ++it)
     {
         item = *it;
 
@@ -1092,7 +1088,6 @@
 uint32_t
 TcpTxBuffer::BytesInFlightRFC() const
 {
-    PacketList::const_iterator it;
     TcpTxItem* item;
     uint32_t size = 0; // "pipe" in RFC
     SequenceNumber32 beginOfCurrentPkt = m_firstByteSeq;
@@ -1104,7 +1099,7 @@
     // After initializing pipe to zero, the following steps are taken for each
     // octet 'S1' in the sequence space between HighACK and HighData that has not
     // been SACKed:
-    for (it = m_sentList.begin(); it != m_sentList.end(); ++it)
+    for (auto it = m_sentList.begin(); it != m_sentList.end(); ++it)
     {
         item = *it;
         totalSize += item->m_packet->GetSize();
@@ -1472,14 +1467,13 @@
 std::ostream&
 operator<<(std::ostream& os, const TcpTxBuffer& tcpTxBuf)
 {
-    TcpTxBuffer::PacketList::const_iterator it;
     std::stringstream ss;
     SequenceNumber32 beginOfCurrentPacket = tcpTxBuf.m_firstByteSeq;
     uint32_t sentSize = 0;
     uint32_t appSize = 0;
 
     Ptr<const Packet> p;
-    for (it = tcpTxBuf.m_sentList.begin(); it != tcpTxBuf.m_sentList.end(); ++it)
+    for (auto it = tcpTxBuf.m_sentList.begin(); it != tcpTxBuf.m_sentList.end(); ++it)
     {
         p = (*it)->GetPacket();
         ss << "{";
@@ -1489,7 +1483,7 @@
         beginOfCurrentPacket += p->GetSize();
     }
 
-    for (it = tcpTxBuf.m_appList.begin(); it != tcpTxBuf.m_appList.end(); ++it)
+    for (auto it = tcpTxBuf.m_appList.begin(); it != tcpTxBuf.m_appList.end(); ++it)
     {
         appSize += (*it)->GetPacket()->GetSize();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-tx-buffer.h ns-3.40/src/internet/model/tcp-tx-buffer.h
--- ns-3.39/src/internet/model/tcp-tx-buffer.h	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-tx-buffer.h	2023-09-27 13:30:37.662839200 -0700
@@ -21,10 +21,11 @@
 #ifndef TCP_TX_BUFFER_H
 #define TCP_TX_BUFFER_H
 
+#include "tcp-option-sack.h"
+#include "tcp-tx-item.h"
+
 #include "ns3/object.h"
 #include "ns3/sequence-number.h"
-#include "ns3/tcp-option-sack.h"
-#include "ns3/tcp-tx-item.h"
 #include "ns3/traced-value.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-westwood-plus.h ns-3.40/src/internet/model/tcp-westwood-plus.h
--- ns-3.39/src/internet/model/tcp-westwood-plus.h	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-westwood-plus.h	2023-09-27 13:30:37.666839100 -0700
@@ -33,10 +33,10 @@
 #define TCP_WESTWOOD_H
 
 #include "tcp-congestion-ops.h"
+#include "tcp-recovery-ops.h"
 
 #include "ns3/data-rate.h"
 #include "ns3/event-id.h"
-#include "ns3/tcp-recovery-ops.h"
 #include "ns3/traced-value.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-yeah.cc ns-3.40/src/internet/model/tcp-yeah.cc
--- ns-3.39/src/internet/model/tcp-yeah.cc	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-yeah.cc	2023-09-27 13:30:37.666839100 -0700
@@ -249,7 +249,7 @@
 
             // queue = rttQueue * bw = rttQueue * (cwnd/RTTmin)
             double bw = segCwnd / m_minRtt.GetSeconds();
-            uint32_t queue = static_cast<uint32_t>(bw * rttQueue.GetSeconds());
+            auto queue = static_cast<uint32_t>(bw * rttQueue.GetSeconds());
             NS_LOG_DEBUG("Queue backlog = " << queue << " given by cwnd = " << segCwnd
                                             << ", minRtt = " << m_minRtt.GetMilliSeconds()
                                             << " ms, baseRtt = " << m_baseRtt.GetMilliSeconds()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/tcp-yeah.h ns-3.40/src/internet/model/tcp-yeah.h
--- ns-3.39/src/internet/model/tcp-yeah.h	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/tcp-yeah.h	2023-09-27 13:30:37.666839100 -0700
@@ -26,8 +26,8 @@
 #ifndef TCPYEAH_H
 #define TCPYEAH_H
 
-#include "ns3/tcp-recovery-ops.h"
-#include "ns3/tcp-scalable.h"
+#include "tcp-recovery-ops.h"
+#include "tcp-scalable.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/udp-header.cc ns-3.40/src/internet/model/udp-header.cc
--- ns-3.39/src/internet/model/udp-header.cc	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/udp-header.cc	2023-09-27 13:30:37.666839100 -0700
@@ -26,27 +26,6 @@
 
 NS_OBJECT_ENSURE_REGISTERED(UdpHeader);
 
-/* The magic values below are used only for debugging.
- * They can be used to easily detect memory corruption
- * problems so you can see the patterns in memory.
- */
-UdpHeader::UdpHeader()
-    : m_sourcePort(0xfffd),
-      m_destinationPort(0xfffd),
-      m_payloadSize(0),
-      m_checksum(0),
-      m_calcChecksum(false),
-      m_goodChecksum(true)
-{
-}
-
-UdpHeader::~UdpHeader()
-{
-    m_sourcePort = 0xfffe;
-    m_destinationPort = 0xfffe;
-    m_payloadSize = 0xfffe;
-}
-
 void
 UdpHeader::EnableChecksums()
 {
@@ -150,7 +129,7 @@
 void
 UdpHeader::ForcePayloadSize(uint16_t payloadSize)
 {
-    m_payloadSize = payloadSize;
+    m_forcedPayloadSize = payloadSize;
 }
 
 TypeId
@@ -189,13 +168,13 @@
 
     i.WriteHtonU16(m_sourcePort);
     i.WriteHtonU16(m_destinationPort);
-    if (m_payloadSize == 0)
+    if (m_forcedPayloadSize == 0)
     {
         i.WriteHtonU16(start.GetSize());
     }
     else
     {
-        i.WriteHtonU16(m_payloadSize);
+        i.WriteHtonU16(m_forcedPayloadSize);
     }
 
     if (m_checksum == 0)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/udp-header.h ns-3.40/src/internet/model/udp-header.h
--- ns-3.39/src/internet/model/udp-header.h	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/udp-header.h	2023-09-27 13:30:37.666839100 -0700
@@ -41,14 +41,6 @@
 {
   public:
     /**
-     * \brief Constructor
-     *
-     * Creates a null header
-     */
-    UdpHeader();
-    ~UdpHeader() override;
-
-    /**
      * \brief Enable checksum calculation for UDP
      */
     void EnableChecksums();
@@ -167,16 +159,21 @@
      * \returns the checksum
      */
     uint16_t CalculateHeaderChecksum(uint16_t size) const;
-    uint16_t m_sourcePort;      //!< Source port
-    uint16_t m_destinationPort; //!< Destination port
-    uint16_t m_payloadSize;     //!< Payload size
-
-    Address m_source;      //!< Source IP address
-    Address m_destination; //!< Destination IP address
-    uint8_t m_protocol;    //!< Protocol number
-    uint16_t m_checksum;   //!< Forced Checksum value
-    bool m_calcChecksum;   //!< Flag to calculate checksum
-    bool m_goodChecksum;   //!< Flag to indicate that checksum is correct
+
+    // The magic values below are used only for debugging.
+    // They can be used to easily detect memory corruption
+    // problems so you can see the patterns in memory.
+    uint16_t m_sourcePort{0xfffd};      //!< Source port
+    uint16_t m_destinationPort{0xfffd}; //!< Destination port
+    uint16_t m_payloadSize{0};          //!< Payload size
+    uint16_t m_forcedPayloadSize{0};    //!< Payload size (forced)
+
+    Address m_source;           //!< Source IP address
+    Address m_destination;      //!< Destination IP address
+    uint8_t m_protocol{17};     //!< Protocol number
+    uint16_t m_checksum{0};     //!< Forced Checksum value
+    bool m_calcChecksum{false}; //!< Flag to calculate checksum
+    bool m_goodChecksum{true};  //!< Flag to indicate that checksum is correct
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/udp-l4-protocol.cc ns-3.40/src/internet/model/udp-l4-protocol.cc
--- ns-3.39/src/internet/model/udp-l4-protocol.cc	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/udp-l4-protocol.cc	2023-09-27 13:30:37.666839100 -0700
@@ -382,8 +382,7 @@
     }
 
     packet->RemoveHeader(udpHeader);
-    for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin(); endPoint != endPoints.end();
-         endPoint++)
+    for (auto endPoint = endPoints.begin(); endPoint != endPoints.end(); endPoint++)
     {
         (*endPoint)->ForwardUp(packet->Copy(), header, udpHeader.GetSourcePort(), interface);
     }
@@ -422,8 +421,7 @@
         NS_LOG_LOGIC("RX_ENDPOINT_UNREACH");
         return IpL4Protocol::RX_ENDPOINT_UNREACH;
     }
-    for (Ipv6EndPointDemux::EndPointsI endPoint = endPoints.begin(); endPoint != endPoints.end();
-         endPoint++)
+    for (auto endPoint = endPoints.begin(); endPoint != endPoints.end(); endPoint++)
     {
         (*endPoint)->ForwardUp(packet->Copy(), header, udpHeader.GetSourcePort(), interface);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/udp-socket-factory-impl.h ns-3.40/src/internet/model/udp-socket-factory-impl.h
--- ns-3.39/src/internet/model/udp-socket-factory-impl.h	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/udp-socket-factory-impl.h	2023-09-27 13:30:37.666839100 -0700
@@ -19,8 +19,9 @@
 #ifndef UDP_SOCKET_FACTORY_IMPL_H
 #define UDP_SOCKET_FACTORY_IMPL_H
 
+#include "udp-socket-factory.h"
+
 #include "ns3/ptr.h"
-#include "ns3/udp-socket-factory.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/model/udp-socket-impl.h ns-3.40/src/internet/model/udp-socket-impl.h
--- ns-3.39/src/internet/model/udp-socket-impl.h	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/model/udp-socket-impl.h	2023-09-27 13:30:37.666839100 -0700
@@ -20,14 +20,14 @@
 #define UDP_SOCKET_IMPL_H
 
 #include "icmpv4.h"
+#include "ipv4-interface.h"
+#include "udp-socket.h"
 
 #include "ns3/callback.h"
 #include "ns3/ipv4-address.h"
-#include "ns3/ipv4-interface.h"
 #include "ns3/ptr.h"
 #include "ns3/socket.h"
 #include "ns3/traced-callback.h"
-#include "ns3/udp-socket.h"
 
 #include <queue>
 #include <stdint.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/global-route-manager-impl-test-suite.cc ns-3.40/src/internet/test/global-route-manager-impl-test-suite.cc
--- ns-3.39/src/internet/test/global-route-manager-impl-test-suite.cc	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/test/global-route-manager-impl-test-suite.cc	2023-09-27 13:30:37.666839100 -0700
@@ -60,7 +60,7 @@
 
     for (int i = 0; i < 100; ++i)
     {
-        SPFVertex* v = new SPFVertex;
+        auto v = new SPFVertex;
         v->SetDistanceFromRoot(std::rand() % 100);
         candidate.Push(v);
     }
@@ -88,18 +88,17 @@
     //  link2:  10.1.3.1/30, 10.1.3.2/30
     //
     // Router 0
-    GlobalRoutingLinkRecord* lr0 =
-        new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
-                                    "0.0.0.2",  // router ID 0.0.0.2
-                                    "10.1.1.1", // local ID
-                                    1);         // metric
-
-    GlobalRoutingLinkRecord* lr1 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
-                                                               "10.1.1.1",
-                                                               "255.255.255.252",
-                                                               1);
+    auto lr0 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
+                                           "0.0.0.2",  // router ID 0.0.0.2
+                                           "10.1.1.1", // local ID
+                                           1);         // metric
+
+    auto lr1 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
+                                           "10.1.1.1",
+                                           "255.255.255.252",
+                                           1);
 
-    GlobalRoutingLSA* lsa0 = new GlobalRoutingLSA();
+    auto lsa0 = new GlobalRoutingLSA();
     lsa0->SetLSType(GlobalRoutingLSA::RouterLSA);
     lsa0->SetLinkStateId("0.0.0.0");
     lsa0->SetAdvertisingRouter("0.0.0.0");
@@ -107,18 +106,17 @@
     lsa0->AddLinkRecord(lr1);
 
     // Router 1
-    GlobalRoutingLinkRecord* lr2 =
-        new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
-                                    "0.0.0.2",
-                                    "10.1.2.1",
-                                    1);
-
-    GlobalRoutingLinkRecord* lr3 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
-                                                               "10.1.2.1",
-                                                               "255.255.255.252",
-                                                               1);
+    auto lr2 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
+                                           "0.0.0.2",
+                                           "10.1.2.1",
+                                           1);
+
+    auto lr3 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
+                                           "10.1.2.1",
+                                           "255.255.255.252",
+                                           1);
 
-    GlobalRoutingLSA* lsa1 = new GlobalRoutingLSA();
+    auto lsa1 = new GlobalRoutingLSA();
     lsa1->SetLSType(GlobalRoutingLSA::RouterLSA);
     lsa1->SetLinkStateId("0.0.0.1");
     lsa1->SetAdvertisingRouter("0.0.0.1");
@@ -126,40 +124,37 @@
     lsa1->AddLinkRecord(lr3);
 
     // Router 2
-    GlobalRoutingLinkRecord* lr4 =
-        new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
-                                    "0.0.0.0",
-                                    "10.1.1.2",
-                                    1);
-
-    GlobalRoutingLinkRecord* lr5 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
-                                                               "10.1.1.2",
-                                                               "255.255.255.252",
-                                                               1);
-
-    GlobalRoutingLinkRecord* lr6 =
-        new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
-                                    "0.0.0.1",
-                                    "10.1.2.2",
-                                    1);
-
-    GlobalRoutingLinkRecord* lr7 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
-                                                               "10.1.2.2",
-                                                               "255.255.255.252",
-                                                               1);
-
-    GlobalRoutingLinkRecord* lr8 =
-        new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
-                                    "0.0.0.3",
-                                    "10.1.3.2",
-                                    1);
-
-    GlobalRoutingLinkRecord* lr9 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
-                                                               "10.1.3.2",
-                                                               "255.255.255.252",
-                                                               1);
+    auto lr4 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
+                                           "0.0.0.0",
+                                           "10.1.1.2",
+                                           1);
+
+    auto lr5 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
+                                           "10.1.1.2",
+                                           "255.255.255.252",
+                                           1);
+
+    auto lr6 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
+                                           "0.0.0.1",
+                                           "10.1.2.2",
+                                           1);
+
+    auto lr7 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
+                                           "10.1.2.2",
+                                           "255.255.255.252",
+                                           1);
+
+    auto lr8 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
+                                           "0.0.0.3",
+                                           "10.1.3.2",
+                                           1);
+
+    auto lr9 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
+                                           "10.1.3.2",
+                                           "255.255.255.252",
+                                           1);
 
-    GlobalRoutingLSA* lsa2 = new GlobalRoutingLSA();
+    auto lsa2 = new GlobalRoutingLSA();
     lsa2->SetLSType(GlobalRoutingLSA::RouterLSA);
     lsa2->SetLinkStateId("0.0.0.2");
     lsa2->SetAdvertisingRouter("0.0.0.2");
@@ -171,19 +166,17 @@
     lsa2->AddLinkRecord(lr9);
 
     // Router 3
-    GlobalRoutingLinkRecord* lr10 =
-        new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
-                                    "0.0.0.2",
-                                    "10.1.2.1",
-                                    1);
-
-    GlobalRoutingLinkRecord* lr11 =
-        new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
-                                    "10.1.2.1",
-                                    "255.255.255.252",
-                                    1);
+    auto lr10 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint,
+                                            "0.0.0.2",
+                                            "10.1.2.1",
+                                            1);
+
+    auto lr11 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork,
+                                            "10.1.2.1",
+                                            "255.255.255.252",
+                                            1);
 
-    GlobalRoutingLSA* lsa3 = new GlobalRoutingLSA();
+    auto lsa3 = new GlobalRoutingLSA();
     lsa3->SetLSType(GlobalRoutingLSA::RouterLSA);
     lsa3->SetLinkStateId("0.0.0.3");
     lsa3->SetAdvertisingRouter("0.0.0.3");
@@ -191,7 +184,7 @@
     lsa3->AddLinkRecord(lr11);
 
     // Test the database
-    GlobalRouteManagerLSDB* srmlsdb = new GlobalRouteManagerLSDB();
+    auto srmlsdb = new GlobalRouteManagerLSDB();
     srmlsdb->Insert(lsa0->GetLinkStateId(), lsa0);
     srmlsdb->Insert(lsa1->GetLinkStateId(), lsa1);
     srmlsdb->Insert(lsa2->GetLinkStateId(), lsa2);
@@ -201,7 +194,7 @@
                           "The Ipv4Address is not stored as the link state ID");
 
     // next, calculate routes based on the manually created LSDB
-    GlobalRouteManagerImpl* srm = new GlobalRouteManagerImpl();
+    auto srm = new GlobalRouteManagerImpl();
     srm->DebugUseLsdb(srmlsdb); // manually add in an LSDB
     // Note-- this will succeed without any nodes in the topology
     // because the NodeList is empty
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/icmp-test.cc ns-3.40/src/internet/test/icmp-test.cc
--- ns-3.39/src/internet/test/icmp-test.cc	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/test/icmp-test.cc	2023-09-27 13:30:37.666839100 -0700
@@ -399,7 +399,7 @@
 IcmpV6EchoReplyTestCase::SendData(Ptr<Socket> socket, Ipv6Address dst)
 {
     Ptr<Packet> p = Create<Packet>();
-    Icmpv6Echo echo(1);
+    Icmpv6Echo echo(true);
     echo.SetSeq(1);
     echo.SetId(0XB1ED);
     p->AddHeader(echo);
@@ -537,7 +537,7 @@
 IcmpV6TimeExceedTestCase::SendData(Ptr<Socket> socket, Ipv6Address dst)
 {
     Ptr<Packet> p = Create<Packet>();
-    Icmpv6Echo echo(1);
+    Icmpv6Echo echo(true);
     echo.SetSeq(1);
     echo.SetId(0XB1ED);
     p->AddHeader(echo);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/ipv4-address-generator-test-suite.cc ns-3.40/src/internet/test/ipv4-address-generator-test-suite.cc
--- ns-3.39/src/internet/test/ipv4-address-generator-test-suite.cc	2023-07-05 14:23:47.861427500 -0700
+++ ns-3.40/src/internet/test/ipv4-address-generator-test-suite.cc	2023-09-27 13:30:37.666839100 -0700
@@ -323,18 +323,28 @@
     Ipv4AddressGenerator::AddAllocated("0.0.0.16");
 
     Ipv4AddressGenerator::TestMode();
+    bool allocated = Ipv4AddressGenerator::IsAddressAllocated("0.0.0.21");
+    NS_TEST_EXPECT_MSG_EQ(allocated, false, "0.0.0.21 should not be already allocated");
     bool added = Ipv4AddressGenerator::AddAllocated("0.0.0.21");
     NS_TEST_EXPECT_MSG_EQ(added, true, "400");
 
+    allocated = Ipv4AddressGenerator::IsAddressAllocated("0.0.0.4");
+    NS_TEST_EXPECT_MSG_EQ(allocated, true, "0.0.0.4 should be already allocated");
     added = Ipv4AddressGenerator::AddAllocated("0.0.0.4");
     NS_TEST_EXPECT_MSG_EQ(added, false, "401");
 
+    allocated = Ipv4AddressGenerator::IsAddressAllocated("0.0.0.9");
+    NS_TEST_EXPECT_MSG_EQ(allocated, true, "0.0.0.9 should be already allocated");
     added = Ipv4AddressGenerator::AddAllocated("0.0.0.9");
     NS_TEST_EXPECT_MSG_EQ(added, false, "402");
 
+    allocated = Ipv4AddressGenerator::IsAddressAllocated("0.0.0.16");
+    NS_TEST_EXPECT_MSG_EQ(allocated, true, "0.0.0.16 should be already allocated");
     added = Ipv4AddressGenerator::AddAllocated("0.0.0.16");
     NS_TEST_EXPECT_MSG_EQ(added, false, "403");
 
+    allocated = Ipv4AddressGenerator::IsAddressAllocated("0.0.0.21");
+    NS_TEST_EXPECT_MSG_EQ(allocated, true, "0.0.0.21 should be already allocated");
     added = Ipv4AddressGenerator::AddAllocated("0.0.0.21");
     NS_TEST_EXPECT_MSG_EQ(added, false, "404");
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/ipv4-global-routing-test-suite.cc ns-3.40/src/internet/test/ipv4-global-routing-test-suite.cc
--- ns-3.39/src/internet/test/ipv4-global-routing-test-suite.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/ipv4-global-routing-test-suite.cc	2023-09-27 13:30:37.666839100 -0700
@@ -894,9 +894,7 @@
 
 Ipv4DynamicGlobalRoutingTestCase::~Ipv4DynamicGlobalRoutingTestCase()
 {
-    std::vector<std::pair<Ptr<Socket>, bool>>::iterator iter;
-
-    for (iter = m_sendSocks.begin(); iter != m_sendSocks.end(); iter++)
+    for (auto iter = m_sendSocks.begin(); iter != m_sendSocks.end(); iter++)
     {
         if (iter->second)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/ipv4-rip-test.cc ns-3.40/src/internet/test/ipv4-rip-test.cc
--- ns-3.39/src/internet/test/ipv4-rip-test.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/ipv4-rip-test.cc	2023-09-27 13:30:37.666839100 -0700
@@ -558,7 +558,7 @@
         std::list<RipRte> rtes = hdr.GetRteList();
 
         // validate the RTEs before processing
-        for (std::list<RipRte>::iterator iter = rtes.begin(); iter != rtes.end(); iter++)
+        for (auto iter = rtes.begin(); iter != rtes.end(); iter++)
         {
             if (iter->GetPrefix() == "10.0.1.0")
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/ipv6-address-generator-test-suite.cc ns-3.40/src/internet/test/ipv6-address-generator-test-suite.cc
--- ns-3.39/src/internet/test/ipv6-address-generator-test-suite.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/ipv6-address-generator-test-suite.cc	2023-09-27 13:30:37.666839100 -0700
@@ -315,18 +315,28 @@
     Ipv6AddressGenerator::AddAllocated("0::0:16");
 
     Ipv6AddressGenerator::TestMode();
+    bool allocated = Ipv6AddressGenerator::IsAddressAllocated("0::0:21");
+    NS_TEST_EXPECT_MSG_EQ(allocated, false, "0::0:21 should not be already allocated");
     bool added = Ipv6AddressGenerator::AddAllocated("0::0:21");
     NS_TEST_EXPECT_MSG_EQ(added, true, "address should get allocated");
 
+    allocated = Ipv6AddressGenerator::IsAddressAllocated("0::0:4");
+    NS_TEST_EXPECT_MSG_EQ(allocated, true, "0::0:4 should be already allocated");
     added = Ipv6AddressGenerator::AddAllocated("0::0:4");
     NS_TEST_EXPECT_MSG_EQ(added, false, "address should not get allocated");
 
+    allocated = Ipv6AddressGenerator::IsAddressAllocated("0::0:9");
+    NS_TEST_EXPECT_MSG_EQ(allocated, true, "0::0:9 should be already allocated");
     added = Ipv6AddressGenerator::AddAllocated("0::0:9");
     NS_TEST_EXPECT_MSG_EQ(added, false, "address should not get allocated");
 
+    allocated = Ipv6AddressGenerator::IsAddressAllocated("0::0:16");
+    NS_TEST_EXPECT_MSG_EQ(allocated, true, "0::0:16 should be already allocated");
     added = Ipv6AddressGenerator::AddAllocated("0::0:16");
     NS_TEST_EXPECT_MSG_EQ(added, false, "address should not get allocated");
 
+    allocated = Ipv6AddressGenerator::IsAddressAllocated("0::0:21");
+    NS_TEST_EXPECT_MSG_EQ(allocated, true, "0::0:21 should be already allocated");
     added = Ipv6AddressGenerator::AddAllocated("0::0:21");
     NS_TEST_EXPECT_MSG_EQ(added, false, "address should not get allocated");
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/ipv6-ripng-test.cc ns-3.40/src/internet/test/ipv6-ripng-test.cc
--- ns-3.39/src/internet/test/ipv6-ripng-test.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/ipv6-ripng-test.cc	2023-09-27 13:30:37.666839100 -0700
@@ -556,7 +556,7 @@
         std::list<RipNgRte> rtes = hdr.GetRteList();
 
         // validate the RTEs before processing
-        for (std::list<RipNgRte>::iterator iter = rtes.begin(); iter != rtes.end(); iter++)
+        for (auto iter = rtes.begin(); iter != rtes.end(); iter++)
         {
             if (iter->GetPrefix() == "2001:1::")
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/tcp-advertised-window-test.cc ns-3.40/src/internet/test/tcp-advertised-window-test.cc
--- ns-3.39/src/internet/test/tcp-advertised-window-test.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/tcp-advertised-window-test.cc	2023-09-27 13:30:37.666839100 -0700
@@ -447,7 +447,7 @@
 TcpAdvWindowOnLossTest::CreateReceiverErrorModel()
 {
     Ptr<TcpSeqErrorModel> m_errorModel = CreateObject<TcpSeqErrorModel>();
-    for (std::vector<uint32_t>::iterator it = m_toDrop.begin(); it != m_toDrop.end(); ++it)
+    for (auto it = m_toDrop.begin(); it != m_toDrop.end(); ++it)
     {
         m_errorModel->AddSeqToKill(SequenceNumber32(*it));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/tcp-bytes-in-flight-test.cc ns-3.40/src/internet/test/tcp-bytes-in-flight-test.cc
--- ns-3.39/src/internet/test/tcp-bytes-in-flight-test.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/tcp-bytes-in-flight-test.cc	2023-09-27 13:30:37.666839100 -0700
@@ -141,7 +141,7 @@
 TcpBytesInFlightTest::CreateReceiverErrorModel()
 {
     Ptr<TcpSeqErrorModel> m_errorModel = CreateObject<TcpSeqErrorModel>();
-    for (std::vector<uint32_t>::iterator it = m_toDrop.begin(); it != m_toDrop.end(); ++it)
+    for (auto it = m_toDrop.begin(); it != m_toDrop.end(); ++it)
     {
         m_errorModel->AddSeqToKill(SequenceNumber32(*it));
     }
@@ -236,7 +236,7 @@
 {
     if (who == SENDER)
     {
-        static SequenceNumber32 retr = SequenceNumber32(0);
+        static SequenceNumber32 retr(0);
         static uint32_t times = 0;
 
         if (m_greatestSeqSent <= h.GetSequenceNumber())
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/tcp-fast-retr-test.cc ns-3.40/src/internet/test/tcp-fast-retr-test.cc
--- ns-3.39/src/internet/test/tcp-fast-retr-test.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/tcp-fast-retr-test.cc	2023-09-27 13:30:37.666839100 -0700
@@ -443,7 +443,7 @@
         types.insert(types.begin(), TcpWestwoodPlus::GetTypeId());
         types.insert(types.begin(), TcpNewReno::GetTypeId());
 
-        for (std::list<TypeId>::iterator it = types.begin(); it != types.end(); ++it)
+        for (auto it = types.begin(); it != types.end(); ++it)
         {
             AddTestCase(new TcpFastRetrTest((*it), 5001, "Fast Retransmit testing"),
                         TestCase::QUICK);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/tcp-rate-ops-test.cc ns-3.40/src/internet/test/tcp-rate-ops-test.cc
--- ns-3.39/src/internet/test/tcp-rate-ops-test.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/tcp-rate-ops-test.cc	2023-09-27 13:30:37.670839000 -0700
@@ -343,7 +343,7 @@
 TcpRateLinuxWithSocketsTest::CreateReceiverErrorModel()
 {
     Ptr<TcpSeqErrorModel> m_errorModel = CreateObject<TcpSeqErrorModel>();
-    for (std::vector<uint32_t>::iterator it = m_toDrop.begin(); it != m_toDrop.end(); ++it)
+    for (auto it = m_toDrop.begin(); it != m_toDrop.end(); ++it)
     {
         m_errorModel->AddSeqToKill(SequenceNumber32(*it));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/tcp-rtt-estimation.cc ns-3.40/src/internet/test/tcp-rtt-estimation.cc
--- ns-3.39/src/internet/test/tcp-rtt-estimation.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/tcp-rtt-estimation.cc	2023-09-27 13:30:37.670839000 -0700
@@ -232,9 +232,7 @@
 {
     Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel>();
 
-    std::vector<uint32_t>::iterator it;
-
-    for (it = m_toDrop.begin(); it != m_toDrop.end(); ++it)
+    for (auto it = m_toDrop.begin(); it != m_toDrop.end(); ++it)
     {
         errorModel->AddSeqToKill(SequenceNumber32((*it)));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/tcp-rx-buffer-test.cc ns-3.40/src/internet/test/tcp-rx-buffer-test.cc
--- ns-3.39/src/internet/test/tcp-rx-buffer-test.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/tcp-rx-buffer-test.cc	2023-09-27 13:30:37.670839000 -0700
@@ -60,7 +60,6 @@
 {
     TcpRxBuffer rxBuf;
     TcpOptionSack::SackList sackList;
-    TcpOptionSack::SackList::iterator it;
     Ptr<Packet> p = Create<Packet>(100);
     TcpHeader h;
 
@@ -83,7 +82,7 @@
                           "Sequence number differs from expected");
     sackList = rxBuf.GetSackList();
     NS_TEST_ASSERT_MSG_EQ(sackList.size(), 1, "SACK list should contain one element");
-    it = sackList.begin();
+    auto it = sackList.begin();
     NS_TEST_ASSERT_MSG_EQ(it->first, SequenceNumber32(501), "SACK block different than expected");
     NS_TEST_ASSERT_MSG_EQ(it->second, SequenceNumber32(601), "SACK block different than expected");
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet/test/tcp-test.cc ns-3.40/src/internet/test/tcp-test.cc
--- ns-3.39/src/internet/test/tcp-test.cc	2023-07-05 14:23:47.865427500 -0700
+++ ns-3.40/src/internet/test/tcp-test.cc	2023-09-27 13:30:37.670839000 -0700
@@ -220,7 +220,7 @@
     m_serverRxPayload = new uint8_t[m_totalBytes];
     for (uint32_t i = 0; i < m_totalBytes; ++i)
     {
-        uint8_t m = (uint8_t)(97 + (i % 26));
+        auto m = (uint8_t)(97 + (i % 26));
         m_sourceTxPayload[i] = m;
     }
     memset(m_sourceRxPayload, 0, m_totalBytes);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/examples/ping-example.cc ns-3.40/src/internet-apps/examples/ping-example.cc
--- ns-3.39/src/internet-apps/examples/ping-example.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/internet-apps/examples/ping-example.cc	2023-09-27 13:30:37.646839100 -0700
@@ -115,8 +115,8 @@
 
     if (!destinationStr.empty())
     {
-        Ipv4Address v4Dst = Ipv4Address(destinationStr.c_str());
-        Ipv6Address v6Dst = Ipv6Address(destinationStr.c_str());
+        Ipv4Address v4Dst(destinationStr.c_str());
+        Ipv6Address v6Dst(destinationStr.c_str());
         if (v4Dst.IsInitialized())
         {
             useIpv6 = false;
@@ -131,8 +131,8 @@
 
     if (!sourceStr.empty())
     {
-        Ipv4Address v4Src = Ipv4Address(sourceStr.c_str());
-        Ipv6Address v6Src = Ipv6Address(sourceStr.c_str());
+        Ipv4Address v4Src(sourceStr.c_str());
+        Ipv6Address v6Src(sourceStr.c_str());
         if (v4Src.IsInitialized())
         {
             source = v4Src;
@@ -157,7 +157,7 @@
         }
         else
         {
-            Ipv4Address v4Dst = Ipv4Address(destinationStr.c_str());
+            Ipv4Address v4Dst(destinationStr.c_str());
             if (v4Dst.IsInitialized() && (v4Dst.IsBroadcast() || v4Dst.IsMulticast()))
             {
                 std::cout << "Specify a source address to use when pinging broadcast or multicast "
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/helper/dhcp-helper.cc ns-3.40/src/internet-apps/helper/dhcp-helper.cc
--- ns-3.39/src/internet-apps/helper/dhcp-helper.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/internet-apps/helper/dhcp-helper.cc	2023-09-27 13:30:37.646839100 -0700
@@ -67,7 +67,7 @@
 DhcpHelper::InstallDhcpClient(NetDeviceContainer netDevices) const
 {
     ApplicationContainer apps;
-    for (NetDeviceContainer::Iterator i = netDevices.Begin(); i != netDevices.End(); ++i)
+    for (auto i = netDevices.Begin(); i != netDevices.End(); ++i)
     {
         apps.Add(InstallDhcpClientPriv(*i));
     }
@@ -184,8 +184,7 @@
     }
 
     // check that the already fixed addresses are not in conflict with the pool
-    std::list<Ipv4Address>::iterator iter;
-    for (iter = m_fixedAddresses.begin(); iter != m_fixedAddresses.end(); iter++)
+    for (auto iter = m_fixedAddresses.begin(); iter != m_fixedAddresses.end(); iter++)
     {
         if (iter->Get() >= minAddr.Get() && iter->Get() <= maxAddr.Get())
         {
@@ -250,8 +249,7 @@
     }
 
     // check that the already fixed addresses are not in conflict with the pool
-    std::list<std::pair<Ipv4Address, Ipv4Address>>::iterator iter;
-    for (iter = m_addressPools.begin(); iter != m_addressPools.end(); iter++)
+    for (auto iter = m_addressPools.begin(); iter != m_addressPools.end(); iter++)
     {
         if (addr.Get() >= iter->first.Get() && addr.Get() <= iter->second.Get())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/helper/ping6-helper.cc ns-3.40/src/internet-apps/helper/ping6-helper.cc
--- ns-3.39/src/internet-apps/helper/ping6-helper.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/internet-apps/helper/ping6-helper.cc	2023-09-27 13:30:37.646839100 -0700
@@ -59,7 +59,7 @@
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<Ping6> client = m_factory.Create<Ping6>();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/helper/ping-helper.cc ns-3.40/src/internet-apps/helper/ping-helper.cc
--- ns-3.39/src/internet-apps/helper/ping-helper.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/internet-apps/helper/ping-helper.cc	2023-09-27 13:30:37.646839100 -0700
@@ -65,7 +65,7 @@
 PingHelper::Install(NodeContainer c) const
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         apps.Add(InstallPriv(*i));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/helper/radvd-helper.cc ns-3.40/src/internet-apps/helper/radvd-helper.cc
--- ns-3.39/src/internet-apps/helper/radvd-helper.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/internet-apps/helper/radvd-helper.cc	2023-09-27 13:30:37.646839100 -0700
@@ -120,8 +120,7 @@
 {
     ApplicationContainer apps;
     Ptr<Radvd> radvd = m_factory.Create<Radvd>();
-    for (RadvdInterfaceMapI iter = m_radvdInterfaces.begin(); iter != m_radvdInterfaces.end();
-         iter++)
+    for (auto iter = m_radvdInterfaces.begin(); iter != m_radvdInterfaces.end(); iter++)
     {
         if (!iter->second->GetPrefixes().empty())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/helper/v4ping-helper.cc ns-3.40/src/internet-apps/helper/v4ping-helper.cc
--- ns-3.39/src/internet-apps/helper/v4ping-helper.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/internet-apps/helper/v4ping-helper.cc	2023-09-27 13:30:37.646839100 -0700
@@ -57,7 +57,7 @@
 V4PingHelper::Install(NodeContainer c) const
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         apps.Add(InstallPriv(*i));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/helper/v4traceroute-helper.cc ns-3.40/src/internet-apps/helper/v4traceroute-helper.cc
--- ns-3.39/src/internet-apps/helper/v4traceroute-helper.cc	2023-07-05 14:23:47.825427300 -0700
+++ ns-3.40/src/internet-apps/helper/v4traceroute-helper.cc	2023-09-27 13:30:37.646839100 -0700
@@ -56,7 +56,7 @@
 V4TraceRouteHelper::Install(NodeContainer c) const
 {
     ApplicationContainer apps;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         apps.Add(InstallPriv(*i));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/model/dhcp-header.cc ns-3.40/src/internet-apps/model/dhcp-header.cc
--- ns-3.39/src/internet-apps/model/dhcp-header.cc	2023-07-05 14:23:47.829427500 -0700
+++ ns-3.40/src/internet-apps/model/dhcp-header.cc	2023-09-27 13:30:37.646839100 -0700
@@ -42,7 +42,7 @@
     m_secs = 0;
     m_hops = 0;
     m_flags = 0;
-    Ipv4Address addr = Ipv4Address("0.0.0.0");
+    Ipv4Address addr("0.0.0.0");
     m_yiAddr = addr;
     m_ciAddr = addr;
     m_siAddr = addr;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/model/dhcp-server.cc ns-3.40/src/internet-apps/model/dhcp-server.cc
--- ns-3.39/src/internet-apps/model/dhcp-server.cc	2023-07-05 14:23:47.829427500 -0700
+++ ns-3.40/src/internet-apps/model/dhcp-server.cc	2023-09-27 13:30:37.646839100 -0700
@@ -160,7 +160,7 @@
     uint32_t range = m_maxAddress.Get() - m_minAddress.Get() + 1;
     for (uint32_t searchSeq = 0; searchSeq < range; searchSeq++)
     {
-        Ipv4Address poolAddress = Ipv4Address(m_minAddress.Get() + searchSeq);
+        Ipv4Address poolAddress(m_minAddress.Get() + searchSeq);
         if (poolAddress != myOwnAddress)
         {
             NS_LOG_LOGIC("Adding " << poolAddress << " to the pool");
@@ -259,7 +259,7 @@
 
     NS_LOG_INFO("DHCP DISCOVER from: " << from.GetIpv4() << " source port: " << from.GetPort());
 
-    LeasedAddressIter iter = m_leasedAddresses.find(sourceChaddr);
+    auto iter = m_leasedAddresses.find(sourceChaddr);
     if (iter != m_leasedAddresses.end())
     {
         // We know this client from some time ago
@@ -425,8 +425,7 @@
     NS_ASSERT_MSG(m_leasedAddresses.find(cleanedCaddr) == m_leasedAddresses.end(),
                   "Client has already an active lease: " << m_leasedAddresses[cleanedCaddr].first);
 
-    AvailableAddress::iterator it =
-        find(m_availableAddresses.begin(), m_availableAddresses.end(), addr);
+    auto it = find(m_availableAddresses.begin(), m_availableAddresses.end(), addr);
     NS_ASSERT_MSG(
         it == m_availableAddresses.end(),
         "Required address is not available (perhaps it has been already assigned): " << addr);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/model/ping6.cc ns-3.40/src/internet-apps/model/ping6.cc
--- ns-3.39/src/internet-apps/model/ping6.cc	2023-07-05 14:23:47.829427500 -0700
+++ ns-3.40/src/internet-apps/model/ping6.cc	2023-09-27 13:30:37.646839100 -0700
@@ -210,7 +210,7 @@
         size = 4;
     }
 
-    uint8_t* data = new uint8_t[size];
+    auto data = new uint8_t[size];
     memset(data, 0, size);
     data[0] = 0xDE;
     data[1] = 0xAD;
@@ -218,7 +218,7 @@
     data[3] = 0xEF;
 
     Ptr<Packet> p = Create<Packet>(data, size);
-    Icmpv6Echo req(1);
+    Icmpv6Echo req(true);
 
     req.SetId(0xBEEF);
     req.SetSeq(m_seq);
@@ -268,7 +268,7 @@
         if (Inet6SocketAddress::IsMatchingType(from))
         {
             Ipv6Header hdr;
-            Icmpv6Echo reply(0);
+            Icmpv6Echo reply(false);
             Icmpv6DestinationUnreachable destUnreach;
             Icmpv6TimeExceeded timeExceeded;
             Inet6SocketAddress address = Inet6SocketAddress::ConvertFrom(from);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/model/ping.cc ns-3.40/src/internet-apps/model/ping.cc
--- ns-3.39/src/internet-apps/model/ping.cc	2023-07-05 14:23:47.829427500 -0700
+++ ns-3.40/src/internet-apps/model/ping.cc	2023-09-27 13:30:37.646839100 -0700
@@ -206,7 +206,7 @@
                     NS_LOG_INFO("Packet too short, discarding");
                     return;
                 }
-                uint8_t* buf = new uint8_t[dataSize];
+                auto buf = new uint8_t[dataSize];
                 echo.GetData(buf);
                 uint64_t appSignature = Read64(buf);
                 delete[] buf;
@@ -286,7 +286,7 @@
             switch (type)
             {
             case Icmpv6Header::ICMPV6_ECHO_REPLY: {
-                Icmpv6Echo echo(0);
+                Icmpv6Echo echo(false);
                 packet->RemoveHeader(echo);
 
                 if (echo.GetId() != PING_ID)
@@ -305,7 +305,7 @@
                     NS_LOG_INFO("Packet too short, discarding");
                     return;
                 }
-                uint8_t* buf = new uint8_t[dataSize];
+                auto buf = new uint8_t[dataSize];
                 packet->CopyData(buf, dataSize);
                 uint64_t appSignature = Read64(buf);
                 delete[] buf;
@@ -426,7 +426,7 @@
     // (where any difference would show up anyway) and borrow that code.  Don't
     // be too surprised when you see that this is a little endian convention.
     //
-    uint8_t* data = new uint8_t[m_size];
+    auto data = new uint8_t[m_size];
     memset(data, 0, m_size);
     NS_ASSERT_MSG(m_size >= 16, "ECHO Payload size must be at least 16 bytes");
 
@@ -583,8 +583,7 @@
     {
         if (Ipv4Address::IsMatchingType(m_interfaceAddress))
         {
-            InetSocketAddress senderInet =
-                InetSocketAddress(Ipv4Address::ConvertFrom(m_interfaceAddress));
+            InetSocketAddress senderInet(Ipv4Address::ConvertFrom(m_interfaceAddress));
             int status = m_socket->Bind(senderInet);
             NS_ASSERT_MSG(status == 0, "Failed to bind IPv4 socket");
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/model/radvd.cc ns-3.40/src/internet-apps/model/radvd.cc
--- ns-3.39/src/internet-apps/model/radvd.cc	2023-07-05 14:23:47.829427500 -0700
+++ ns-3.40/src/internet-apps/model/radvd.cc	2023-09-27 13:30:37.650839000 -0700
@@ -75,7 +75,7 @@
 Radvd::~Radvd()
 {
     NS_LOG_FUNCTION(this);
-    for (RadvdInterfaceListI it = m_configurations.begin(); it != m_configurations.end(); ++it)
+    for (auto it = m_configurations.begin(); it != m_configurations.end(); ++it)
     {
         *it = nullptr;
     }
@@ -91,7 +91,7 @@
     m_recvSocket->Close();
     m_recvSocket = nullptr;
 
-    for (SocketMapI it = m_sendSockets.begin(); it != m_sendSockets.end(); ++it)
+    for (auto it = m_sendSockets.begin(); it != m_sendSockets.end(); ++it)
     {
         it->second->Close();
         it->second = nullptr;
@@ -120,7 +120,7 @@
         m_recvSocket->SetRecvPktInfo(true);
     }
 
-    for (RadvdInterfaceListCI it = m_configurations.begin(); it != m_configurations.end(); it++)
+    for (auto it = m_configurations.begin(); it != m_configurations.end(); it++)
     {
         if ((*it)->IsSendAdvert())
         {
@@ -159,13 +159,13 @@
         m_recvSocket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
     }
 
-    for (EventIdMapI it = m_unsolicitedEventIds.begin(); it != m_unsolicitedEventIds.end(); ++it)
+    for (auto it = m_unsolicitedEventIds.begin(); it != m_unsolicitedEventIds.end(); ++it)
     {
         Simulator::Cancel((*it).second);
     }
     m_unsolicitedEventIds.clear();
 
-    for (EventIdMapI it = m_solicitedEventIds.begin(); it != m_solicitedEventIds.end(); ++it)
+    for (auto it = m_solicitedEventIds.begin(); it != m_solicitedEventIds.end(); ++it)
     {
         Simulator::Cancel((*it).second);
     }
@@ -231,8 +231,7 @@
     }
 
     /* add list of prefixes */
-    for (std::list<Ptr<RadvdPrefix>>::const_iterator jt = prefixes.begin(); jt != prefixes.end();
-         jt++)
+    for (auto jt = prefixes.begin(); jt != prefixes.end(); jt++)
     {
         uint8_t flags = 0;
         prefixHdr = Icmpv6OptionPrefixInformation();
@@ -288,7 +287,7 @@
 
     if (reschedule)
     {
-        uint64_t delay = static_cast<uint64_t>(
+        auto delay = static_cast<uint64_t>(
             m_jitter->GetValue(config->GetMinRtrAdvInterval(), config->GetMaxRtrAdvInterval()) +
             0.5);
         if (config->IsInitialRtrAdv())
@@ -348,9 +347,7 @@
                 NS_LOG_INFO("Received ICMPv6 Router Solicitation from "
                             << hdr.GetSource() << " code = " << (uint32_t)rsHdr.GetCode());
 
-                for (RadvdInterfaceListCI it = m_configurations.begin();
-                     it != m_configurations.end();
-                     it++)
+                for (auto it = m_configurations.begin(); it != m_configurations.end(); it++)
                 {
                     if (ipInterfaceIndex == (*it)->GetInterface())
                     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/model/radvd-interface.cc ns-3.40/src/internet-apps/model/radvd-interface.cc
--- ns-3.39/src/internet-apps/model/radvd-interface.cc	2023-07-05 14:23:47.829427500 -0700
+++ ns-3.40/src/internet-apps/model/radvd-interface.cc	2023-09-27 13:30:37.646839100 -0700
@@ -86,7 +86,7 @@
 {
     NS_LOG_FUNCTION(this);
     /* clear prefixes */
-    for (RadvdPrefixListI it = m_prefixes.begin(); it != m_prefixes.end(); ++it)
+    for (auto it = m_prefixes.begin(); it != m_prefixes.end(); ++it)
     {
         (*it) = nullptr;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/model/v4ping.cc ns-3.40/src/internet-apps/model/v4ping.cc
--- ns-3.39/src/internet-apps/model/v4ping.cc	2023-07-05 14:23:47.829427500 -0700
+++ ns-3.40/src/internet-apps/model/v4ping.cc	2023-09-27 13:30:37.650839000 -0700
@@ -137,11 +137,11 @@
         {
             Icmpv4Echo echo;
             p->RemoveHeader(echo);
-            std::map<uint16_t, Time>::iterator i = m_sent.find(echo.GetSequenceNumber());
+            auto i = m_sent.find(echo.GetSequenceNumber());
 
             if (i != m_sent.end() && echo.GetIdentifier() == 0)
             {
-                uint32_t* buf = new uint32_t[m_size];
+                auto buf = new uint32_t[m_size];
                 uint32_t dataSize = echo.GetDataSize();
                 uint32_t nodeId;
                 uint32_t appId;
@@ -215,7 +215,7 @@
     // (where any difference would show up anyway) and borrow that code.  Don't
     // be too surprised when you see that this is a little endian convention.
     //
-    uint8_t* data = new uint8_t[m_size];
+    auto data = new uint8_t[m_size];
     for (uint32_t i = 0; i < m_size; ++i)
     {
         data[i] = 0;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/model/v4traceroute.cc ns-3.40/src/internet-apps/model/v4traceroute.cc
--- ns-3.39/src/internet-apps/model/v4traceroute.cc	2023-07-05 14:23:47.829427500 -0700
+++ ns-3.40/src/internet-apps/model/v4traceroute.cc	2023-09-27 13:30:37.650839000 -0700
@@ -243,7 +243,7 @@
             recvSeq = (uint16_t)data[7] << 0;
             recvSeq |= (uint16_t)data[6] << 8;
 
-            std::map<uint16_t, Time>::iterator i = m_sent.find(recvSeq);
+            auto i = m_sent.find(recvSeq);
             if (i != m_sent.end())
             {
                 Time sendTime = i->second;
@@ -296,7 +296,7 @@
 
             Icmpv4Echo echo;
             p->RemoveHeader(echo);
-            std::map<uint16_t, Time>::iterator i = m_sent.find(echo.GetSequenceNumber());
+            auto i = m_sent.find(echo.GetSequenceNumber());
 
             if (i != m_sent.end() && echo.GetIdentifier() == 0)
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/internet-apps/test/ping-test.cc ns-3.40/src/internet-apps/test/ping-test.cc
--- ns-3.39/src/internet-apps/test/ping-test.cc	2023-07-05 14:23:47.829427500 -0700
+++ ns-3.40/src/internet-apps/test/ping-test.cc	2023-09-27 13:30:37.650839000 -0700
@@ -576,7 +576,7 @@
     //                        number sent equals number received, which equals 5.
     //    How validated:  PingReport trace is checked for number of packets
     //                    transmitted and received (5), and number of drops (0).
-    PingTestCase* testcase1v4 = new PingTestCase(
+    auto testcase1v4 = new PingTestCase(
         "1. Unlimited pings, no losses, StopApplication () with no packets in flight IPv4",
         USEIPV6_FALSE);
     testcase1v4->SetStartTime(Seconds(1));
@@ -588,7 +588,7 @@
     testcase1v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
     AddTestCase(testcase1v4, TestCase::QUICK);
 
-    PingTestCase* testcase1v6 = new PingTestCase(
+    auto testcase1v6 = new PingTestCase(
         "1. Unlimited pings, no losses, StopApplication () with no packets in flight IPv6",
         USEIPV6_TRUE);
     testcase1v6->SetStartTime(Seconds(1));
@@ -608,7 +608,7 @@
     //                     to be lost
     // How validated:  PingReport trace is checked for number of packets
     //                 transmitted (1) and received (0), and number of drops (0)
-    PingTestCase* testcase2v4 = new PingTestCase(
+    auto testcase2v4 = new PingTestCase(
         "2. Unlimited pings, no losses, StopApplication () with 1 packet in flight IPv4",
         USEIPV6_FALSE);
     testcase2v4->SetStartTime(Seconds(1));
@@ -619,7 +619,7 @@
     testcase1v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
     AddTestCase(testcase2v4, TestCase::QUICK);
 
-    PingTestCase* testcase2v6 = new PingTestCase(
+    auto testcase2v6 = new PingTestCase(
         "2. Unlimited pings, no losses, StopApplication () with 1 packet in flight IPv6",
         USEIPV6_TRUE);
     testcase2v6->SetStartTime(Seconds(1));
@@ -645,10 +645,9 @@
     //                 Report time will be MicroSeconds (2020001).
     uint32_t count = 2;
     uint32_t expectedTx = 2;
-    PingTestCase* testcase3v4 =
-        new PingTestCase("3. Test for operation of count attribute and exit "
-                         "time after all pings were received, IPv4",
-                         USEIPV6_FALSE);
+    auto testcase3v4 = new PingTestCase("3. Test for operation of count attribute and exit "
+                                        "time after all pings were received, IPv4",
+                                        USEIPV6_FALSE);
     testcase3v4->SetStartTime(Seconds(1));
     testcase3v4->SetStopTime(Seconds(5));
     testcase3v4->SetCount(count);
@@ -660,10 +659,9 @@
     testcase3v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
     AddTestCase(testcase3v4, TestCase::QUICK);
 
-    PingTestCase* testcase3v6 =
-        new PingTestCase("3. Test for operation of count attribute and exit "
-                         "time after all pings were received, IPv6",
-                         USEIPV6_TRUE);
+    auto testcase3v6 = new PingTestCase("3. Test for operation of count attribute and exit "
+                                        "time after all pings were received, IPv6",
+                                        USEIPV6_TRUE);
     testcase3v6->SetStartTime(Seconds(1));
     testcase3v6->SetStopTime(Seconds(5));
     testcase3v6->SetCount(count);
@@ -685,7 +683,7 @@
     // How validated:  PingReport trace is checked for number of packets
     //                 transmitted (2) and received (2), and number of drops (0)
     Time interval = Seconds(3.0);
-    PingTestCase* testcase4v4 =
+    auto testcase4v4 =
         new PingTestCase("4. Test for the operation of interval attribute for IPv4", USEIPV6_FALSE);
     testcase4v4->SetStartTime(Seconds(1));
     testcase4v4->SetStopTime(Seconds(5));
@@ -696,7 +694,7 @@
     testcase4v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
     AddTestCase(testcase4v4, TestCase::QUICK);
 
-    PingTestCase* testcase4v6 =
+    auto testcase4v6 =
         new PingTestCase("4. Test for the operation of interval attribute for IPv6", USEIPV6_TRUE);
     testcase4v6->SetStartTime(Seconds(1));
     testcase4v6->SetStopTime(Seconds(5));
@@ -724,7 +722,7 @@
     // How validated:  PingReport trace is checked for number of packets
     //                 transmitted (5) and  received (0).
     //                 The packet loss rate should be checked to be 100 percent
-    PingTestCase* testcase5v4 =
+    auto testcase5v4 =
         new PingTestCase("5. Test for behavior of ping to unreachable IPv4 address", USEIPV6_FALSE);
     testcase5v4->SetStartTime(Seconds(1));
     testcase5v4->SetStopTime(Seconds(5.5));
@@ -734,7 +732,7 @@
     testcase5v4->CheckReportLoss(100);
     AddTestCase(testcase5v4, TestCase::QUICK);
 
-    PingTestCase* testcase5v6 =
+    auto testcase5v6 =
         new PingTestCase("5. Test for behavior of ping to unreachable IPv6 address", USEIPV6_TRUE);
     testcase5v6->SetStartTime(Seconds(1));
     testcase5v6->SetStopTime(Seconds(5.5));
@@ -757,7 +755,7 @@
     // How validated:  PingReport trace is checked for number of packets
     //                 transmitted (2) and received (2),number of drops (0),
     //                 Report time will be MicroSeconds (2020001).
-    PingTestCase* testcase6v4 =
+    auto testcase6v4 =
         new PingTestCase("6. Test for behavior of ping to broadcast IPv4 address", USEIPV6_FALSE);
     testcase6v4->SetStartTime(Seconds(1));
     testcase6v4->SetStopTime(Seconds(5.5));
@@ -767,7 +765,7 @@
     testcase6v4->CheckReportLoss(0);
     AddTestCase(testcase6v4, TestCase::QUICK);
 
-    PingTestCase* testcase6v6 =
+    auto testcase6v6 =
         new PingTestCase("6. Test for behavior of ping to all-nodes multicast IPv6 address",
                          USEIPV6_TRUE);
     testcase6v6->SetStartTime(Seconds(1));
@@ -791,7 +789,7 @@
     //                 transmitted (3) and received (2), loss percentage (33).
     //                 Ping Tx trace (3) and Rtt trace (2) are also checked.
     //                 Report time will be MicroSeconds (3040000).
-    PingTestCase* testcase7v4 = new PingTestCase(
+    auto testcase7v4 = new PingTestCase(
         "7. Test behavior of first reply lost in a count-limited configuration, IPv4",
         USEIPV6_FALSE);
     std::list<uint32_t> dropList{0};
@@ -807,7 +805,7 @@
     testcase7v4->CheckReportTime(MicroSeconds(3040000));
     AddTestCase(testcase7v4, TestCase::QUICK);
 
-    PingTestCase* testcase7v6 = new PingTestCase(
+    auto testcase7v6 = new PingTestCase(
         "7. Test behavior of first reply lost in a count-limited configuration, IPv6",
         USEIPV6_TRUE);
     testcase7v6->SetDropList(dropList);
@@ -836,7 +834,7 @@
     //                 transmitted (3) and received (2), loss percentage (33).
     //                 Ping Tx trace (3) and Rtt trace (2) are also checked.
     //                 Report time will be MicroSeconds (3040000).
-    PingTestCase* testcase8v4 = new PingTestCase(
+    auto testcase8v4 = new PingTestCase(
         "8. Test behavior of second reply lost in a count-limited configuration, IPv4",
         USEIPV6_FALSE);
     std::list<uint32_t> dropList2{1};
@@ -852,7 +850,7 @@
     testcase8v4->CheckReportTime(MicroSeconds(3040000));
     AddTestCase(testcase8v4, TestCase::QUICK);
 
-    PingTestCase* testcase8v6 = new PingTestCase(
+    auto testcase8v6 = new PingTestCase(
         "8. Test behavior of second reply lost in a count-limited configuration, IPv6",
         USEIPV6_TRUE);
     testcase8v6->SetDropList(dropList2);
@@ -881,7 +879,7 @@
     //                 transmitted (3) and received (2), loss percentage (33).
     //                 Ping Tx trace (3) and Rtt trace (2) are also checked.
     //                 Report time will be MicroSeconds (3040000).
-    PingTestCase* testcase9v4 = new PingTestCase(
+    auto testcase9v4 = new PingTestCase(
         "9. Test behavior of last reply lost in a count-limited configuration, IPv4",
         USEIPV6_FALSE);
     std::list<uint32_t> dropList3{2};
@@ -897,7 +895,7 @@
     testcase9v4->CheckReportTime(MicroSeconds(3040000));
     AddTestCase(testcase9v4, TestCase::QUICK);
 
-    PingTestCase* testcase9v6 = new PingTestCase(
+    auto testcase9v6 = new PingTestCase(
         "9. Test behavior of last reply lost in a count-limited configuration, IPv6",
         USEIPV6_TRUE);
     testcase9v6->SetDropList(dropList3);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/doc/lr-wpan.rst ns-3.40/src/lr-wpan/doc/lr-wpan.rst
--- ns-3.39/src/lr-wpan/doc/lr-wpan.rst	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/doc/lr-wpan.rst	2023-09-27 13:30:37.670839000 -0700
@@ -220,7 +220,10 @@
 have the effect to receive more packets (and at a greater distance) but it raises the probability to have dropped packets at the
 MAC layer or the probability of corrupted packets. By default, the receiver sensitivity is set to the maximum theoretical possible value of -106.58 dBm for the supported IEEE 802.15.4 O-QPSK 250kps.
 This rx sensitivity is set for the "perfect radio" which only considers the floor noise, in essence, this do not include the noise factor (noise introduced by imperfections in the demodulator chip or external factors).
-The receiver sensitivity can be changed to different values using ``SetRxSensitivity`` function in the PHY to simulate the hearing capabilities of different compliant radio transceivers (the standard minimum compliant Rx sensitivity is -85 dBm).:::
+The receiver sensitivity can be changed to different values using ``SetRxSensitivity`` function in the PHY to simulate the hearing capabilities of different compliant radio transceivers (the standard minimum compliant Rx sensitivity is -85 dBm).:
+
+::
+
                                                               (defined by the standard)
    NoiseFloor          Max Sensitivity                          Min Sensitivity
    -106.987dBm          -106.58dBm                                   -85dBm
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/examples/lr-wpan-bootstrap.cc ns-3.40/src/lr-wpan/examples/lr-wpan-bootstrap.cc
--- ns-3.39/src/lr-wpan/examples/lr-wpan-bootstrap.cc	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/examples/lr-wpan-bootstrap.cc	2023-09-27 13:30:37.670839000 -0700
@@ -381,7 +381,7 @@
     lrWpanHelper.SetExtendedAddresses(lrwpanDevices);
 
     // Devices hooks & MAC MLME-scan primitive set
-    for (NodeContainer::Iterator i = nodes.Begin(); i != nodes.End(); i++)
+    for (auto i = nodes.Begin(); i != nodes.End(); i++)
     {
         Ptr<Node> node = *i;
         Ptr<NetDevice> netDevice = node->GetDevice(0);
@@ -416,7 +416,7 @@
     }
 
     // Coordinator hooks
-    for (NodeContainer::Iterator i = coordinators.Begin(); i != coordinators.End(); i++)
+    for (auto i = coordinators.Begin(); i != coordinators.End(); i++)
     {
         Ptr<Node> coor = *i;
         Ptr<NetDevice> netDevice = coor->GetDevice(0);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/helper/lr-wpan-helper.cc ns-3.40/src/lr-wpan/helper/lr-wpan-helper.cc
--- ns-3.39/src/lr-wpan/helper/lr-wpan-helper.cc	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/helper/lr-wpan-helper.cc	2023-09-27 13:30:37.670839000 -0700
@@ -179,7 +179,7 @@
 LrWpanHelper::Install(NodeContainer c)
 {
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); i++)
+    for (auto i = c.Begin(); i != c.End(); i++)
     {
         Ptr<Node> node = *i;
 
@@ -218,7 +218,7 @@
 {
     int64_t currentStream = stream;
     Ptr<NetDevice> netDevice;
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         netDevice = (*i);
         Ptr<LrWpanNetDevice> lrwpan = DynamicCast<LrWpanNetDevice>(netDevice);
@@ -242,7 +242,7 @@
     Mac16Address coordShortAddr;
     Mac64Address coordExtAddr;
 
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); i++)
+    for (auto i = c.Begin(); i != c.End(); i++)
     {
         if (id < 0x0001 || id > 0xFFFD)
         {
@@ -285,7 +285,7 @@
     uint8_t idBuf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
     Mac64Address address64;
 
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); i++)
+    for (auto i = c.Begin(); i != c.End(); i++)
     {
         Ptr<LrWpanNetDevice> device = DynamicCast<LrWpanNetDevice>(*i);
         if (device)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/model/lr-wpan-csmaca.h ns-3.40/src/lr-wpan/model/lr-wpan-csmaca.h
--- ns-3.39/src/lr-wpan/model/lr-wpan-csmaca.h	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/model/lr-wpan-csmaca.h	2023-09-27 13:30:37.670839000 -0700
@@ -23,8 +23,9 @@
 #ifndef LR_WPAN_CSMACA_H
 #define LR_WPAN_CSMACA_H
 
+#include "lr-wpan-mac.h"
+
 #include <ns3/event-id.h>
-#include <ns3/lr-wpan-mac.h>
 #include <ns3/object.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/model/lr-wpan-fields.cc ns-3.40/src/lr-wpan/model/lr-wpan-fields.cc
--- ns-3.39/src/lr-wpan/model/lr-wpan-fields.cc	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/model/lr-wpan-fields.cc	2023-09-27 13:30:37.670839000 -0700
@@ -492,25 +492,49 @@
     m_allocAddr = true;
 }
 
-uint32_t
-CapabilityField::GetSerializedSize() const
+CapabilityField::CapabilityField(uint8_t bitmap)
 {
-    return 1;
+    SetCapability(bitmap);
 }
 
-Buffer::Iterator
-CapabilityField::Serialize(Buffer::Iterator i) const
+uint8_t
+CapabilityField::GetCapability() const
 {
     uint8_t capability;
 
-    capability = 0;                                          //!< Bit 0 (reserved)
-    capability = (m_deviceType << 1) & (0x01 << 1);          //!< Bit 1
+    capability = (m_reservedBit0) & (0x01);                  //!< Bit 0 (reserved)
+    capability |= (m_deviceType << 1) & (0x01 << 1);         //!< Bit 1
     capability |= (m_powerSource << 2) & (0x01 << 2);        //!< Bit 2
     capability |= (m_receiverOnWhenIdle << 3) & (0x01 << 3); //!< Bit 3
-                                                             //!< Bit 4-5 (reserved)
+    capability |= (m_reservedBit45 << 4) & (0x03 << 4);      //!< Bit 4-5 (reserved)
     capability |= (m_securityCap << 6) & (0x01 << 6);        //!< Bit 6
     capability |= (m_allocAddr << 7) & (0x01 << 7);          //!< Bit 7
-    i.WriteU8(capability);
+
+    return capability;
+}
+
+void
+CapabilityField::SetCapability(uint8_t bitmap)
+{
+    m_reservedBit0 = (bitmap) & (0x01);            //!< Bit 0 (reserved)
+    m_deviceType = (bitmap >> 1) & (0x01);         //!< Bit 1
+    m_powerSource = (bitmap >> 2) & (0x01);        //!< Bit 2
+    m_receiverOnWhenIdle = (bitmap >> 3) & (0x01); //!< Bit 3
+    m_reservedBit45 = (bitmap >> 4) & (0x03);      //!< Bit 4-5 (reserved)
+    m_securityCap = (bitmap >> 6) & (0x01);        //!< Bit 6
+    m_allocAddr = (bitmap >> 7) & (0x01);          //!< Bit 7
+}
+
+uint32_t
+CapabilityField::GetSerializedSize() const
+{
+    return 1;
+}
+
+Buffer::Iterator
+CapabilityField::Serialize(Buffer::Iterator i) const
+{
+    i.WriteU8(GetCapability());
     return i;
 }
 
@@ -518,14 +542,7 @@
 CapabilityField::Deserialize(Buffer::Iterator i)
 {
     uint8_t capability = i.ReadU8();
-    //!< Bit 0 (reserved)
-    m_deviceType = (capability >> 1) & (0x01);         //!< Bit 1
-    m_powerSource = (capability >> 2) & (0x01);        //!< Bit 2
-    m_receiverOnWhenIdle = (capability >> 3) & (0x01); //!< Bit 3
-                                                       //!< Bit 4-5 (reserved)
-    m_securityCap = (capability >> 6) & (0x01);        //!< Bit 6
-    m_allocAddr = (capability >> 7) & (0x01);          //!< Bit 7
-
+    SetCapability(capability);
     return i;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/model/lr-wpan-fields.h ns-3.40/src/lr-wpan/model/lr-wpan-fields.h
--- ns-3.39/src/lr-wpan/model/lr-wpan-fields.h	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/model/lr-wpan-fields.h	2023-09-27 13:30:37.670839000 -0700
@@ -355,88 +355,137 @@
 {
   public:
     CapabilityField();
+
+    /**
+     * Construct a Capability field based on a bitmap.
+     *
+     * \param bitmap The bitmap representing the capability
+     */
+    CapabilityField(uint8_t bitmap);
+
+    /**
+     * Get the bitmap representing the device capability.
+     *
+     * \return The bitmap representing the device capability.
+     */
+    uint8_t GetCapability() const;
+
+    /**
+     * Set the bitmap representing the device capability.
+     *
+     * \param bitmap The bitmap representing the capability
+     */
+    void SetCapability(uint8_t bitmap);
+
     /**
      * Get the size of the serialized Capability Information Field.
+     *
      * \return the size of the serialized field.
      */
     uint32_t GetSerializedSize() const;
+
     /**
      * Serialize the entire Capability Information Field.
+     *
      * \param i an iterator which points to where the Capability information field
      * should be written.
      * \return an iterator.
      */
     Buffer::Iterator Serialize(Buffer::Iterator i) const;
+
     /**
      * Deserialize the entire Capability Information Field.
+     *
      * \param i an iterator which points to where the Capability information field should be read.
      * \return an iterator.
      */
     Buffer::Iterator Deserialize(Buffer::Iterator i);
+
     /**
      * True if the device type is a Full Functional Device (FFD) false if is a Reduced Functional
      * Device (RFD).
+     *
      * \return True if the device type is a Full Functional Device (FFD) false if is a Reduced
      * Functional Device (RFD).
      */
     bool IsDeviceTypeFfd() const;
+
     /**
      * True if the device is receiving power from alternating current mains.
+     *
      * \return True if the device is receiving power from alternating current mains.
      */
     bool IsPowSrcAvailable() const;
+
     /**
      * True if the device does not disable its receiver to conserve power during idle periods.
+     *
      * \return True if the device does not disable its receiver to conserve power during idle
      * periods.
      */
     bool IsReceiverOnWhenIdle() const;
+
     /**
      * True if the device is capable of sending and receiving cryptographically protected MAC
      * frames.
+     *
      * \return True if the device is capable of sending and receiving cryptographically protected
      * MAC frames.
      */
     bool IsSecurityCapability() const;
+
     /**
      * True if the device wishes the coordinator to allocate a short address as result of the
      * association procedure.
+     *
      * \return True if the device wishes the coordinator to allocate a short address as result of
      * the association procedure.
      */
     bool IsShortAddrAllocOn() const;
+
     /**
      * Set the Device type in the Capability Information Field.
      * True = full functional device (FFD)  False = reduced functional device (RFD).
+     *
      * \param devType The device type described in the Capability Information Field.
      */
     void SetFfdDevice(bool devType);
+
     /**
      * Set the Power Source available flag in the Capability Information Field.
+     *
      * \param pow Set true if a Power Source is available in the Capability Information Field.
      */
     void SetPowSrcAvailable(bool pow);
+
     /**
      * Indicate if the receiver is On on Idle
+     *
      * \param rxIdle Set true if the receiver is on when Idle
      */
     void SetRxOnWhenIdle(bool rxIdle);
+
     /**
      * Set the Security Capability flag in the Capability Information Field.
+     *
      * \param sec Set true if the device have Security Capabilities.
      */
     void SetSecurityCap(bool sec);
+
     /**
      * Set the Short Address Flag in the Capability Information Field.
+     *
      * \param addrAlloc Describes whether or not the coordinator should allocate a short
      *                  address in the association process.
      */
     void SetShortAddrAllocOn(bool addrAlloc);
 
   private:
+    bool m_reservedBit0;       //!< Capability Information Field, Reserved (bit 0)
     bool m_deviceType;         //!< Capability Information Field, Device Type  (bit 1)
     bool m_powerSource;        //!< Capability Information Field, Power Source (bit 2)
     bool m_receiverOnWhenIdle; //!< Capability Information Field, Receiver On When Idle (bit 3)
+    uint8_t m_reservedBit45;   //!< Capability Information Field, Reserved (bit 4 & 5)
     bool m_securityCap;        //!< Capability Information Field, Security Capability (bit 6)
     bool m_allocAddr;          //!< Capability Information Field, Allocate Address (bit 7)
 };
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/model/lr-wpan-interference-helper.cc ns-3.40/src/lr-wpan/model/lr-wpan-interference-helper.cc
--- ns-3.39/src/lr-wpan/model/lr-wpan-interference-helper.cc	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/model/lr-wpan-interference-helper.cc	2023-09-27 13:30:37.670839000 -0700
@@ -95,9 +95,8 @@
     if (m_dirty)
     {
         // Sum up the current interference PSD.
-        std::set<Ptr<const SpectrumValue>>::const_iterator it;
         m_signal = Create<SpectrumValue>(m_spectrumModel);
-        for (it = m_signals.begin(); it != m_signals.end(); ++it)
+        for (auto it = m_signals.begin(); it != m_signals.end(); ++it)
         {
             *m_signal += *(*it);
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/model/lr-wpan-mac.cc ns-3.40/src/lr-wpan/model/lr-wpan-mac.cc
--- ns-3.39/src/lr-wpan/model/lr-wpan-mac.cc	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/model/lr-wpan-mac.cc	2023-09-27 13:30:37.674839300 -0700
@@ -183,6 +183,7 @@
     m_numCsmacaRetry = 0;
     m_txPkt = nullptr;
     m_rxPkt = nullptr;
+    m_lastRxFrameLqi = 0;
     m_ifs = 0;
 
     m_macLIFSPeriod = 40;
@@ -847,7 +848,7 @@
     NS_LOG_FUNCTION(this);
     NS_ASSERT(params.m_logCh <= 26 && m_macPanId != 0xffff);
 
-    uint64_t symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
+    auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
     // change phy current logical channel
     Ptr<LrWpanPhyPibAttributes> pibAttr = Create<LrWpanPhyPibAttributes>();
     pibAttr->phyCurrentChannel = params.m_logCh;
@@ -1659,7 +1660,7 @@
 void
 LrWpanMac::BeaconSearchTimeout()
 {
-    uint64_t symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
+    auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
 
     if (m_numLostBeacons > lrwpan::aMaxLostBeacons)
     {
@@ -1871,8 +1872,8 @@
     // srcPanId = m_macPanId if only srcAddr field in Data or Command frame,accept frame if
     // srcPanId=m_macPanId
 
-    Ptr<Packet> originalPkt = p->Copy(); // because we will strip headers
-    uint64_t symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
+    Ptr<Packet> originalPkt = p->Copy();                           // because we will strip headers
+    auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
     m_promiscSnifferTrace(originalPkt);
 
     m_macPromiscRxTrace(originalPkt);
@@ -1974,21 +1975,6 @@
                               (m_macPanId == 0xffff && receivedMacHdr.IsCommand());
             }
 
-            if (acceptFrame && (receivedMacHdr.GetShortDstAddr() == Mac16Address("FF:FF")))
-            {
-                // TODO: shouldn't this be filtered by the PHY?
-                // A broadcast message (e.g. beacons, orphan notifications) should not be received
-                // by the device who issues it.
-                if (receivedMacHdr.GetSrcAddrMode() == EXT_ADDR)
-                {
-                    acceptFrame = (receivedMacHdr.GetExtSrcAddr() != GetExtendedAddress());
-                }
-                else
-                {
-                    acceptFrame = (receivedMacHdr.GetShortSrcAddr() != GetShortAddress());
-                }
-            }
-
             if (acceptFrame && (receivedMacHdr.GetDstAddrMode() == SHORT_ADDR))
             {
                 if (receivedMacHdr.GetShortDstAddr() == m_shortAddress)
@@ -2108,9 +2094,10 @@
                     m_setMacState.Cancel();
                     ChangeMacState(MAC_IDLE);
 
-                    // save received packet to process the appropriate indication/response after
-                    // sending ACK (PD-DATA.confirm)
+                    // save received packet and LQI to process the appropriate indication/response
+                    // after sending ACK (PD-DATA.confirm)
                     m_rxPkt = originalPkt->Copy();
+                    m_lastRxFrameLqi = lqi;
 
                     // LOG Commands with ACK required.
                     CommandPayloadHeader receivedMacPayload;
@@ -2680,7 +2667,7 @@
 void
 LrWpanMac::IfsWaitTimeout(Time ifsTime)
 {
-    uint64_t symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false);
+    auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false);
     Time lifsTime = Seconds((double)m_macLIFSPeriod / symbolRate);
     Time sifsTime = Seconds((double)m_macSIFSPeriod / symbolRate);
 
@@ -2947,34 +2934,37 @@
 }
 
 void
-LrWpanMac::PrintPendTxQ(std::ostream& os) const
+LrWpanMac::PrintPendingTxQueue(std::ostream& os) const
 {
     LrWpanMacHeader peekedMacHdr;
 
     os << "Pending Transaction List [" << GetShortAddress() << " | " << GetExtendedAddress()
        << "] | CurrentTime: " << Simulator::Now().As(Time::S) << "\n"
-       << "       Destination        | Sequence Number |   Frame type    | Expire time\n";
-
-    for (uint32_t i = 0; i < m_indTxQueue.size(); i++)
-    {
-        m_indTxQueue[i]->txQPkt->PeekHeader(peekedMacHdr);
-        os << m_indTxQueue[i]->dstExtAddress << "           "
-           << static_cast<uint32_t>(m_indTxQueue[i]->seqNum) << "          ";
+       << "    Destination    |"
+       << "    Sequence Number |"
+       << "    Frame type    |"
+       << "    Expire time\n";
+
+    for (auto transaction : m_indTxQueue)
+    {
+        transaction->txQPkt->PeekHeader(peekedMacHdr);
+        os << transaction->dstExtAddress << "           "
+           << static_cast<uint32_t>(transaction->seqNum) << "          ";
 
         if (peekedMacHdr.IsCommand())
         {
-            os << "Cmd Frame    ";
+            os << " Command Frame   ";
         }
         else if (peekedMacHdr.IsData())
         {
-            os << "Data Frame   ";
+            os << " Data Frame      ";
         }
         else
         {
-            os << "Unk Frame    ";
+            os << " Unknown Frame   ";
         }
 
-        os << m_indTxQueue[i]->expireTime.As(Time::S) << "\n";
+        os << transaction->expireTime.As(Time::S) << "\n";
     }
 }
 
@@ -2985,11 +2975,14 @@
 
     os << "\nTx Queue [" << GetShortAddress() << " | " << GetExtendedAddress()
        << "] | CurrentTime: " << Simulator::Now().As(Time::S) << "\n"
-       << "       Destination                 | Sequence Number |  Dst PAN id | Frame type    |\n";
+       << "    Destination    |"
+       << "    Sequence Number    |"
+       << "    Dst PAN id    |"
+       << "    Frame type    |\n";
 
-    for (uint32_t i = 0; i < m_indTxQueue.size(); i++)
+    for (auto transaction : m_txQueue)
     {
-        m_txQueue[i]->txQPkt->PeekHeader(peekedMacHdr);
+        transaction->txQPkt->PeekHeader(peekedMacHdr);
 
         os << "[" << peekedMacHdr.GetShortDstAddr() << "]"
            << ", [" << peekedMacHdr.GetExtDstAddr() << "]        "
@@ -2998,15 +2991,15 @@
 
         if (peekedMacHdr.IsCommand())
         {
-            os << "Cmd Frame    ";
+            os << " Command Frame   ";
         }
         else if (peekedMacHdr.IsData())
         {
-            os << "Data Frame   ";
+            os << " Data Frame      ";
         }
         else
         {
-            os << "Unk Frame    ";
+            os << " Unknown Frame   ";
         }
 
         os << "\n";
@@ -3185,9 +3178,13 @@
                 {
                     if (!m_mlmeAssociateIndicationCallback.IsNull())
                     {
+                        // NOTE: The LQI parameter is not part of the standard but found
+                        // in some implementations as is required for higher layers (See Zboss
+                        // implementation).
                         MlmeAssociateIndicationParams associateParams;
                         associateParams.capabilityInfo = receivedMacPayload.GetCapabilityField();
                         associateParams.m_extDevAddr = receivedMacHdr.GetExtSrcAddr();
+                        associateParams.lqi = m_lastRxFrameLqi;
                         m_mlmeAssociateIndicationCallback(associateParams);
                     }
 
@@ -3202,15 +3199,13 @@
                     switch (receivedMacPayload.GetAssociationStatus())
                     {
                     case CommandPayloadHeader::SUCCESSFUL:
-                        confirmParams.m_status =
-                            LrWpanMlmeAssociateConfirmStatus::MLMEASSOC_SUCCESS;
-                        // The original short address used in the association
-                        // used in the association request
-                        confirmParams.m_assocShortAddr = GetShortAddress();
-
                         // The assigned short address by the coordinator
                         SetShortAddress(receivedMacPayload.GetShortAddr());
                         m_macPanId = receivedMacHdr.GetSrcPanId();
+
+                        confirmParams.m_status =
+                            LrWpanMlmeAssociateConfirmStatus::MLMEASSOC_SUCCESS;
+                        confirmParams.m_assocShortAddr = GetShortAddress();
                         break;
                     case CommandPayloadHeader::FULL_CAPACITY:
                         confirmParams.m_status =
@@ -3424,7 +3419,7 @@
     {
         if (status == LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
         {
-            uint64_t symbolRate = static_cast<uint64_t>(m_phy->GetDataOrSymbolRate(false));
+            auto symbolRate = static_cast<uint64_t>(m_phy->GetDataOrSymbolRate(false));
             Time nextScanTime;
 
             if (m_scanParams.m_scanType == MLMESCAN_ORPHAN)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/model/lr-wpan-mac.h ns-3.40/src/lr-wpan/model/lr-wpan-mac.h
--- ns-3.39/src/lr-wpan/model/lr-wpan-mac.h	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/model/lr-wpan-mac.h	2023-09-27 13:30:37.674839300 -0700
@@ -25,9 +25,10 @@
 #ifndef LR_WPAN_MAC_H
 #define LR_WPAN_MAC_H
 
+#include "lr-wpan-fields.h"
+#include "lr-wpan-phy.h"
+
 #include <ns3/event-id.h>
-#include <ns3/lr-wpan-fields.h>
-#include <ns3/lr-wpan-phy.h>
 #include <ns3/mac16-address.h>
 #include <ns3/mac64-address.h>
 #include <ns3/object.h>
@@ -447,9 +448,11 @@
  */
 struct MlmeAssociateIndicationParams
 {
-    Mac64Address m_extDevAddr; //!< The extended address of the device requesting association
-    CapabilityField
-        capabilityInfo; //!< The operational capabilities of the device requesting association.
+    Mac64Address m_extDevAddr;      //!< The extended address of the device requesting association
+    CapabilityField capabilityInfo; //!< The operational capabilities of
+                                    //!< the device requesting association.
+    uint8_t lqi{0}; //!< The link quality indicator of the received associate request command
+                    //!< (Not officially supported in the standard but found in implementations)
 };
 
 /**
@@ -1584,7 +1587,7 @@
      * Print the Pending transaction list.
      * \param os The reference to the output stream used by this print function.
      */
-    void PrintPendTxQ(std::ostream& os) const;
+    void PrintPendingTxQueue(std::ostream& os) const;
 
     /**
      * Print the Transmit Queue.
@@ -2219,6 +2222,11 @@
     uint8_t m_numCsmacaRetry;
 
     /**
+     * Keep track of the last received frame Link Quality Indicator
+     */
+    uint8_t m_lastRxFrameLqi;
+
+    /**
      * Scheduler event for the ACK timeout of the currently transmitted data
      * packet.
      */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/model/lr-wpan-mac-trailer.cc ns-3.40/src/lr-wpan/model/lr-wpan-mac-trailer.cc
--- ns-3.39/src/lr-wpan/model/lr-wpan-mac-trailer.cc	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/model/lr-wpan-mac-trailer.cc	2023-09-27 13:30:37.670839000 -0700
@@ -93,7 +93,7 @@
     if (m_calcFcs)
     {
         uint16_t size = p->GetSize();
-        uint8_t* serial_packet = new uint8_t[size];
+        auto serial_packet = new uint8_t[size];
 
         p->CopyData(serial_packet, size);
 
@@ -115,7 +115,7 @@
     {
         uint16_t checkFcs;
         uint16_t size = p->GetSize();
-        uint8_t* serial_packet = new uint8_t[size];
+        auto serial_packet = new uint8_t[size];
 
         p->CopyData(serial_packet, size);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/model/lr-wpan-net-device.h ns-3.40/src/lr-wpan/model/lr-wpan-net-device.h
--- ns-3.39/src/lr-wpan/model/lr-wpan-net-device.h	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/model/lr-wpan-net-device.h	2023-09-27 13:30:37.674839300 -0700
@@ -22,7 +22,8 @@
 #ifndef LR_WPAN_NET_DEVICE_H
 #define LR_WPAN_NET_DEVICE_H
 
-#include <ns3/lr-wpan-mac.h>
+#include "lr-wpan-mac.h"
+
 #include <ns3/net-device.h>
 #include <ns3/traced-callback.h>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lr-wpan/test/lr-wpan-mac-test.cc ns-3.40/src/lr-wpan/test/lr-wpan-mac-test.cc
--- ns-3.39/src/lr-wpan/test/lr-wpan-mac-test.cc	2023-07-05 14:23:47.869427400 -0700
+++ ns-3.40/src/lr-wpan/test/lr-wpan-mac-test.cc	2023-09-27 13:30:37.674839300 -0700
@@ -308,6 +308,7 @@
      * \param params MLME scan confirm parameters
      */
     void ScanConfirm(MlmeScanConfirmParams params);
+
     /**
      * Function used to notify the reception of a beacon with payload.
      *
@@ -380,9 +381,16 @@
     Ptr<LrWpanNetDevice> endNodeNetDevice = CreateObject<LrWpanNetDevice>();
     Ptr<LrWpanNetDevice> coord2NetDevice = CreateObject<LrWpanNetDevice>();
 
-    coord1NetDevice->SetAddress(Mac16Address("00:01"));
-    endNodeNetDevice->SetAddress(Mac16Address("00:02"));
-    coord2NetDevice->SetAddress(Mac16Address("00:03"));
+    // PAN coordinators typically have a short address = 00:00 (e.g. Zigbee networks)
+    coord1NetDevice->GetMac()->SetExtendedAddress("00:00:00:00:00:00:CA:FE");
+    coord1NetDevice->GetMac()->SetShortAddress(Mac16Address("00:00"));
+
+    coord2NetDevice->GetMac()->SetExtendedAddress("00:00:00:00:00:00:BE:BE");
+    coord2NetDevice->GetMac()->SetShortAddress(Mac16Address("00:00"));
+
+    // An end device currently not associated (short address = ff:ff)
+    endNodeNetDevice->GetMac()->SetExtendedAddress("00:00:00:00:00:00:00:03");
+    endNodeNetDevice->GetMac()->SetShortAddress(Mac16Address("ff:ff"));
 
     // Configure Spectrum channel
     Ptr<SingleModelSpectrumChannel> channel = CreateObject<SingleModelSpectrumChannel>();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/examples/lena-cc-helper.cc ns-3.40/src/lte/examples/lena-cc-helper.cc
--- ns-3.39/src/lte/examples/lena-cc-helper.cc	2023-07-05 14:23:47.897427600 -0700
+++ ns-3.40/src/lte/examples/lena-cc-helper.cc	2023-09-27 13:30:37.702839100 -0700
@@ -44,10 +44,8 @@
 
     std::map<uint8_t, ComponentCarrier> ccm = cch->EquallySpacedCcs();
 
-    std::map<uint8_t, ComponentCarrier>::iterator it;
-
     std::cout << " CcMap size " << ccm.size() << std::endl;
-    for (it = ccm.begin(); it != ccm.end(); it++)
+    for (auto it = ccm.begin(); it != ccm.end(); it++)
     {
         Print(it->second);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/examples/lena-deactivate-bearer.cc ns-3.40/src/lte/examples/lena-deactivate-bearer.cc
--- ns-3.39/src/lte/examples/lena-deactivate-bearer.cc	2023-07-05 14:23:47.897427600 -0700
+++ ns-3.40/src/lte/examples/lena-deactivate-bearer.cc	2023-09-27 13:30:37.702839100 -0700
@@ -69,7 +69,7 @@
     Ptr<Node> pgw = epcHelper->GetPgwNode();
 
     // Enable Logging
-    LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
+    auto logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
 
     LogComponentEnable("BearerDeactivateExample", LOG_LEVEL_ALL);
     LogComponentEnable("LteHelper", logLevel);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/examples/lena-distributed-ffr.cc ns-3.40/src/lte/examples/lena-distributed-ffr.cc
--- ns-3.39/src/lte/examples/lena-distributed-ffr.cc	2023-07-05 14:23:47.897427600 -0700
+++ ns-3.40/src/lte/examples/lena-distributed-ffr.cc	2023-09-27 13:30:37.702839100 -0700
@@ -45,7 +45,7 @@
         NS_LOG_ERROR("Can't open file " << filename);
         return;
     }
-    for (NodeList::Iterator it = NodeList::Begin(); it != NodeList::End(); ++it)
+    for (auto it = NodeList::Begin(); it != NodeList::End(); ++it)
     {
         Ptr<Node> node = *it;
         int nDevs = node->GetNDevices();
@@ -74,7 +74,7 @@
         NS_LOG_ERROR("Can't open file " << filename);
         return;
     }
-    for (NodeList::Iterator it = NodeList::Begin(); it != NodeList::End(); ++it)
+    for (auto it = NodeList::Begin(); it != NodeList::End(); ++it)
     {
         Ptr<Node> node = *it;
         int nDevs = node->GetNDevices();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/examples/lena-dual-stripe.cc ns-3.40/src/lte/examples/lena-dual-stripe.cc
--- ns-3.39/src/lte/examples/lena-dual-stripe.cc	2023-07-05 14:23:47.897427600 -0700
+++ ns-3.40/src/lte/examples/lena-dual-stripe.cc	2023-09-27 13:30:37.702839100 -0700
@@ -158,7 +158,7 @@
 bool
 FemtocellBlockAllocator::OverlapsWithAnyPrevious(Box box)
 {
-    for (std::list<Box>::iterator it = m_previousBlocks.begin(); it != m_previousBlocks.end(); ++it)
+    for (auto it = m_previousBlocks.begin(); it != m_previousBlocks.end(); ++it)
     {
         if (AreOverlapping(*it, box))
         {
@@ -184,7 +184,7 @@
         return;
     }
     uint32_t index = 0;
-    for (BuildingList::Iterator it = BuildingList::Begin(); it != BuildingList::End(); ++it)
+    for (auto it = BuildingList::Begin(); it != BuildingList::End(); ++it)
     {
         ++index;
         Box box = (*it)->GetBoundaries();
@@ -208,7 +208,7 @@
         NS_LOG_ERROR("Can't open file " << filename);
         return;
     }
-    for (NodeList::Iterator it = NodeList::Begin(); it != NodeList::End(); ++it)
+    for (auto it = NodeList::Begin(); it != NodeList::End(); ++it)
     {
         Ptr<Node> node = *it;
         int nDevs = node->GetNDevices();
@@ -242,7 +242,7 @@
         NS_LOG_ERROR("Can't open file " << filename);
         return;
     }
-    for (NodeList::Iterator it = NodeList::Begin(); it != NodeList::End(); ++it)
+    for (auto it = NodeList::Begin(); it != NodeList::End(); ++it)
     {
         Ptr<Node> node = *it;
         int nDevs = node->GetNDevices();
@@ -714,7 +714,7 @@
         // forcing initialization so we don't have to wait for Nodes to
         // start before positions are assigned (which is needed to
         // output node positions to file and to make AttachToClosestEnb work)
-        for (NodeContainer::Iterator it = macroUes.Begin(); it != macroUes.End(); ++it)
+        for (auto it = macroUes.Begin(); it != macroUes.End(); ++it)
         {
             (*it)->Initialize();
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/examples/lena-frequency-reuse.cc ns-3.40/src/lte/examples/lena-frequency-reuse.cc
--- ns-3.39/src/lte/examples/lena-frequency-reuse.cc	2023-07-05 14:23:47.897427600 -0700
+++ ns-3.40/src/lte/examples/lena-frequency-reuse.cc	2023-09-27 13:30:37.702839100 -0700
@@ -41,7 +41,7 @@
         NS_LOG_ERROR("Can't open file " << filename);
         return;
     }
-    for (NodeList::Iterator it = NodeList::Begin(); it != NodeList::End(); ++it)
+    for (auto it = NodeList::Begin(); it != NodeList::End(); ++it)
     {
         Ptr<Node> node = *it;
         int nDevs = node->GetNDevices();
@@ -70,7 +70,7 @@
         NS_LOG_ERROR("Can't open file " << filename);
         return;
     }
-    for (NodeList::Iterator it = NodeList::Begin(); it != NodeList::End(); ++it)
+    for (auto it = NodeList::Begin(); it != NodeList::End(); ++it)
     {
         Ptr<Node> node = *it;
         int nDevs = node->GetNDevices();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/examples/lena-radio-link-failure.cc ns-3.40/src/lte/examples/lena-radio-link-failure.cc
--- ns-3.39/src/lte/examples/lena-radio-link-failure.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/examples/lena-radio-link-failure.cc	2023-09-27 13:30:37.702839100 -0700
@@ -49,7 +49,7 @@
 void
 PrintUePosition(uint64_t imsi)
 {
-    for (NodeList::Iterator it = NodeList::Begin(); it != NodeList::End(); ++it)
+    for (auto it = NodeList::Begin(); it != NodeList::End(); ++it)
     {
         Ptr<Node> node = *it;
         int nDevs = node->GetNDevices();
@@ -381,7 +381,7 @@
 
     if (enableNsLogs)
     {
-        LogLevel logLevel =
+        auto logLevel =
             (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_NODE | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
         LogComponentEnable("LteUeRrc", logLevel);
         LogComponentEnable("LteUeMac", logLevel);
@@ -632,7 +632,7 @@
     Config::ConnectWithoutContext(oss.str(), MakeCallback(&ReceivePacket));
 
     bool firstWrite = true;
-    std::string rrcType = useIdealRrc == 1 ? "ideal_rrc" : "real_rrc";
+    std::string rrcType = useIdealRrc ? "ideal_rrc" : "real_rrc";
     std::string fileName = "rlf_dl_thrput_" + std::to_string(enbNodes.GetN()) + "_eNB_" + rrcType;
     Time binSize = Seconds(0.2);
     Simulator::Schedule(Seconds(0.47), &Throughput, firstWrite, binSize, fileName);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/helper/lte-global-pathloss-database.cc ns-3.40/src/lte/helper/lte-global-pathloss-database.cc
--- ns-3.39/src/lte/helper/lte-global-pathloss-database.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/helper/lte-global-pathloss-database.cc	2023-09-27 13:30:37.702839100 -0700
@@ -38,14 +38,9 @@
 LteGlobalPathlossDatabase::Print()
 {
     NS_LOG_FUNCTION(this);
-    for (std::map<uint16_t, std::map<uint64_t, double>>::const_iterator cellIdIt =
-             m_pathlossMap.begin();
-         cellIdIt != m_pathlossMap.end();
-         ++cellIdIt)
+    for (auto cellIdIt = m_pathlossMap.begin(); cellIdIt != m_pathlossMap.end(); ++cellIdIt)
     {
-        for (std::map<uint64_t, double>::const_iterator imsiIt = cellIdIt->second.begin();
-             imsiIt != cellIdIt->second.end();
-             ++imsiIt)
+        for (auto imsiIt = cellIdIt->second.begin(); imsiIt != cellIdIt->second.end(); ++imsiIt)
         {
             std::cout << "CellId: " << cellIdIt->first << " IMSI: " << imsiIt->first
                       << " pathloss: " << imsiIt->second << " dB" << std::endl;
@@ -57,12 +52,12 @@
 LteGlobalPathlossDatabase::GetPathloss(uint16_t cellId, uint64_t imsi)
 {
     NS_LOG_FUNCTION(this);
-    std::map<uint16_t, std::map<uint64_t, double>>::iterator cellIt = m_pathlossMap.find(cellId);
+    auto cellIt = m_pathlossMap.find(cellId);
     if (cellIt == m_pathlossMap.end())
     {
         return std::numeric_limits<double>::infinity();
     }
-    std::map<uint64_t, double>::iterator ueIt = cellIt->second.find(imsi);
+    auto ueIt = cellIt->second.find(imsi);
     if (ueIt == cellIt->second.end())
     {
         return std::numeric_limits<double>::infinity();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/helper/lte-helper.cc ns-3.40/src/lte/helper/lte-helper.cc
--- ns-3.39/src/lte/helper/lte-helper.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/helper/lte-helper.cc	2023-09-27 13:30:37.702839100 -0700
@@ -487,7 +487,7 @@
     NS_LOG_FUNCTION(this);
     Initialize(); // will run DoInitialize () if necessary
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<NetDevice> device = InstallSingleEnbDevice(node);
@@ -501,7 +501,7 @@
 {
     NS_LOG_FUNCTION(this);
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<NetDevice> device = InstallSingleUeDevice(node);
@@ -531,8 +531,7 @@
                                     << ")");
     // create component carrier map for this eNb device
     std::map<uint8_t, Ptr<ComponentCarrierBaseStation>> ccMap;
-    for (std::map<uint8_t, ComponentCarrier>::iterator it = m_componentCarrierPhyParams.begin();
-         it != m_componentCarrierPhyParams.end();
+    for (auto it = m_componentCarrierPhyParams.begin(); it != m_componentCarrierPhyParams.end();
          ++it)
     {
         Ptr<ComponentCarrierEnb> cc = CreateObject<ComponentCarrierEnb>();
@@ -752,7 +751,7 @@
     dev->SetAttribute("CellId", UintegerValue(cellId));
     dev->SetAttribute("LteEnbComponentCarrierManager", PointerValue(ccmEnbManager));
     dev->SetCcMap(ccMap);
-    std::map<uint8_t, Ptr<ComponentCarrierBaseStation>>::iterator it = ccMap.begin();
+    auto it = ccMap.begin();
     dev->SetAttribute("LteEnbRrc", PointerValue(rrc));
     dev->SetAttribute("LteHandoverAlgorithm", PointerValue(handoverAlgorithm));
     dev->SetAttribute(
@@ -848,8 +847,7 @@
                                     << ")");
     std::map<uint8_t, Ptr<ComponentCarrierUe>> ueCcMap;
 
-    for (std::map<uint8_t, ComponentCarrier>::iterator it = m_componentCarrierPhyParams.begin();
-         it != m_componentCarrierPhyParams.end();
+    for (auto it = m_componentCarrierPhyParams.begin(); it != m_componentCarrierPhyParams.end();
          ++it)
     {
         Ptr<ComponentCarrierUe> cc = CreateObject<ComponentCarrierUe>();
@@ -867,9 +865,7 @@
     // CC map is not needed anymore
     m_componentCarrierPhyParams.clear();
 
-    for (std::map<uint8_t, Ptr<ComponentCarrierUe>>::iterator it = ueCcMap.begin();
-         it != ueCcMap.end();
-         ++it)
+    for (auto it = ueCcMap.begin(); it != ueCcMap.end(); ++it)
     {
         Ptr<LteSpectrumPhy> dlPhy = CreateObject<LteSpectrumPhy>();
         Ptr<LteSpectrumPhy> ulPhy = CreateObject<LteSpectrumPhy>();
@@ -971,9 +967,7 @@
     nas->SetAsSapProvider(rrc->GetAsSapProvider());
     rrc->SetAsSapUser(nas->GetAsSapUser());
 
-    for (std::map<uint8_t, Ptr<ComponentCarrierUe>>::iterator it = ueCcMap.begin();
-         it != ueCcMap.end();
-         ++it)
+    for (auto it = ueCcMap.begin(); it != ueCcMap.end(); ++it)
     {
         rrc->SetLteUeCmacSapProvider(it->second->GetMac()->GetLteUeCmacSapProvider(), it->first);
         it->second->GetMac()->SetLteUeCmacSapUser(rrc->GetLteUeCmacSapUser(it->first));
@@ -1009,9 +1003,7 @@
     // when the default PDP context is created. This is a simplification.
     dev->SetAddress(Mac64Address::Allocate());
 
-    for (std::map<uint8_t, Ptr<ComponentCarrierUe>>::iterator it = ueCcMap.begin();
-         it != ueCcMap.end();
-         ++it)
+    for (auto it = ueCcMap.begin(); it != ueCcMap.end(); ++it)
     {
         Ptr<LteUePhy> ccPhy = it->second->GetPhy();
         ccPhy->SetDevice(dev);
@@ -1047,7 +1039,7 @@
 LteHelper::Attach(NetDeviceContainer ueDevices)
 {
     NS_LOG_FUNCTION(this);
-    for (NetDeviceContainer::Iterator i = ueDevices.Begin(); i != ueDevices.End(); ++i)
+    for (auto i = ueDevices.Begin(); i != ueDevices.End(); ++i)
     {
         Attach(*i);
     }
@@ -1089,7 +1081,7 @@
 LteHelper::Attach(NetDeviceContainer ueDevices, Ptr<NetDevice> enbDevice)
 {
     NS_LOG_FUNCTION(this);
-    for (NetDeviceContainer::Iterator i = ueDevices.Begin(); i != ueDevices.End(); ++i)
+    for (auto i = ueDevices.Begin(); i != ueDevices.End(); ++i)
     {
         Attach(*i, enbDevice);
     }
@@ -1130,7 +1122,7 @@
 LteHelper::AttachToClosestEnb(NetDeviceContainer ueDevices, NetDeviceContainer enbDevices)
 {
     NS_LOG_FUNCTION(this);
-    for (NetDeviceContainer::Iterator i = ueDevices.Begin(); i != ueDevices.End(); ++i)
+    for (auto i = ueDevices.Begin(); i != ueDevices.End(); ++i)
     {
         AttachToClosestEnb(*i, enbDevices);
     }
@@ -1144,7 +1136,7 @@
     Vector uepos = ueDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
     double minDistance = std::numeric_limits<double>::infinity();
     Ptr<NetDevice> closestEnbDevice;
-    for (NetDeviceContainer::Iterator i = enbDevices.Begin(); i != enbDevices.End(); ++i)
+    for (auto i = enbDevices.Begin(); i != enbDevices.End(); ++i)
     {
         Vector enbpos = (*i)->GetNode()->GetObject<MobilityModel>()->GetPosition();
         double distance = CalculateDistance(uepos, enbpos);
@@ -1164,7 +1156,7 @@
                                       Ptr<EpcTft> tft)
 {
     NS_LOG_FUNCTION(this);
-    for (NetDeviceContainer::Iterator i = ueDevices.Begin(); i != ueDevices.End(); ++i)
+    for (auto i = ueDevices.Begin(); i != ueDevices.End(); ++i)
     {
         uint8_t bearerId = ActivateDedicatedEpsBearer(*i, bearer, tft);
         return bearerId;
@@ -1324,9 +1316,9 @@
 
     NS_ASSERT_MSG(m_epcHelper, "X2 interfaces cannot be set up when the EPC is not used");
 
-    for (NodeContainer::Iterator i = enbNodes.Begin(); i != enbNodes.End(); ++i)
+    for (auto i = enbNodes.Begin(); i != enbNodes.End(); ++i)
     {
-        for (NodeContainer::Iterator j = i + 1; j != enbNodes.End(); ++j)
+        for (auto j = i + 1; j != enbNodes.End(); ++j)
         {
             AddX2Interface(*i, *j);
         }
@@ -1444,7 +1436,7 @@
 LteHelper::ActivateDataRadioBearer(NetDeviceContainer ueDevices, EpsBearer bearer)
 {
     NS_LOG_FUNCTION(this);
-    for (NetDeviceContainer::Iterator i = ueDevices.Begin(); i != ueDevices.End(); ++i)
+    for (auto i = ueDevices.Begin(); i != ueDevices.End(); ++i)
     {
         ActivateDataRadioBearer(*i, bearer);
     }
@@ -1585,15 +1577,14 @@
         }
     }
     Ptr<NetDevice> netDevice;
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         netDevice = (*i);
         Ptr<LteEnbNetDevice> lteEnb = DynamicCast<LteEnbNetDevice>(netDevice);
         if (lteEnb)
         {
             std::map<uint8_t, Ptr<ComponentCarrierBaseStation>> tmpMap = lteEnb->GetCcMap();
-            std::map<uint8_t, Ptr<ComponentCarrierBaseStation>>::iterator it;
-            it = tmpMap.begin();
+            auto it = tmpMap.begin();
             Ptr<LteSpectrumPhy> dlPhy =
                 DynamicCast<ComponentCarrierEnb>(it->second)->GetPhy()->GetDownlinkSpectrumPhy();
             Ptr<LteSpectrumPhy> ulPhy =
@@ -1605,8 +1596,7 @@
         if (lteUe)
         {
             std::map<uint8_t, Ptr<ComponentCarrierUe>> tmpMap = lteUe->GetCcMap();
-            std::map<uint8_t, Ptr<ComponentCarrierUe>>::iterator it;
-            it = tmpMap.begin();
+            auto it = tmpMap.begin();
             Ptr<LteSpectrumPhy> dlPhy = it->second->GetPhy()->GetDownlinkSpectrumPhy();
             Ptr<LteSpectrumPhy> ulPhy = it->second->GetPhy()->GetUplinkSpectrumPhy();
             Ptr<LteUeMac> ueMac = lteUe->GetMac();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/helper/no-backhaul-epc-helper.cc ns-3.40/src/lte/helper/no-backhaul-epc-helper.cc
--- ns-3.39/src/lte/helper/no-backhaul-epc-helper.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/helper/no-backhaul-epc-helper.cc	2023-09-27 13:30:37.702839100 -0700
@@ -540,7 +540,7 @@
 Ipv6InterfaceContainer
 NoBackhaulEpcHelper::AssignUeIpv6Address(NetDeviceContainer ueDevices)
 {
-    for (NetDeviceContainer::Iterator iter = ueDevices.Begin(); iter != ueDevices.End(); iter++)
+    for (auto iter = ueDevices.Begin(); iter != ueDevices.End(); iter++)
     {
         Ptr<Icmpv6L4Protocol> icmpv6 = (*iter)->GetNode()->GetObject<Icmpv6L4Protocol>();
         icmpv6->SetAttribute("DAD", BooleanValue(false));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/helper/radio-bearer-stats-calculator.cc ns-3.40/src/lte/helper/radio-bearer-stats-calculator.cc
--- ns-3.39/src/lte/helper/radio-bearer-stats-calculator.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/helper/radio-bearer-stats-calculator.cc	2023-09-27 13:30:37.702839100 -0700
@@ -189,7 +189,7 @@
         m_ulRxPackets[p]++;
         m_ulRxData[p] += packetSize;
 
-        Uint64StatsMap::iterator it = m_ulDelay.find(p);
+        auto it = m_ulDelay.find(p);
         if (it == m_ulDelay.end())
         {
             NS_LOG_DEBUG(this << " Creating UL stats calculators for IMSI " << p.m_imsi
@@ -220,7 +220,7 @@
         m_dlRxPackets[p]++;
         m_dlRxData[p] += packetSize;
 
-        Uint64StatsMap::iterator it = m_dlDelay.find(p);
+        auto it = m_dlDelay.find(p);
         if (it == m_dlDelay.end())
         {
             NS_LOG_DEBUG(this << " Creating DL stats calculators for IMSI " << p.m_imsi
@@ -298,7 +298,7 @@
 
     // Get the unique IMSI/LCID pairs list
     std::vector<ImsiLcidPair_t> pairVector;
-    for (Uint32Map::iterator it = m_ulTxPackets.begin(); it != m_ulTxPackets.end(); ++it)
+    for (auto it = m_ulTxPackets.begin(); it != m_ulTxPackets.end(); ++it)
     {
         if (find(pairVector.begin(), pairVector.end(), (*it).first) == pairVector.end())
         {
@@ -306,7 +306,7 @@
         }
     }
 
-    for (Uint32Map::iterator it = m_ulRxPackets.begin(); it != m_ulRxPackets.end(); ++it)
+    for (auto it = m_ulRxPackets.begin(); it != m_ulRxPackets.end(); ++it)
     {
         if (find(pairVector.begin(), pairVector.end(), (*it).first) == pairVector.end())
         {
@@ -315,11 +315,10 @@
     }
 
     Time endTime = m_startTime + m_epochDuration;
-    for (std::vector<ImsiLcidPair_t>::iterator it = pairVector.begin(); it != pairVector.end();
-         ++it)
+    for (auto it = pairVector.begin(); it != pairVector.end(); ++it)
     {
         ImsiLcidPair_t p = *it;
-        FlowIdMap::const_iterator flowIdIt = m_flowId.find(p);
+        auto flowIdIt = m_flowId.find(p);
         NS_ASSERT_MSG(flowIdIt != m_flowId.end(),
                       "FlowId (imsi " << p.m_imsi << " lcid " << (uint32_t)p.m_lcId
                                       << ") is missing");
@@ -337,12 +336,12 @@
         outFile << GetUlRxPackets(p.m_imsi, p.m_lcId) << "\t";
         outFile << GetUlRxData(p.m_imsi, p.m_lcId) << "\t";
         std::vector<double> stats = GetUlDelayStats(p.m_imsi, p.m_lcId);
-        for (std::vector<double>::iterator it = stats.begin(); it != stats.end(); ++it)
+        for (auto it = stats.begin(); it != stats.end(); ++it)
         {
             outFile << (*it) * 1e-9 << "\t";
         }
         stats = GetUlPduSizeStats(p.m_imsi, p.m_lcId);
-        for (std::vector<double>::iterator it = stats.begin(); it != stats.end(); ++it)
+        for (auto it = stats.begin(); it != stats.end(); ++it)
         {
             outFile << (*it) << "\t";
         }
@@ -359,7 +358,7 @@
 
     // Get the unique IMSI/LCID pairs list
     std::vector<ImsiLcidPair_t> pairVector;
-    for (Uint32Map::iterator it = m_dlTxPackets.begin(); it != m_dlTxPackets.end(); ++it)
+    for (auto it = m_dlTxPackets.begin(); it != m_dlTxPackets.end(); ++it)
     {
         if (find(pairVector.begin(), pairVector.end(), (*it).first) == pairVector.end())
         {
@@ -367,7 +366,7 @@
         }
     }
 
-    for (Uint32Map::iterator it = m_dlRxPackets.begin(); it != m_dlRxPackets.end(); ++it)
+    for (auto it = m_dlRxPackets.begin(); it != m_dlRxPackets.end(); ++it)
     {
         if (find(pairVector.begin(), pairVector.end(), (*it).first) == pairVector.end())
         {
@@ -376,11 +375,10 @@
     }
 
     Time endTime = m_startTime + m_epochDuration;
-    for (std::vector<ImsiLcidPair_t>::iterator pair = pairVector.begin(); pair != pairVector.end();
-         ++pair)
+    for (auto pair = pairVector.begin(); pair != pairVector.end(); ++pair)
     {
         ImsiLcidPair_t p = *pair;
-        FlowIdMap::const_iterator flowIdIt = m_flowId.find(p);
+        auto flowIdIt = m_flowId.find(p);
         NS_ASSERT_MSG(flowIdIt != m_flowId.end(),
                       "FlowId (imsi " << p.m_imsi << " lcid " << (uint32_t)p.m_lcId
                                       << ") is missing");
@@ -398,12 +396,12 @@
         outFile << GetDlRxPackets(p.m_imsi, p.m_lcId) << "\t";
         outFile << GetDlRxData(p.m_imsi, p.m_lcId) << "\t";
         std::vector<double> stats = GetDlDelayStats(p.m_imsi, p.m_lcId);
-        for (std::vector<double>::iterator it = stats.begin(); it != stats.end(); ++it)
+        for (auto it = stats.begin(); it != stats.end(); ++it)
         {
             outFile << (*it) * 1e-9 << "\t";
         }
         stats = GetDlPduSizeStats(p.m_imsi, p.m_lcId);
-        for (std::vector<double>::iterator it = stats.begin(); it != stats.end(); ++it)
+        for (auto it = stats.begin(); it != stats.end(); ++it)
         {
             outFile << (*it) << "\t";
         }
@@ -492,7 +490,7 @@
 {
     NS_LOG_FUNCTION(this << imsi << (uint16_t)lcid);
     ImsiLcidPair_t p(imsi, lcid);
-    Uint64StatsMap::iterator it = m_ulDelay.find(p);
+    auto it = m_ulDelay.find(p);
     if (it == m_ulDelay.end())
     {
         NS_LOG_ERROR("UL delay for " << imsi << " - " << (uint16_t)lcid << " not found");
@@ -507,7 +505,7 @@
     NS_LOG_FUNCTION(this << imsi << (uint16_t)lcid);
     ImsiLcidPair_t p(imsi, lcid);
     std::vector<double> stats;
-    Uint64StatsMap::iterator it = m_ulDelay.find(p);
+    auto it = m_ulDelay.find(p);
     if (it == m_ulDelay.end())
     {
         stats.push_back(0.0);
@@ -529,7 +527,7 @@
     NS_LOG_FUNCTION(this << imsi << (uint16_t)lcid);
     ImsiLcidPair_t p(imsi, lcid);
     std::vector<double> stats;
-    Uint32StatsMap::iterator it = m_ulPduSize.find(p);
+    auto it = m_ulPduSize.find(p);
     if (it == m_ulPduSize.end())
     {
         stats.push_back(0.0);
@@ -598,7 +596,7 @@
 {
     NS_LOG_FUNCTION(this << imsi << (uint16_t)lcid);
     ImsiLcidPair_t p(imsi, lcid);
-    Uint64StatsMap::iterator it = m_dlDelay.find(p);
+    auto it = m_dlDelay.find(p);
     if (it == m_dlDelay.end())
     {
         NS_LOG_ERROR("DL delay for " << imsi << " not found");
@@ -613,7 +611,7 @@
     NS_LOG_FUNCTION(this << imsi << (uint16_t)lcid);
     ImsiLcidPair_t p(imsi, lcid);
     std::vector<double> stats;
-    Uint64StatsMap::iterator it = m_dlDelay.find(p);
+    auto it = m_dlDelay.find(p);
     if (it == m_dlDelay.end())
     {
         stats.push_back(0.0);
@@ -635,7 +633,7 @@
     NS_LOG_FUNCTION(this << imsi << (uint16_t)lcid);
     ImsiLcidPair_t p(imsi, lcid);
     std::vector<double> stats;
-    Uint32StatsMap::iterator it = m_dlPduSize.find(p);
+    auto it = m_dlPduSize.find(p);
     if (it == m_dlPduSize.end())
     {
         stats.push_back(0.0);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/helper/radio-bearer-stats-connector.cc ns-3.40/src/lte/helper/radio-bearer-stats-connector.cc
--- ns-3.39/src/lte/helper/radio-bearer-stats-connector.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/helper/radio-bearer-stats-connector.cc	2023-09-27 13:30:37.702839100 -0700
@@ -259,7 +259,7 @@
     CellIdRnti key;
     key.cellId = cellId;
     key.rnti = rnti;
-    std::map<CellIdRnti, std::string>::iterator it = m_ueManagerPathByCellIdRnti.find(key);
+    auto it = m_ueManagerPathByCellIdRnti.find(key);
     NS_ASSERT(it != m_ueManagerPathByCellIdRnti.end());
     std::string ueManagerPath = it->second;
     NS_LOG_LOGIC("ueManagerPath = " << ueManagerPath);
@@ -290,7 +290,7 @@
     CellIdRnti key;
     key.cellId = cellId;
     key.rnti = rnti;
-    std::map<CellIdRnti, std::string>::iterator it = m_ueManagerPathByCellIdRnti.find(key);
+    auto it = m_ueManagerPathByCellIdRnti.find(key);
     NS_ASSERT(it != m_ueManagerPathByCellIdRnti.end());
     std::string ueManagerPath = it->second;
     NS_LOG_LOGIC("ueManagerPath = " << ueManagerPath);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/helper/radio-environment-map-helper.cc ns-3.40/src/lte/helper/radio-environment-map-helper.cc
--- ns-3.39/src/lte/helper/radio-environment-map-helper.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/helper/radio-environment-map-helper.cc	2023-09-27 13:30:37.706839300 -0700
@@ -306,7 +306,7 @@
 RadioEnvironmentMapHelper::RunOneIteration(double xMin, double xMax, double yMin, double yMax)
 {
     NS_LOG_FUNCTION(this << xMin << xMax << yMin << yMax);
-    std::list<RemPoint>::iterator remIt = m_rem.begin();
+    auto remIt = m_rem.begin();
     double x = 0.0;
     double y = 0.0;
     for (x = xMin; x < xMax + 0.5 * m_xStep; x += m_xStep)
@@ -342,7 +342,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    for (std::list<RemPoint>::iterator it = m_rem.begin(); it != m_rem.end(); ++it)
+    for (auto it = m_rem.begin(); it != m_rem.end(); ++it)
     {
         if (!(it->phy->IsActive()))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/a2-a4-rsrq-handover-algorithm.cc ns-3.40/src/lte/model/a2-a4-rsrq-handover-algorithm.cc
--- ns-3.39/src/lte/model/a2-a4-rsrq-handover-algorithm.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/model/a2-a4-rsrq-handover-algorithm.cc	2023-09-27 13:30:37.706839300 -0700
@@ -149,8 +149,7 @@
     {
         if (measResults.haveMeasResultNeighCells && !measResults.measResultListEutra.empty())
         {
-            for (std::list<LteRrcSap::MeasResultEutra>::iterator it =
-                     measResults.measResultListEutra.begin();
+            for (auto it = measResults.measResultListEutra.begin();
                  it != measResults.measResultListEutra.end();
                  ++it)
             {
@@ -177,8 +176,7 @@
 {
     NS_LOG_FUNCTION(this << rnti << (uint16_t)servingCellRsrq);
 
-    MeasurementTable_t::iterator it1;
-    it1 = m_neighbourCellMeasures.find(rnti);
+    auto it1 = m_neighbourCellMeasures.find(rnti);
 
     if (it1 == m_neighbourCellMeasures.end())
     {
@@ -191,8 +189,7 @@
         NS_LOG_LOGIC("Number of neighbour cells = " << it1->second.size());
         uint16_t bestNeighbourCellId = 0;
         uint8_t bestNeighbourRsrq = 0;
-        MeasurementRow_t::iterator it2;
-        for (it2 = it1->second.begin(); it2 != it1->second.end(); ++it2)
+        for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2)
         {
             if ((it2->second->m_rsrq > bestNeighbourRsrq) && IsValidNeighbour(it2->first))
             {
@@ -239,23 +236,20 @@
 A2A4RsrqHandoverAlgorithm::UpdateNeighbourMeasurements(uint16_t rnti, uint16_t cellId, uint8_t rsrq)
 {
     NS_LOG_FUNCTION(this << rnti << cellId << (uint16_t)rsrq);
-    MeasurementTable_t::iterator it1;
-    it1 = m_neighbourCellMeasures.find(rnti);
+    auto it1 = m_neighbourCellMeasures.find(rnti);
 
     if (it1 == m_neighbourCellMeasures.end())
     {
         // insert a new UE entry
         MeasurementRow_t row;
-        std::pair<MeasurementTable_t::iterator, bool> ret;
-        ret = m_neighbourCellMeasures.insert(std::pair<uint16_t, MeasurementRow_t>(rnti, row));
+        auto ret = m_neighbourCellMeasures.insert(std::pair<uint16_t, MeasurementRow_t>(rnti, row));
         NS_ASSERT(ret.second);
         it1 = ret.first;
     }
 
     NS_ASSERT(it1 != m_neighbourCellMeasures.end());
     Ptr<UeMeasure> neighbourCellMeasures;
-    std::map<uint16_t, Ptr<UeMeasure>>::iterator it2;
-    it2 = it1->second.find(cellId);
+    auto it2 = it1->second.find(cellId);
 
     if (it2 != it1->second.end())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/a3-rsrp-handover-algorithm.cc ns-3.40/src/lte/model/a3-rsrp-handover-algorithm.cc
--- ns-3.39/src/lte/model/a3-rsrp-handover-algorithm.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/model/a3-rsrp-handover-algorithm.cc	2023-09-27 13:30:37.706839300 -0700
@@ -135,8 +135,7 @@
         uint16_t bestNeighbourCellId = 0;
         uint8_t bestNeighbourRsrp = 0;
 
-        for (std::list<LteRrcSap::MeasResultEutra>::iterator it =
-                 measResults.measResultListEutra.begin();
+        for (auto it = measResults.measResultListEutra.begin();
              it != measResults.measResultListEutra.end();
              ++it)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/cqa-ff-mac-scheduler.cc ns-3.40/src/lte/model/cqa-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/cqa-ff-mac-scheduler.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/model/cqa-ff-mac-scheduler.cc	2023-09-27 13:30:37.706839300 -0700
@@ -248,7 +248,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, uint8_t>(params.m_rnti, params.m_transmissionMode));
@@ -300,9 +300,7 @@
     // LTE MAC scheduler specification
     if (params.m_reconfigureFlag)
     {
-        std::vector<LogicalChannelConfigListElement_s>::const_iterator lcit;
-
-        for (lcit = params.m_logicalChannelConfigList.begin();
+        for (auto lcit = params.m_logicalChannelConfigList.begin();
              lcit != params.m_logicalChannelConfigList.end();
              lcit++)
         {
@@ -322,9 +320,7 @@
     } // else new UE is added
     else
     {
-        std::vector<LogicalChannelConfigListElement_s>::const_iterator lcit;
-
-        for (lcit = params.m_logicalChannelConfigList.begin();
+        for (auto lcit = params.m_logicalChannelConfigList.begin();
              lcit != params.m_logicalChannelConfigList.end();
              lcit++)
         {
@@ -334,11 +330,9 @@
         }
     }
 
-    std::map<uint16_t, CqasFlowPerf_t>::iterator it;
-
     for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
     {
-        it = m_flowStatsDl.find(params.m_rnti);
+        auto it = m_flowStatsDl.find(params.m_rnti);
 
         if (it == m_flowStatsDl.end())
         {
@@ -382,9 +376,9 @@
     const FfMacCschedSapProvider::CschedLcReleaseReqParameters& params)
 {
     NS_LOG_FUNCTION(this);
-    std::vector<uint8_t>::const_iterator it;
 
-    for (it = params.m_logicalChannelIdentity.begin(); it != params.m_logicalChannelIdentity.end();
+    for (auto it = params.m_logicalChannelIdentity.begin();
+         it != params.m_logicalChannelIdentity.end();
          it++)
     {
         LteFlowId_t flowId = LteFlowId_t(params.m_rnti, *it);
@@ -404,15 +398,13 @@
 
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).first.m_rnti == params.m_rnti) &&
                 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
             {
-                temp = it;
+                auto temp = it;
                 it++;
                 m_rlcBufferReq.erase(temp);
             }
@@ -453,14 +445,12 @@
     m_flowStatsDl.erase(params.m_rnti);
     m_flowStatsUl.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).first.m_rnti == params.m_rnti)
         {
-            temp = it;
+            auto temp = it;
             it++;
             m_rlcBufferReq.erase(temp);
         }
@@ -482,11 +472,9 @@
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
 
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-
     LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
 
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
 
     if (it == m_rlcBufferReq.end())
     {
@@ -533,9 +521,8 @@
 unsigned int
 CqaFfMacScheduler::LcActivePerFlow(uint16_t rnti)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     unsigned int lcActive = 0;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
                                              ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
@@ -556,13 +543,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -586,13 +572,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -621,8 +606,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -632,8 +616,7 @@
                 // reset HARQ process
 
                 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -667,7 +650,6 @@
     int numberOfRBGs = m_cschedCellConfig.m_dlBandwidth / rbgSize;
     std::map<uint16_t, std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>>
         allocationMapPerRntiPerLCId;
-    std::map<uint16_t, std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>>::iterator itMap;
     allocationMapPerRntiPerLCId.clear();
     bool (*key_function_pointer_groups)(int, int) = CqaGroupDescComparator;
     t_map_HOLgroupToUEs map_GBRHOLgroupToUE(key_function_pointer_groups);
@@ -681,7 +663,7 @@
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
 
     rbgMap = m_ffrSapProvider->GetAvailableDlRbg();
-    for (std::vector<bool>::iterator it = rbgMap.begin(); it != rbgMap.end(); it++)
+    for (auto it = rbgMap.begin(); it != rbgMap.end(); it++)
     {
         if (*it)
         {
@@ -691,9 +673,9 @@
 
     FfMacSchedSapUser::SchedDlConfigIndParameters ret;
 
-    //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    // update UL HARQ proc id
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -709,7 +691,7 @@
     uint16_t tmpFfrRbStartOffset = 0;
     uint16_t index = 0;
 
-    for (std::vector<bool>::iterator it = ulRbMap.begin(); it != ulRbMap.end(); it++)
+    for (auto it = ulRbMap.begin(); it != ulRbMap.end(); it++)
     {
         if (*it)
         {
@@ -740,8 +722,7 @@
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
     rbStart = ffrRbStartOffset;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -805,15 +786,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -855,7 +834,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -883,8 +862,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -905,16 +883,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1001,8 +977,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -1079,8 +1054,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -1093,15 +1067,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -1127,13 +1100,11 @@
         return;
     }
 
-    std::map<LteFlowId_t, LogicalChannelConfigListElement_s>::iterator itLogicalChannels;
-
-    for (itLogicalChannels = m_ueLogicalChannelsConfigList.begin();
+    for (auto itLogicalChannels = m_ueLogicalChannelsConfigList.begin();
          itLogicalChannels != m_ueLogicalChannelsConfigList.end();
          itLogicalChannels++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(itLogicalChannels->first.m_rnti);
+        auto itRnti = rntiAllocated.find(itLogicalChannels->first.m_rnti);
         if ((itRnti != rntiAllocated.end()) ||
             (!HarqProcessAvailability(itLogicalChannels->first.m_rnti)))
         {
@@ -1151,8 +1122,7 @@
             continue;
         }
 
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itRlcBufferReq = m_rlcBufferReq.find(itLogicalChannels->first);
+        auto itRlcBufferReq = m_rlcBufferReq.find(itLogicalChannels->first);
         if (itRlcBufferReq == m_rlcBufferReq.end())
         {
             continue;
@@ -1219,17 +1189,12 @@
     // channels) that belong to the same RNTI
     std::map<uint16_t, uint8_t> sbCqiSum;
 
-    for (std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-             itrbr = m_rlcBufferReq.begin();
-         itrbr != m_rlcBufferReq.end();
-         itrbr++)
+    for (auto itrbr = m_rlcBufferReq.begin(); itrbr != m_rlcBufferReq.end(); itrbr++)
     {
         LteFlowId_t flowId = itrbr->first; // Prepare data for the scheduling mechanism
         // check first the channel conditions for this UE, if CQI!=0
-        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-        itCqi = m_a30CqiRxed.find((*itrbr).first.m_rnti);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itrbr).first.m_rnti);
+        auto itCqi = m_a30CqiRxed.find((*itrbr).first.m_rnti);
+        auto itTxMode = m_uesTxMode.find((*itrbr).first.m_rnti);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itrbr).first.m_rnti);
@@ -1270,10 +1235,8 @@
         uint8_t sum = 0;
         for (int i = 0; i < numberOfRBGs; i++)
         {
-            std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-            itCqi = m_a30CqiRxed.find((*itrbr).first.m_rnti);
-            std::map<uint16_t, uint8_t>::iterator itTxMode;
-            itTxMode = m_uesTxMode.find((*itrbr).first.m_rnti);
+            auto itCqi = m_a30CqiRxed.find((*itrbr).first.m_rnti);
+            auto itTxMode = m_uesTxMode.find((*itrbr).first.m_rnti);
             if (itTxMode == m_uesTxMode.end())
             {
                 NS_FATAL_ERROR("No Transmission Mode info on user " << (*itrbr).first.m_rnti);
@@ -1282,10 +1245,7 @@
             std::vector<uint8_t> sbCqis;
             if (itCqi == m_a30CqiRxed.end())
             {
-                for (uint8_t k = 0; k < nLayer; k++)
-                {
-                    sbCqis.push_back(1); // start with lowest value
-                }
+                sbCqis = std::vector<uint8_t>(nLayer, 1); // start with lowest value
             }
             else
             {
@@ -1332,8 +1292,8 @@
         }
     }
 
-    t_it_HOLgroupToUEs itGBRgroups = map_GBRHOLgroupToUE.begin();
-    t_it_HOLgroupToUEs itnonGBRgroups = map_nonGBRHOLgroupToUE.begin();
+    auto itGBRgroups = map_GBRHOLgroupToUE.begin();
+    auto itnonGBRgroups = map_nonGBRHOLgroupToUE.begin();
 
     // while there are more resources available, loop through the users that are grouped by HOL
     // value
@@ -1380,9 +1340,7 @@
 
             // Iterate through the users and calculate which user will use the best of the current
             // resource block.end() and assign to that user.
-            for (std::set<LteFlowId_t>::iterator it = itCurrentGroup->second.begin();
-                 it != itCurrentGroup->second.end();
-                 it++)
+            for (auto it = itCurrentGroup->second.begin(); it != itCurrentGroup->second.end(); it++)
             {
                 LteFlowId_t flowId = *it;
                 uint8_t cqi_value = 1; // higher better, maximum is 15
@@ -1393,10 +1351,7 @@
                 int numberOfRBGAllocatedForThisUser = 0;
                 LogicalChannelConfigListElement_s lc =
                     m_ueLogicalChannelsConfigList.find(flowId)->second;
-                std::map<uint16_t, SbMeasResult_s>::iterator itRntiCQIsMap =
-                    m_a30CqiRxed.find(flowId.m_rnti);
-
-                std::map<uint16_t, CqasFlowPerf_t>::iterator itStats;
+                auto itRntiCQIsMap = m_a30CqiRxed.find(flowId.m_rnti);
 
                 if (!m_ffrSapProvider->IsDlRbgAvailableForUe(currentRB, flowId.m_rnti))
                 {
@@ -1409,7 +1364,7 @@
                 }
                 currentRBchecked = true;
 
-                itStats = m_flowStatsDl.find(flowId.m_rnti);
+                auto itStats = m_flowStatsDl.find(flowId.m_rnti);
                 double tbr_weight =
                     (*itStats).second.targetThroughput / (*itStats).second.lastAveragedThroughput;
                 if (tbr_weight < 1.0)
@@ -1419,9 +1374,7 @@
 
                 if (itRntiCQIsMap != m_a30CqiRxed.end())
                 {
-                    for (std::set<int>::iterator it = availableRBGs.begin();
-                         it != availableRBGs.end();
-                         it++)
+                    for (auto it = availableRBGs.begin(); it != availableRBGs.end(); it++)
                     {
                         try
                         {
@@ -1462,7 +1415,7 @@
                     numberOfRBGAllocatedForThisUser =
                         (allocationMapPerRntiPerLCId.find(flowId.m_rnti)->second.size());
 
-                    for (std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>::iterator itRBG =
+                    for (auto itRBG =
                              allocationMapPerRntiPerLCId.find(flowId.m_rnti)->second.begin();
                          itRBG != allocationMapPerRntiPerLCId.find(flowId.m_rnti)->second.end();
                          itRBG++)
@@ -1564,7 +1517,7 @@
             s.cqi_value_for_lc = UeToCQIValue.find(userWithMaximumMetric)->second;
             s.resource_block_index = currentRB;
 
-            itMap = allocationMapPerRntiPerLCId.find(userWithMaximumMetric.m_rnti);
+            auto itMap = allocationMapPerRntiPerLCId.find(userWithMaximumMetric.m_rnti);
 
             if (itMap == allocationMapPerRntiPerLCId.end())
             {
@@ -1598,8 +1551,7 @@
     }     // while there are more groups of users
 
     // reset TTI stats of users
-    std::map<uint16_t, CqasFlowPerf_t>::iterator itStats;
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         (*itStats).second.lastTtiBytesTransmitted = 0;
     }
@@ -1607,7 +1559,7 @@
     // 3) Creating the correspondent DCIs (Generate the transmission opportunities by grouping the
     // RBGs of the same RNTI)
     // FfMacSchedSapUser::SchedDlConfigIndParameters ret;
-    itMap = allocationMapPerRntiPerLCId.begin();
+    auto itMap = allocationMapPerRntiPerLCId.begin();
     std::map<uint16_t, double> m_rnti_per_ratio;
 
     while (itMap != allocationMapPerRntiPerLCId.end())
@@ -1632,15 +1584,10 @@
         double doubleRbgNum = numberOfRBGs;
         double rrRatio = doubleRBgPerRnti / doubleRbgNum;
         m_rnti_per_ratio.insert(std::pair<uint16_t, double>((*itMap).first, rrRatio));
-        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-        itCqi = m_a30CqiRxed.find((*itMap).first);
         uint8_t worstCqi = 15;
 
         // assign the worst value of CQI that user experienced on any of its subbands
-        for (std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>::iterator it =
-                 (*itMap).second.begin();
-             it != (*itMap).second.end();
-             it++)
+        for (auto it = (*itMap).second.begin(); it != (*itMap).second.end(); it++)
         {
             if (it->second.cqi_value_for_lc < worstCqi)
             {
@@ -1655,8 +1602,7 @@
         newDci.m_resAlloc = 0; // only allocation type 0 at this stage
         newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
         uint32_t rbgMask = 0;
-        std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>::iterator itRBGsPerRNTI;
-        for (itRBGsPerRNTI = (*itMap).second.begin(); itRBGsPerRNTI != (*itMap).second.end();
+        for (auto itRBGsPerRNTI = (*itMap).second.begin(); itRBGsPerRNTI != (*itMap).second.end();
              itRBGsPerRNTI++)
         {
             rbgMask = rbgMask + (0x1 << itRBGsPerRNTI->second.resource_block_index);
@@ -1664,9 +1610,7 @@
         newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
         // NOTE: In this first version of CqaFfMacScheduler, it is assumed one flow per user.
         // create the rlc PDUs -> equally divide resources among active LCs
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itBufReq;
-        for (itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
+        for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
         {
             if (((*itBufReq).first.m_rnti == (*itMap).first) &&
                 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
@@ -1689,8 +1633,7 @@
                 if (m_harqOn)
                 {
                     // store RLC PDU list for HARQ
-                    std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                        m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
+                    auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
                     if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                     {
                         NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1720,8 +1663,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1729,8 +1671,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1742,8 +1683,7 @@
 
         ret.m_buildDataList.push_back(newEl);
         // update UE stats
-        std::map<uint16_t, CqasFlowPerf_t>::iterator it;
-        it = m_flowStatsDl.find((*itMap).first);
+        auto it = m_flowStatsDl.find((*itMap).first);
         if (it != m_flowStatsDl.end())
         {
             (*it).second.lastTtiBytesTransmitted = tbSize;
@@ -1759,7 +1699,7 @@
 
     // update UEs stats
     NS_LOG_INFO(this << " Update UEs statistics");
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         if (allocationMapPerRntiPerLCId.find(itStats->first) != allocationMapPerRntiPerLCId.end())
         {
@@ -1782,8 +1722,7 @@
     m_schedSapUser->SchedDlConfigInd(ret);
 
     int count_allocated_resource_blocks = 0;
-    for (std::map<uint16_t, std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>>::iterator itMap =
-             allocationMapPerRntiPerLCId.begin();
+    for (auto itMap = allocationMapPerRntiPerLCId.begin();
          itMap != allocationMapPerRntiPerLCId.end();
          itMap++)
     {
@@ -1814,9 +1753,8 @@
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1831,17 +1769,15 @@
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
         else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
         {
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_a30CqiRxed.find(rnti);
+            auto it = m_a30CqiRxed.find(rnti);
             if (it == m_a30CqiRxed.end())
             {
                 // create the new entry
@@ -1854,8 +1790,7 @@
             {
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_a30CqiTimers.find(rnti);
+                auto itTimers = m_a30CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1869,7 +1804,7 @@
 double
 CqaFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find(rnti);
+    auto itCqi = m_ueCqi.find(rnti);
     if (itCqi == m_ueCqi.end())
     {
         // no cqi info about this UE
@@ -1922,7 +1857,7 @@
 
     rbMap = m_ffrSapProvider->GetAvailableUlRbg();
 
-    for (std::vector<bool>::iterator it = rbMap.begin(); it != rbMap.end(); it++)
+    for (auto it = rbMap.begin(); it != rbMap.end(); it++)
     {
         if (*it)
         {
@@ -1952,8 +1887,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1961,16 +1895,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
                                  << " i " << i << " size " << params.m_ulInfoList.size());
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                     continue;
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -2030,7 +1962,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
         {
@@ -2063,7 +1995,6 @@
     }
     int rbAllocated = 0;
 
-    std::map<uint16_t, CqasFlowPerf_t>::iterator itStats;
     if (m_nextRntiUl != 0)
     {
         for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
@@ -2085,7 +2016,7 @@
     }
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -2178,7 +2109,7 @@
             break;
         }
 
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -2249,15 +2180,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -2265,8 +2194,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -2282,7 +2210,7 @@
                          << (uint16_t)harqId);
 
         // update TTI  UE stats
-        itStats = m_flowStatsUl.find((*it).first);
+        auto itStats = m_flowStatsUl.find((*it).first);
         if (itStats != m_flowStatsUl.end())
         {
             (*itStats).second.lastTtiBytesTransmitted = uldci.m_tbSize;
@@ -2308,7 +2236,7 @@
 
     // Update global UE stats
     // update UEs stats
-    for (itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
+    for (auto itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
     {
         (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
         // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
@@ -2345,8 +2273,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -2367,7 +2293,7 @@
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
             NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -2413,11 +2339,9 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
         NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
                           << " subframe no. " << (0xF & params.m_sfnSf));
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             return;
@@ -2426,7 +2350,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -2456,8 +2380,7 @@
                 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
                                   << sinr);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -2480,8 +2403,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -2508,8 +2430,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -2529,7 +2450,7 @@
 CqaFfMacScheduler::RefreshDlCqiMaps()
 {
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -2537,12 +2458,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -2554,7 +2475,7 @@
     }
 
     // refresh DL CQI A30 Map
-    std::map<uint16_t, uint32_t>::iterator itA30 = m_a30CqiTimers.begin();
+    auto itA30 = m_a30CqiTimers.begin();
     while (itA30 != m_a30CqiTimers.end())
     {
         NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
@@ -2562,12 +2483,12 @@
         if ((*itA30).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find((*itA30).first);
+            auto itMap = m_a30CqiRxed.find((*itA30).first);
             NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
                           " Does not find CQI report for user " << (*itA30).first);
             NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
             m_a30CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itA30;
+            auto temp = itA30;
             itA30++;
             m_a30CqiTimers.erase(temp);
         }
@@ -2583,7 +2504,7 @@
 CqaFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -2591,13 +2512,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -2612,9 +2533,8 @@
 void
 CqaFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     LteFlowId_t flow(rnti, lcid);
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
     if (it != m_rlcBufferReq.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
@@ -2669,7 +2589,7 @@
 CqaFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/epc-enb-application.cc ns-3.40/src/lte/model/epc-enb-application.cc
--- ns-3.39/src/lte/model/epc-enb-application.cc	2023-07-05 14:23:47.901427700 -0700
+++ ns-3.40/src/lte/model/epc-enb-application.cc	2023-09-27 13:30:37.706839300 -0700
@@ -164,9 +164,7 @@
 
     uint16_t gci = params.cellId;
     std::list<EpcS1apSapMme::ErabSwitchedInDownlinkItem> erabToBeSwitchedInDownlinkList;
-    for (std::list<EpcEnbS1SapProvider::BearerToBeSwitched>::iterator bit =
-             params.bearersToBeSwitched.begin();
-         bit != params.bearersToBeSwitched.end();
+    for (auto bit = params.bearersToBeSwitched.begin(); bit != params.bearersToBeSwitched.end();
          ++bit)
     {
         EpsFlowId_t flowId;
@@ -193,12 +191,10 @@
 EpcEnbApplication::DoUeContextRelease(uint16_t rnti)
 {
     NS_LOG_FUNCTION(this << rnti);
-    std::map<uint16_t, std::map<uint8_t, uint32_t>>::iterator rntiIt = m_rbidTeidMap.find(rnti);
+    auto rntiIt = m_rbidTeidMap.find(rnti);
     if (rntiIt != m_rbidTeidMap.end())
     {
-        for (std::map<uint8_t, uint32_t>::iterator bidIt = rntiIt->second.begin();
-             bidIt != rntiIt->second.end();
-             ++bidIt)
+        for (auto bidIt = rntiIt->second.begin(); bidIt != rntiIt->second.end(); ++bidIt)
         {
             uint32_t teid = bidIt->second;
             m_teidRbidMap.erase(teid);
@@ -218,13 +214,11 @@
     NS_LOG_FUNCTION(this);
 
     uint64_t imsi = mmeUeS1Id;
-    std::map<uint64_t, uint16_t>::iterator imsiIt = m_imsiRntiMap.find(imsi);
+    auto imsiIt = m_imsiRntiMap.find(imsi);
     NS_ASSERT_MSG(imsiIt != m_imsiRntiMap.end(), "unknown IMSI");
     uint16_t rnti = imsiIt->second;
 
-    for (std::list<EpcS1apSapEnb::ErabToBeSetupItem>::iterator erabIt = erabToBeSetupList.begin();
-         erabIt != erabToBeSetupList.end();
-         ++erabIt)
+    for (auto erabIt = erabToBeSetupList.begin(); erabIt != erabToBeSetupList.end(); ++erabIt)
     {
         // request the RRC to setup a radio bearer
         EpcEnbS1SapUser::DataRadioBearerSetupRequestParameters params;
@@ -256,7 +250,7 @@
     NS_LOG_FUNCTION(this);
 
     uint64_t imsi = mmeUeS1Id;
-    std::map<uint64_t, uint16_t>::iterator imsiIt = m_imsiRntiMap.find(imsi);
+    auto imsiIt = m_imsiRntiMap.find(imsi);
     NS_ASSERT_MSG(imsiIt != m_imsiRntiMap.end(), "unknown IMSI");
     uint16_t rnti = imsiIt->second;
     EpcEnbS1SapUser::PathSwitchRequestAcknowledgeParameters params;
@@ -283,15 +277,15 @@
     NS_ASSERT(found);
     uint16_t rnti = tag.GetRnti();
     uint8_t bid = tag.GetBid();
-    NS_LOG_LOGIC("received packet with RNTI=" << (uint32_t)rnti << ", BID=" << (uint32_t)bid);
-    std::map<uint16_t, std::map<uint8_t, uint32_t>>::iterator rntiIt = m_rbidTeidMap.find(rnti);
+    NS_LOG_INFO("Received packet with RNTI: " << rnti << ", BID: " << +bid);
+    auto rntiIt = m_rbidTeidMap.find(rnti);
     if (rntiIt == m_rbidTeidMap.end())
     {
         NS_LOG_WARN("UE context not found, discarding packet");
     }
     else
     {
-        std::map<uint8_t, uint32_t>::iterator bidIt = rntiIt->second.find(bid);
+        auto bidIt = rntiIt->second.find(bid);
         NS_ASSERT(bidIt != rntiIt->second.end());
         uint32_t teid = bidIt->second;
         m_rxLteSocketPktTrace(packet->Copy());
@@ -308,7 +302,8 @@
     GtpuHeader gtpu;
     packet->RemoveHeader(gtpu);
     uint32_t teid = gtpu.GetTeid();
-    std::map<uint32_t, EpsFlowId_t>::iterator it = m_teidRbidMap.find(teid);
+    NS_LOG_INFO("Received packet from S1-U interface with GTP TEID: " << teid);
+    auto it = m_teidRbidMap.find(teid);
     if (it == m_teidRbidMap.end())
     {
         NS_LOG_WARN("UE context at cell id " << m_cellId << " not found, discarding packet");
@@ -323,9 +318,10 @@
 void
 EpcEnbApplication::SendToLteSocket(Ptr<Packet> packet, uint16_t rnti, uint8_t bid)
 {
-    NS_LOG_FUNCTION(this << packet << rnti << (uint16_t)bid << packet->GetSize());
+    NS_LOG_FUNCTION(this << packet << rnti << bid << packet->GetSize());
     EpsBearerTag tag(rnti, bid);
     packet->AddPacketTag(tag);
+    NS_LOG_INFO("Add EpsBearerTag with RNTI " << rnti << " and bearer ID " << +bid);
     uint8_t ipType;
 
     packet->CopyData(&ipType, 1);
@@ -334,10 +330,12 @@
     int sentBytes;
     if (ipType == 0x04)
     {
+        NS_LOG_INFO("Forward packet from eNB's S1-U to LTE stack via IPv4 socket.");
         sentBytes = m_lteSocket->Send(packet);
     }
     else if (ipType == 0x06)
     {
+        NS_LOG_INFO("Forward packet from eNB's S1-U to LTE stack via IPv6 socket.");
         sentBytes = m_lteSocket6->Send(packet);
     }
     else
@@ -359,6 +357,7 @@
     gtpu.SetLength(packet->GetSize() + gtpu.GetSerializedSize() - 8);
     packet->AddHeader(gtpu);
     uint32_t flags = 0;
+    NS_LOG_INFO("Forward packet from eNB's LTE to S1-U stack with TEID: " << teid);
     m_s1uSocket->SendTo(packet, flags, InetSocketAddress(m_sgwS1uAddress, m_gtpuUdpPort));
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/epc-mme-application.cc ns-3.40/src/lte/model/epc-mme-application.cc
--- ns-3.39/src/lte/model/epc-mme-application.cc	2023-07-05 14:23:47.905427700 -0700
+++ ns-3.40/src/lte/model/epc-mme-application.cc	2023-09-27 13:30:37.706839300 -0700
@@ -103,7 +103,7 @@
 EpcMmeApplication::AddBearer(uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer)
 {
     NS_LOG_FUNCTION(this << imsi);
-    std::map<uint64_t, Ptr<UeInfo>>::iterator it = m_ueInfoMap.find(imsi);
+    auto it = m_ueInfoMap.find(imsi);
     NS_ASSERT_MSG(it != m_ueInfoMap.end(), "could not find any UE with IMSI " << imsi);
     NS_ASSERT_MSG(it->second->bearerCounter < 11,
                   "too many bearers already! " << it->second->bearerCounter);
@@ -124,7 +124,7 @@
                                       uint16_t gci)
 {
     NS_LOG_FUNCTION(this << mmeUeS1Id << enbUeS1Id << imsi << gci);
-    std::map<uint64_t, Ptr<UeInfo>>::iterator it = m_ueInfoMap.find(imsi);
+    auto it = m_ueInfoMap.find(imsi);
     NS_ASSERT_MSG(it != m_ueInfoMap.end(), "could not find any UE with IMSI " << imsi);
     it->second->cellId = gci;
 
@@ -139,7 +139,7 @@
     msg.SetSenderCpFteid(mmeS11Fteid); // S11 MME GTP-C F-TEID
 
     std::list<GtpcCreateSessionRequestMessage::BearerContextToBeCreated> bearerContexts;
-    for (std::list<BearerInfo>::iterator bit = it->second->bearersToBeActivated.begin();
+    for (auto bit = it->second->bearersToBeActivated.begin();
          bit != it->second->bearersToBeActivated.end();
          ++bit)
     {
@@ -180,7 +180,7 @@
 {
     NS_LOG_FUNCTION(this << mmeUeS1Id << enbUeS1Id << gci);
     uint64_t imsi = mmeUeS1Id;
-    std::map<uint64_t, Ptr<UeInfo>>::iterator it = m_ueInfoMap.find(imsi);
+    auto it = m_ueInfoMap.find(imsi);
     NS_ASSERT_MSG(it != m_ueInfoMap.end(), "could not find any UE with IMSI " << imsi);
     NS_LOG_INFO("IMSI " << imsi << " old eNB: " << it->second->cellId << ", new eNB: " << gci);
     it->second->cellId = gci;
@@ -221,7 +221,7 @@
 {
     NS_LOG_FUNCTION(this << mmeUeS1Id << enbUeS1Id);
     uint64_t imsi = mmeUeS1Id;
-    std::map<uint64_t, Ptr<UeInfo>>::iterator it = m_ueInfoMap.find(imsi);
+    auto it = m_ueInfoMap.find(imsi);
     NS_ASSERT_MSG(it != m_ueInfoMap.end(), "could not find any UE with IMSI " << imsi);
 
     GtpcDeleteBearerCommandMessage msg;
@@ -247,7 +247,7 @@
 EpcMmeApplication::RemoveBearer(Ptr<UeInfo> ueInfo, uint8_t epsBearerId)
 {
     NS_LOG_FUNCTION(this << epsBearerId);
-    std::list<BearerInfo>::iterator bit = ueInfo->bearersToBeActivated.begin();
+    auto bit = ueInfo->bearersToBeActivated.begin();
     while (bit != ueInfo->bearersToBeActivated.end())
     {
         if (bit->bearerId == epsBearerId)
@@ -296,13 +296,13 @@
     NS_LOG_FUNCTION(this << header);
     uint64_t imsi = header.GetTeid();
     NS_LOG_DEBUG("TEID/IMSI " << imsi);
-    std::map<uint64_t, Ptr<UeInfo>>::iterator it = m_ueInfoMap.find(imsi);
+    auto it = m_ueInfoMap.find(imsi);
     NS_ASSERT_MSG(it != m_ueInfoMap.end(), "could not find any UE with IMSI " << imsi);
     uint16_t cellId = it->second->cellId;
     uint16_t enbUeS1Id = it->second->enbUeS1Id;
     uint64_t mmeUeS1Id = it->second->mmeUeS1Id;
     NS_LOG_DEBUG("cellId " << cellId << " mmeUeS1Id " << mmeUeS1Id << " enbUeS1Id " << enbUeS1Id);
-    std::map<uint16_t, Ptr<EnbInfo>>::iterator jt = m_enbInfoMap.find(cellId);
+    auto jt = m_enbInfoMap.find(cellId);
     NS_ASSERT_MSG(jt != m_enbInfoMap.end(), "could not find any eNB with CellId " << cellId);
 
     GtpcCreateSessionResponseMessage msg;
@@ -337,7 +337,7 @@
 
     uint64_t imsi = header.GetTeid();
     NS_LOG_DEBUG("TEID/IMSI " << imsi);
-    std::map<uint64_t, Ptr<UeInfo>>::iterator it = m_ueInfoMap.find(imsi);
+    auto it = m_ueInfoMap.find(imsi);
     NS_ASSERT_MSG(it != m_ueInfoMap.end(), "could not find any UE with IMSI " << imsi);
     uint16_t cellId = it->second->cellId;
     uint16_t enbUeS1Id = it->second->enbUeS1Id;
@@ -345,7 +345,7 @@
     NS_LOG_DEBUG("cellId " << cellId << " mmeUeS1Id " << mmeUeS1Id << " enbUeS1Id " << enbUeS1Id);
     std::list<EpcS1apSapEnb::ErabSwitchedInUplinkItem>
         erabToBeSwitchedInUplinkList; // unused for now
-    std::map<uint16_t, Ptr<EnbInfo>>::iterator jt = m_enbInfoMap.find(cellId);
+    auto jt = m_enbInfoMap.find(cellId);
     NS_ASSERT_MSG(jt != m_enbInfoMap.end(), "could not find any eNB with CellId " << cellId);
 
     NS_LOG_DEBUG("Send PathSwitchRequestAcknowledge to eNB " << jt->second->s1apSapEnb);
@@ -361,7 +361,7 @@
     NS_LOG_FUNCTION(this << header);
     uint64_t imsi = header.GetTeid();
     NS_LOG_DEBUG("TEID/IMSI " << imsi);
-    std::map<uint64_t, Ptr<UeInfo>>::iterator it = m_ueInfoMap.find(imsi);
+    auto it = m_ueInfoMap.find(imsi);
     NS_ASSERT_MSG(it != m_ueInfoMap.end(), "could not find any UE with IMSI " << imsi);
 
     GtpcDeleteBearerRequestMessage msg;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/epc-pgw-application.cc ns-3.40/src/lte/model/epc-pgw-application.cc
--- ns-3.39/src/lte/model/epc-pgw-application.cc	2023-07-05 14:23:47.905427700 -0700
+++ ns-3.40/src/lte/model/epc-pgw-application.cc	2023-09-27 13:30:37.706839300 -0700
@@ -58,7 +58,7 @@
 EpcPgwApplication::UeInfo::RemoveBearer(uint8_t bearerId)
 {
     NS_LOG_FUNCTION(this << (uint16_t)bearerId);
-    std::map<uint8_t, uint32_t>::iterator it = m_teidByBearerIdMap.find(bearerId);
+    auto it = m_teidByBearerIdMap.find(bearerId);
     m_tftClassifier.Delete(it->second); // delete tft
     m_teidByBearerIdMap.erase(bearerId);
 }
@@ -180,7 +180,7 @@
         NS_LOG_LOGIC("packet addressed to UE " << ueAddr);
 
         // find corresponding UeInfo address
-        std::map<Ipv4Address, Ptr<UeInfo>>::iterator it = m_ueInfoByAddrMap.find(ueAddr);
+        auto it = m_ueInfoByAddrMap.find(ueAddr);
         if (it == m_ueInfoByAddrMap.end())
         {
             NS_LOG_WARN("unknown UE address " << ueAddr);
@@ -207,7 +207,7 @@
         NS_LOG_LOGIC("packet addressed to UE " << ueAddr);
 
         // find corresponding UeInfo address
-        std::map<Ipv6Address, Ptr<UeInfo>>::iterator it = m_ueInfoByAddrMap6.find(ueAddr);
+        auto it = m_ueInfoByAddrMap6.find(ueAddr);
         if (it == m_ueInfoByAddrMap6.end())
         {
             NS_LOG_WARN("unknown UE address " << ueAddr);
@@ -298,7 +298,7 @@
     uint16_t cellId = msg.GetUliEcgi();
     NS_LOG_DEBUG("cellId " << cellId << " IMSI " << imsi);
 
-    std::map<uint64_t, Ptr<UeInfo>>::iterator ueit = m_ueInfoByImsiMap.find(imsi);
+    auto ueit = m_ueInfoByImsiMap.find(imsi);
     NS_ASSERT_MSG(ueit != m_ueInfoByImsiMap.end(), "unknown IMSI " << imsi);
     ueit->second->SetSgwAddr(m_sgwS5Addr);
 
@@ -360,7 +360,7 @@
     uint16_t cellId = msg.GetUliEcgi();
     NS_LOG_DEBUG("cellId " << cellId << " IMSI " << imsi);
 
-    std::map<uint64_t, Ptr<UeInfo>>::iterator ueit = m_ueInfoByImsiMap.find(imsi);
+    auto ueit = m_ueInfoByImsiMap.find(imsi);
     NS_ASSERT_MSG(ueit != m_ueInfoByImsiMap.end(), "unknown IMSI " << imsi);
     ueit->second->SetSgwAddr(m_sgwS5Addr);
 
@@ -422,7 +422,7 @@
     packet->RemoveHeader(msg);
 
     uint64_t imsi = msg.GetTeid();
-    std::map<uint64_t, Ptr<UeInfo>>::iterator ueit = m_ueInfoByImsiMap.find(imsi);
+    auto ueit = m_ueInfoByImsiMap.find(imsi);
     NS_ASSERT_MSG(ueit != m_ueInfoByImsiMap.end(), "unknown IMSI " << imsi);
 
     for (auto& epsBearerId : msg.GetEpsBearerIds())
@@ -498,7 +498,7 @@
 EpcPgwApplication::SetUeAddress(uint64_t imsi, Ipv4Address ueAddr)
 {
     NS_LOG_FUNCTION(this << imsi << ueAddr);
-    std::map<uint64_t, Ptr<UeInfo>>::iterator ueit = m_ueInfoByImsiMap.find(imsi);
+    auto ueit = m_ueInfoByImsiMap.find(imsi);
     NS_ASSERT_MSG(ueit != m_ueInfoByImsiMap.end(), "unknown IMSI" << imsi);
     ueit->second->SetUeAddr(ueAddr);
     m_ueInfoByAddrMap[ueAddr] = ueit->second;
@@ -508,7 +508,7 @@
 EpcPgwApplication::SetUeAddress6(uint64_t imsi, Ipv6Address ueAddr)
 {
     NS_LOG_FUNCTION(this << imsi << ueAddr);
-    std::map<uint64_t, Ptr<UeInfo>>::iterator ueit = m_ueInfoByImsiMap.find(imsi);
+    auto ueit = m_ueInfoByImsiMap.find(imsi);
     NS_ASSERT_MSG(ueit != m_ueInfoByImsiMap.end(), "unknown IMSI " << imsi);
     m_ueInfoByAddrMap6[ueAddr] = ueit->second;
     ueit->second->SetUeAddr6(ueAddr);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/epc-sgw-application.cc ns-3.40/src/lte/model/epc-sgw-application.cc
--- ns-3.39/src/lte/model/epc-sgw-application.cc	2023-07-05 14:23:47.905427700 -0700
+++ ns-3.40/src/lte/model/epc-sgw-application.cc	2023-09-27 13:30:37.706839300 -0700
@@ -235,7 +235,7 @@
     uint16_t cellId = msg.GetUliEcgi();
     NS_LOG_DEBUG("cellId " << cellId << " IMSI " << imsi);
 
-    std::map<uint16_t, EnbInfo>::iterator enbit = m_enbInfoByCellId.find(cellId);
+    auto enbit = m_enbInfoByCellId.find(cellId);
     NS_ASSERT_MSG(enbit != m_enbInfoByCellId.end(), "unknown CellId " << cellId);
     Ipv4Address enbAddr = enbit->second.enbAddr;
     NS_LOG_DEBUG("eNB " << enbAddr);
@@ -301,7 +301,7 @@
     uint16_t cellId = msg.GetUliEcgi();
     NS_LOG_DEBUG("cellId " << cellId << " IMSI " << imsi);
 
-    std::map<uint16_t, EnbInfo>::iterator enbit = m_enbInfoByCellId.find(cellId);
+    auto enbit = m_enbInfoByCellId.find(cellId);
     NS_ASSERT_MSG(enbit != m_enbInfoByCellId.end(), "unknown CellId " << cellId);
     Ipv4Address enbAddr = enbit->second.enbAddr;
     NS_LOG_DEBUG("eNB " << enbAddr);
@@ -321,7 +321,7 @@
         uint32_t teid = bearerContext.fteid.teid;
         Ipv4Address enbAddr = bearerContext.fteid.addr;
         NS_LOG_DEBUG("bearerId " << (uint16_t)bearerContext.epsBearerId << " TEID " << teid);
-        std::map<uint32_t, Ipv4Address>::iterator addrit = m_enbByTeidMap.find(teid);
+        auto addrit = m_enbByTeidMap.find(teid);
         NS_ASSERT_MSG(addrit != m_enbByTeidMap.end(), "unknown TEID " << teid);
         addrit->second = enbAddr;
         GtpcModifyBearerRequestMessage::BearerContextToBeModified bearerContextOut;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/epc-tft.cc ns-3.40/src/lte/model/epc-tft.cc
--- ns-3.39/src/lte/model/epc-tft.cc	2023-07-05 14:23:47.905427700 -0700
+++ ns-3.40/src/lte/model/epc-tft.cc	2023-09-27 13:30:37.706839300 -0700
@@ -265,7 +265,7 @@
 {
     NS_LOG_FUNCTION(this << direction << remoteAddress << localAddress << std::dec << remotePort
                          << localPort << (uint16_t)typeOfService);
-    for (std::list<PacketFilter>::iterator it = m_filters.begin(); it != m_filters.end(); ++it)
+    for (auto it = m_filters.begin(); it != m_filters.end(); ++it)
     {
         if (it->Matches(direction,
                         remoteAddress,
@@ -290,7 +290,7 @@
 {
     NS_LOG_FUNCTION(this << direction << remoteAddress << localAddress << std::dec << remotePort
                          << localPort << (uint16_t)typeOfService);
-    for (std::list<PacketFilter>::iterator it = m_filters.begin(); it != m_filters.end(); ++it)
+    for (auto it = m_filters.begin(); it != m_filters.end(); ++it)
     {
         if (it->Matches(direction,
                         remoteAddress,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/epc-tft-classifier.cc ns-3.40/src/lte/model/epc-tft-classifier.cc
--- ns-3.39/src/lte/model/epc-tft-classifier.cc	2023-07-05 14:23:47.905427700 -0700
+++ ns-3.40/src/lte/model/epc-tft-classifier.cc	2023-09-27 13:30:37.706839300 -0700
@@ -187,9 +187,7 @@
                                 protocol,
                                 ipv4Header.GetIdentification());
 
-            std::map<std::tuple<uint32_t, uint32_t, uint8_t, uint16_t>,
-                     std::pair<uint32_t, uint32_t>>::iterator it =
-                m_classifiedIpv4Fragments.find(fragmentKey);
+            auto it = m_classifiedIpv4Fragments.find(fragmentKey);
 
             if (it != m_classifiedIpv4Fragments.end())
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/epc-ue-nas.cc ns-3.40/src/lte/model/epc-ue-nas.cc
--- ns-3.39/src/lte/model/epc-ue-nas.cc	2023-07-05 14:23:47.905427700 -0700
+++ ns-3.40/src/lte/model/epc-ue-nas.cc	2023-09-27 13:30:37.706839300 -0700
@@ -206,7 +206,7 @@
     case ACTIVE: {
         uint32_t id = m_tftClassifier.Classify(packet, EpcTft::UPLINK, protocolNumber);
         NS_ASSERT((id & 0xFFFFFF00) == 0);
-        uint8_t bid = (uint8_t)(id & 0x000000FF);
+        auto bid = (uint8_t)(id & 0x000000FF);
         if (bid == 0)
         {
             return false;
@@ -295,8 +295,7 @@
     switch (m_state)
     {
     case ACTIVE:
-        for (std::list<BearerToBeActivated>::iterator it = m_bearersToBeActivatedList.begin();
-             it != m_bearersToBeActivatedList.end();
+        for (auto it = m_bearersToBeActivatedList.begin(); it != m_bearersToBeActivatedList.end();
              m_bearersToBeActivatedList.erase(it++))
         {
             DoActivateEpsBearer(it->bearer, it->tft);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/epc-x2-header.cc ns-3.40/src/lte/model/epc-x2-header.cc
--- ns-3.39/src/lte/model/epc-x2-header.cc	2023-07-05 14:23:47.905427700 -0700
+++ ns-3.40/src/lte/model/epc-x2-header.cc	2023-09-27 13:30:37.706839300 -0700
@@ -1209,8 +1209,7 @@
         m_headerLength += 2;
         for (int k = 0; k < sz2; k++)
         {
-            EpcX2Sap::UlInterferenceOverloadIndicationItem item =
-                (EpcX2Sap::UlInterferenceOverloadIndicationItem)i.ReadU8();
+            auto item = (EpcX2Sap::UlInterferenceOverloadIndicationItem)i.ReadU8();
             cellInfoItem.ulInterferenceOverloadIndicationList.push_back(item);
         }
         m_headerLength += sz2;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/fdbet-ff-mac-scheduler.cc ns-3.40/src/lte/model/fdbet-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/fdbet-ff-mac-scheduler.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/fdbet-ff-mac-scheduler.cc	2023-09-27 13:30:37.814839600 -0700
@@ -159,7 +159,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, double>(params.m_rnti, params.m_transmissionMode));
@@ -205,10 +205,9 @@
 {
     NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
 
-    std::map<uint16_t, fdbetsFlowPerf_t>::iterator it;
     for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
     {
-        it = m_flowStatsDl.find(params.m_rnti);
+        auto it = m_flowStatsDl.find(params.m_rnti);
 
         if (it == m_flowStatsDl.end())
         {
@@ -235,15 +234,13 @@
     NS_LOG_FUNCTION(this);
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).first.m_rnti == params.m_rnti) &&
                 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
             {
-                temp = it;
+                auto temp = it;
                 it++;
                 m_rlcBufferReq.erase(temp);
             }
@@ -273,14 +270,12 @@
     m_flowStatsDl.erase(params.m_rnti);
     m_flowStatsUl.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).first.m_rnti == params.m_rnti)
         {
-            temp = it;
+            auto temp = it;
             it++;
             m_rlcBufferReq.erase(temp);
         }
@@ -302,11 +297,9 @@
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
 
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-
     LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
 
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
 
     if (it == m_rlcBufferReq.end())
     {
@@ -353,9 +346,8 @@
 unsigned int
 FdBetFfMacScheduler::LcActivePerFlow(uint16_t rnti)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     unsigned int lcActive = 0;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
                                              ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
@@ -376,13 +368,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -406,13 +397,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -441,8 +431,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -452,8 +441,7 @@
                 // reset HARQ process
 
                 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -493,9 +481,9 @@
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
     FfMacSchedSapUser::SchedDlConfigIndParameters ret;
 
-    //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    // update UL HARQ proc id
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -504,8 +492,7 @@
     // RACH Allocation
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -569,15 +556,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -619,7 +604,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -647,8 +632,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -669,16 +653,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -765,8 +747,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -843,8 +824,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -857,15 +837,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -891,15 +870,13 @@
         return;
     }
 
-    std::map<uint16_t, fdbetsFlowPerf_t>::iterator itFlow;
     std::map<uint16_t, double> estAveThr; // store expected average throughput for UE
-    std::map<uint16_t, double>::iterator itMax = estAveThr.end();
-    std::map<uint16_t, double>::iterator it;
+    auto itMax = estAveThr.end();
     std::map<uint16_t, int> rbgPerRntiLog; // record the number of RBG assigned to UE
     double metricMax = 0.0;
-    for (itFlow = m_flowStatsDl.begin(); itFlow != m_flowStatsDl.end(); itFlow++)
+    for (auto itFlow = m_flowStatsDl.begin(); itFlow != m_flowStatsDl.end(); itFlow++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*itFlow).first);
+        auto itRnti = rntiAllocated.find((*itFlow).first);
         if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*itFlow).first)))
         {
             // UE already allocated for HARQ or without HARQ process available -> drop it
@@ -915,10 +892,8 @@
         }
 
         // check first what are channel conditions for this UE, if CQI!=0
-        std::map<uint16_t, uint8_t>::iterator itCqi;
-        itCqi = m_p10CqiRxed.find((*itFlow).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itFlow).first);
+        auto itCqi = m_p10CqiRxed.find((*itFlow).first);
+        auto itTxMode = m_uesTxMode.find((*itFlow).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itFlow).first);
@@ -951,7 +926,7 @@
     if (!estAveThr.empty())
     {
         // Find UE with largest priority metric
-        for (it = estAveThr.begin(); it != estAveThr.end(); it++)
+        for (auto it = estAveThr.begin(); it != estAveThr.end(); it++)
         {
             double metric = 1 / (*it).second;
             if (metric > metricMax)
@@ -970,9 +945,8 @@
             if (!rbgMap.at(i))
             {
                 // allocate one RBG to current UE
-                std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
                 std::vector<uint16_t> tempMap;
-                itMap = allocationMap.find((*itMax).first);
+                auto itMap = allocationMap.find((*itMax).first);
                 if (itMap == allocationMap.end())
                 {
                     tempMap.push_back(i);
@@ -985,10 +959,8 @@
                 }
 
                 // calculate expected throughput for current UE
-                std::map<uint16_t, uint8_t>::iterator itCqi;
-                itCqi = m_p10CqiRxed.find((*itMax).first);
-                std::map<uint16_t, uint8_t>::iterator itTxMode;
-                itTxMode = m_uesTxMode.find((*itMax).first);
+                auto itCqi = m_p10CqiRxed.find((*itMax).first);
+                auto itTxMode = m_uesTxMode.find((*itMax).first);
                 if (itTxMode == m_uesTxMode.end())
                 {
                     NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMax).first);
@@ -1007,10 +979,8 @@
                     }
                 }
 
-                std::map<uint16_t, int>::iterator itRbgPerRntiLog;
-                itRbgPerRntiLog = rbgPerRntiLog.find((*itMax).first);
-                std::map<uint16_t, fdbetsFlowPerf_t>::iterator itPastAveThr;
-                itPastAveThr = m_flowStatsDl.find((*itMax).first);
+                auto itRbgPerRntiLog = rbgPerRntiLog.find((*itMax).first);
+                auto itPastAveThr = m_flowStatsDl.find((*itMax).first);
                 uint32_t bytesTxed = 0;
                 for (uint8_t j = 0; j < nLayer; j++)
                 {
@@ -1030,7 +1000,7 @@
 
                 // find new UE with largest priority metric
                 metricMax = 0.0;
-                for (it = estAveThr.begin(); it != estAveThr.end(); it++)
+                for (auto it = estAveThr.begin(); it != estAveThr.end(); it++)
                 {
                     double metric = 1 / (*it).second;
                     if (metric > metricMax)
@@ -1051,15 +1021,14 @@
     } // end if estAveThr
 
     // reset TTI stats of users
-    std::map<uint16_t, fdbetsFlowPerf_t>::iterator itStats;
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         (*itStats).second.lastTtiBytesTrasmitted = 0;
     }
 
     // generate the transmission opportunities by grouping the RBGs of the same RNTI and
     // creating the correspondent DCIs
-    std::map<uint16_t, std::vector<uint16_t>>::iterator itMap = allocationMap.begin();
+    auto itMap = allocationMap.begin();
     while (itMap != allocationMap.end())
     {
         // create new BuildDataListElement_s for this LC
@@ -1078,10 +1047,8 @@
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
         uint16_t RgbPerRnti = (*itMap).second.size();
-        std::map<uint16_t, uint8_t>::iterator itCqi;
-        itCqi = m_p10CqiRxed.find((*itMap).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itMap).first);
+        auto itCqi = m_p10CqiRxed.find((*itMap).first);
+        auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
@@ -1117,9 +1084,7 @@
         newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
 
         // create the rlc PDUs -> equally divide resources among actives LCs
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itBufReq;
-        for (itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
+        for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
         {
             if (((*itBufReq).first.m_rnti == (*itMap).first) &&
                 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
@@ -1141,8 +1106,7 @@
                     if (m_harqOn)
                     {
                         // store RLC PDU list for HARQ
-                        std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                            m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
+                        auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
                         if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                         {
                             NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1171,8 +1135,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1180,8 +1143,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1193,8 +1155,7 @@
 
         ret.m_buildDataList.push_back(newEl);
         // update UE stats
-        std::map<uint16_t, fdbetsFlowPerf_t>::iterator it;
-        it = m_flowStatsDl.find((*itMap).first);
+        auto it = m_flowStatsDl.find((*itMap).first);
         if (it != m_flowStatsDl.end())
         {
             (*it).second.lastTtiBytesTrasmitted = bytesTxed;
@@ -1211,7 +1172,7 @@
 
     // update UEs stats
     NS_LOG_INFO(this << " Update UEs statistics");
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
         // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
@@ -1248,9 +1209,8 @@
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1265,17 +1225,15 @@
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
         else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
         {
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_a30CqiRxed.find(rnti);
+            auto it = m_a30CqiRxed.find(rnti);
             if (it == m_a30CqiRxed.end())
             {
                 // create the new entry
@@ -1288,8 +1246,7 @@
             {
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_a30CqiTimers.find(rnti);
+                auto itTimers = m_a30CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1303,7 +1260,7 @@
 double
 FdBetFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find(rnti);
+    auto itCqi = m_ueCqi.find(rnti);
     if (itCqi == m_ueCqi.end())
     {
         // no cqi info about this UE
@@ -1370,8 +1327,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1379,16 +1335,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
                                  << " i " << i << " size " << params.m_ulInfoList.size());
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                     continue;
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1446,7 +1400,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
         {
@@ -1476,7 +1430,6 @@
     }
     int rbAllocated = 0;
 
-    std::map<uint16_t, fdbetsFlowPerf_t>::iterator itStats;
     if (m_nextRntiUl != 0)
     {
         for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
@@ -1498,7 +1451,7 @@
     }
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -1583,7 +1536,7 @@
             return;
         }
 
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -1654,15 +1607,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -1670,8 +1621,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -1687,7 +1637,7 @@
                          << (uint16_t)harqId);
 
         // update TTI  UE stats
-        itStats = m_flowStatsUl.find((*it).first);
+        auto itStats = m_flowStatsUl.find((*it).first);
         if (itStats != m_flowStatsUl.end())
         {
             (*itStats).second.lastTtiBytesTrasmitted = uldci.m_tbSize;
@@ -1713,7 +1663,7 @@
 
     // Update global UE stats
     // update UEs stats
-    for (itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
+    for (auto itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
     {
         (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
         // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
@@ -1750,8 +1700,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -1772,7 +1720,7 @@
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
             NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -1818,11 +1766,9 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
         NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
                           << " subframe no. " << (0xF & params.m_sfnSf));
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             return;
@@ -1831,7 +1777,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -1861,8 +1807,7 @@
                 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
                                   << sinr);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1883,8 +1828,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -1911,8 +1855,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -1932,7 +1875,7 @@
 FdBetFfMacScheduler::RefreshDlCqiMaps()
 {
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -1940,12 +1883,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -1957,7 +1900,7 @@
     }
 
     // refresh DL CQI A30 Map
-    std::map<uint16_t, uint32_t>::iterator itA30 = m_a30CqiTimers.begin();
+    auto itA30 = m_a30CqiTimers.begin();
     while (itA30 != m_a30CqiTimers.end())
     {
         NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
@@ -1965,12 +1908,12 @@
         if ((*itA30).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find((*itA30).first);
+            auto itMap = m_a30CqiRxed.find((*itA30).first);
             NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
                           " Does not find CQI report for user " << (*itA30).first);
             NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
             m_a30CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itA30;
+            auto temp = itA30;
             itA30++;
             m_a30CqiTimers.erase(temp);
         }
@@ -1986,7 +1929,7 @@
 FdBetFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -1994,13 +1937,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -2015,9 +1958,8 @@
 void
 FdBetFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     LteFlowId_t flow(rnti, lcid);
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
     if (it != m_rlcBufferReq.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
@@ -2072,7 +2014,7 @@
 FdBetFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/fdmt-ff-mac-scheduler.cc ns-3.40/src/lte/model/fdmt-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/fdmt-ff-mac-scheduler.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/fdmt-ff-mac-scheduler.cc	2023-09-27 13:30:37.814839600 -0700
@@ -158,7 +158,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, double>(params.m_rnti, params.m_transmissionMode));
@@ -204,10 +204,9 @@
 {
     NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
 
-    std::set<uint16_t>::iterator it;
     for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
     {
-        it = m_flowStatsDl.find(params.m_rnti);
+        auto it = m_flowStatsDl.find(params.m_rnti);
 
         if (it == m_flowStatsDl.end())
         {
@@ -224,15 +223,13 @@
     NS_LOG_FUNCTION(this);
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).first.m_rnti == params.m_rnti) &&
                 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
             {
-                temp = it;
+                auto temp = it;
                 it++;
                 m_rlcBufferReq.erase(temp);
             }
@@ -262,14 +259,12 @@
     m_flowStatsDl.erase(params.m_rnti);
     m_flowStatsUl.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).first.m_rnti == params.m_rnti)
         {
-            temp = it;
+            auto temp = it;
             it++;
             m_rlcBufferReq.erase(temp);
         }
@@ -291,11 +286,9 @@
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
 
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-
     LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
 
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
 
     if (it == m_rlcBufferReq.end())
     {
@@ -342,9 +335,8 @@
 unsigned int
 FdMtFfMacScheduler::LcActivePerFlow(uint16_t rnti)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     unsigned int lcActive = 0;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
                                              ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
@@ -365,13 +357,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -395,13 +386,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -430,8 +420,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -441,8 +430,7 @@
                 // reset HARQ process
 
                 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -482,9 +470,9 @@
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
     FfMacSchedSapUser::SchedDlConfigIndParameters ret;
 
-    //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    // update UL HARQ proc id
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -493,8 +481,7 @@
     // RACH Allocation
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -558,15 +545,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -608,7 +593,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -636,8 +621,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -658,16 +642,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -754,8 +736,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -832,8 +813,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -846,15 +826,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -885,12 +864,11 @@
         NS_LOG_INFO(this << " ALLOCATION for RBG " << i << " of " << rbgNum);
         if (!rbgMap.at(i))
         {
-            std::set<uint16_t>::iterator it;
-            std::set<uint16_t>::iterator itMax = m_flowStatsDl.end();
+            auto itMax = m_flowStatsDl.end();
             double rcqiMax = 0.0;
-            for (it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
+            for (auto it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
             {
-                std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it));
+                auto itRnti = rntiAllocated.find((*it));
                 if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*it))))
                 {
                     // UE already allocated for HARQ or without HARQ process available -> drop it
@@ -905,10 +883,8 @@
                     continue;
                 }
 
-                std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-                itCqi = m_a30CqiRxed.find((*it));
-                std::map<uint16_t, uint8_t>::iterator itTxMode;
-                itTxMode = m_uesTxMode.find((*it));
+                auto itCqi = m_a30CqiRxed.find((*it));
+                auto itTxMode = m_uesTxMode.find((*it));
                 if (itTxMode == m_uesTxMode.end())
                 {
                     NS_FATAL_ERROR("No Transmission Mode info on user " << (*it));
@@ -917,10 +893,7 @@
                 std::vector<uint8_t> sbCqi;
                 if (itCqi == m_a30CqiRxed.end())
                 {
-                    for (uint8_t k = 0; k < nLayer; k++)
-                    {
-                        sbCqi.push_back(1); // start with lowest value
-                    }
+                    sbCqi = std::vector<uint8_t>(nLayer, 1); // start with lowest value
                 }
                 else
                 {
@@ -978,8 +951,7 @@
             else
             {
                 rbgMap.at(i) = true;
-                std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-                itMap = allocationMap.find((*itMax));
+                auto itMap = allocationMap.find((*itMax));
                 if (itMap == allocationMap.end())
                 {
                     // insert new element
@@ -999,7 +971,7 @@
 
     // generate the transmission opportunities by grouping the RBGs of the same RNTI and
     // creating the correspondent DCIs
-    std::map<uint16_t, std::vector<uint16_t>>::iterator itMap = allocationMap.begin();
+    auto itMap = allocationMap.begin();
     while (itMap != allocationMap.end())
     {
         // create new BuildDataListElement_s for this LC
@@ -1018,10 +990,8 @@
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
         uint16_t RgbPerRnti = (*itMap).second.size();
-        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-        itCqi = m_a30CqiRxed.find((*itMap).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itMap).first);
+        auto itCqi = m_a30CqiRxed.find((*itMap).first);
+        auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
@@ -1104,9 +1074,7 @@
         newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
 
         // create the rlc PDUs -> equally divide resources among actives LCs
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itBufReq;
-        for (itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
+        for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
         {
             if (((*itBufReq).first.m_rnti == (*itMap).first) &&
                 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
@@ -1128,8 +1096,7 @@
                     if (m_harqOn)
                     {
                         // store RLC PDU list for HARQ
-                        std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                            m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
+                        auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
                         if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                         {
                             NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1158,8 +1125,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1167,8 +1133,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1208,9 +1173,8 @@
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1225,17 +1189,15 @@
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
         else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
         {
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_a30CqiRxed.find(rnti);
+            auto it = m_a30CqiRxed.find(rnti);
             if (it == m_a30CqiRxed.end())
             {
                 // create the new entry
@@ -1248,8 +1210,7 @@
             {
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_a30CqiTimers.find(rnti);
+                auto itTimers = m_a30CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1263,7 +1224,7 @@
 double
 FdMtFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find(rnti);
+    auto itCqi = m_ueCqi.find(rnti);
     if (itCqi == m_ueCqi.end())
     {
         // no cqi info about this UE
@@ -1330,8 +1291,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1339,16 +1299,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
                                  << " i " << i << " size " << params.m_ulInfoList.size());
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                     continue;
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1406,7 +1364,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
         {
@@ -1457,7 +1415,7 @@
     }
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -1542,7 +1500,7 @@
             return;
         }
 
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -1613,15 +1571,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -1629,8 +1585,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -1684,8 +1639,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -1706,7 +1659,7 @@
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
             NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -1752,11 +1705,9 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
         NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
                           << " subframe no. " << (0xF & params.m_sfnSf));
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             return;
@@ -1765,7 +1716,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -1795,8 +1746,7 @@
                 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
                                   << sinr);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1817,8 +1767,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -1845,8 +1794,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -1866,7 +1814,7 @@
 FdMtFfMacScheduler::RefreshDlCqiMaps()
 {
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -1874,12 +1822,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -1891,7 +1839,7 @@
     }
 
     // refresh DL CQI A30 Map
-    std::map<uint16_t, uint32_t>::iterator itA30 = m_a30CqiTimers.begin();
+    auto itA30 = m_a30CqiTimers.begin();
     while (itA30 != m_a30CqiTimers.end())
     {
         NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
@@ -1899,12 +1847,12 @@
         if ((*itA30).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find((*itA30).first);
+            auto itMap = m_a30CqiRxed.find((*itA30).first);
             NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
                           " Does not find CQI report for user " << (*itA30).first);
             NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
             m_a30CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itA30;
+            auto temp = itA30;
             itA30++;
             m_a30CqiTimers.erase(temp);
         }
@@ -1920,7 +1868,7 @@
 FdMtFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -1928,13 +1876,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -1949,9 +1897,8 @@
 void
 FdMtFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     LteFlowId_t flow(rnti, lcid);
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
     if (it != m_rlcBufferReq.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
@@ -2006,7 +1953,7 @@
 FdMtFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/fdtbfq-ff-mac-scheduler.cc ns-3.40/src/lte/model/fdtbfq-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/fdtbfq-ff-mac-scheduler.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/fdtbfq-ff-mac-scheduler.cc	2023-09-27 13:30:37.814839600 -0700
@@ -184,7 +184,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, double>(params.m_rnti, params.m_transmissionMode));
@@ -230,10 +230,9 @@
 {
     NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
 
-    std::map<uint16_t, fdtbfqsFlowPerf_t>::iterator it;
     for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
     {
-        it = m_flowStatsDl.find(params.m_rnti);
+        auto it = m_flowStatsDl.find(params.m_rnti);
 
         if (it == m_flowStatsDl.end())
         {
@@ -289,15 +288,13 @@
     NS_LOG_FUNCTION(this);
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).first.m_rnti == params.m_rnti) &&
                 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
             {
-                temp = it;
+                auto temp = it;
                 it++;
                 m_rlcBufferReq.erase(temp);
             }
@@ -327,14 +324,12 @@
     m_flowStatsDl.erase(params.m_rnti);
     m_flowStatsUl.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).first.m_rnti == params.m_rnti)
         {
-            temp = it;
+            auto temp = it;
             it++;
             m_rlcBufferReq.erase(temp);
         }
@@ -356,11 +351,9 @@
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
 
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-
     LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
 
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
 
     if (it == m_rlcBufferReq.end())
     {
@@ -407,9 +400,8 @@
 unsigned int
 FdTbfqFfMacScheduler::LcActivePerFlow(uint16_t rnti)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     unsigned int lcActive = 0;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
                                              ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
@@ -430,13 +422,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -460,13 +451,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -495,8 +485,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -506,8 +495,7 @@
                 // reset HARQ process
 
                 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -547,7 +535,7 @@
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
 
     rbgMap = m_ffrSapProvider->GetAvailableDlRbg();
-    for (std::vector<bool>::iterator it = rbgMap.begin(); it != rbgMap.end(); it++)
+    for (auto it = rbgMap.begin(); it != rbgMap.end(); it++)
     {
         if (*it)
         {
@@ -558,8 +546,8 @@
     FfMacSchedSapUser::SchedDlConfigIndParameters ret;
 
     //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -575,7 +563,7 @@
     uint16_t tmpFfrRbStartOffset = 0;
     uint16_t index = 0;
 
-    for (std::vector<bool>::iterator it = ulRbMap.begin(); it != ulRbMap.end(); it++)
+    for (auto it = ulRbMap.begin(); it != ulRbMap.end(); it++)
     {
         if (*it)
         {
@@ -606,8 +594,7 @@
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
     rbStart = ffrRbStartOffset;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -671,15 +658,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -721,7 +706,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -749,8 +734,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -771,16 +755,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -867,8 +849,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -945,8 +926,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -959,15 +939,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -994,8 +973,7 @@
     }
 
     // update token pool, counter and bank size
-    std::map<uint16_t, fdtbfqsFlowPerf_t>::iterator itStats;
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         if ((*itStats).second.tokenGenerationRate / 1000 + (*itStats).second.tokenPoolSize >
             (*itStats).second.maxTokenPoolSize)
@@ -1021,12 +999,12 @@
     {
         // select UE with largest metric
         std::map<uint16_t, fdtbfqsFlowPerf_t>::iterator it;
-        std::map<uint16_t, fdtbfqsFlowPerf_t>::iterator itMax = m_flowStatsDl.end();
+        auto itMax = m_flowStatsDl.end();
         double metricMax = 0.0;
         bool firstRnti = true;
         for (it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
         {
-            std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+            auto itRnti = rntiAllocated.find((*it).first);
             if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*it).first)))
             {
                 // UE already allocated for HARQ or without HARQ process available -> drop it
@@ -1041,10 +1019,8 @@
                 continue;
             }
             // check first the channel conditions for this UE, if CQI!=0
-            std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-            itCqi = m_a30CqiRxed.find((*it).first);
-            std::map<uint16_t, uint8_t>::iterator itTxMode;
-            itTxMode = m_uesTxMode.find((*it).first);
+            auto itCqi = m_a30CqiRxed.find((*it).first);
+            auto itTxMode = m_uesTxMode.find((*it).first);
             if (itTxMode == m_uesTxMode.end())
             {
                 NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
@@ -1078,8 +1054,7 @@
                 continue;
             }
 
-            std::set<uint16_t>::iterator rnti;
-            rnti = allocatedRnti.find((*it).first);
+            auto rnti = allocatedRnti.find((*it).first);
             if (rnti != allocatedRnti.end()) //  already allocated RBGs to this UE
             {
                 continue;
@@ -1139,9 +1114,8 @@
             // calculate rlc buffer size
             uint32_t rlcBufSize = 0;
             uint8_t lcid = 0;
-            std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-                itRlcBuf;
-            for (itRlcBuf = m_rlcBufferReq.begin(); itRlcBuf != m_rlcBufferReq.end(); itRlcBuf++)
+            for (auto itRlcBuf = m_rlcBufferReq.begin(); itRlcBuf != m_rlcBufferReq.end();
+                 itRlcBuf++)
             {
                 if ((*itRlcBuf).first.m_rnti == (*itMax).first)
                 {
@@ -1149,7 +1123,7 @@
                 }
             }
             LteFlowId_t flow((*itMax).first, lcid);
-            itRlcBuf = m_rlcBufferReq.find(flow);
+            auto itRlcBuf = m_rlcBufferReq.find(flow);
             if (itRlcBuf != m_rlcBufferReq.end())
             {
                 rlcBufSize = (*itRlcBuf).second.m_rlcTransmissionQueueSize +
@@ -1172,10 +1146,8 @@
         {
             totalRbg++;
 
-            std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-            itCqi = m_a30CqiRxed.find((*itMax).first);
-            std::map<uint16_t, uint8_t>::iterator itTxMode;
-            itTxMode = m_uesTxMode.find((*itMax).first);
+            auto itCqi = m_a30CqiRxed.find((*itMax).first);
+            auto itTxMode = m_uesTxMode.find((*itMax).first);
             if (itTxMode == m_uesTxMode.end())
             {
                 NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
@@ -1187,8 +1159,7 @@
             rbgIndex = rbgNum;
             for (int k = 0; k < rbgNum; k++)
             {
-                std::set<uint8_t>::iterator rbg;
-                rbg = allocatedRbg.find(k);
+                auto rbg = allocatedRbg.find(k);
                 if (rbg != allocatedRbg.end()) // RBGs are already allocated to this UE
                 {
                     continue;
@@ -1207,10 +1178,7 @@
                 std::vector<uint8_t> sbCqi;
                 if (itCqi == m_a30CqiRxed.end())
                 {
-                    for (uint8_t k = 0; k < nLayer; k++)
-                    {
-                        sbCqi.push_back(1); // start with lowest value
-                    }
+                    sbCqi = std::vector<uint8_t>(nLayer, 1); // start with lowest value
                 }
                 else
                 {
@@ -1268,8 +1236,7 @@
             }
 
             // assign this RBG to UE
-            std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-            itMap = allocationMap.find((*itMax).first);
+            auto itMap = allocationMap.find((*itMax).first);
             uint16_t RbgPerRnti;
             if (itMap == allocationMap.end())
             {
@@ -1355,8 +1322,7 @@
         {
             NS_LOG_DEBUG("budget: " << budget << " bytesTxed: " << bytesTxed << " at "
                                     << Simulator::Now().As(Time::MS));
-            std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-            itMap = allocationMap.find((*itMax).first);
+            auto itMap = allocationMap.find((*itMax).first);
             (*itMap).second.pop_back();
             allocatedRbg.erase(rbgIndex);
             bytesTxed = bytesTxedTmp; // recovery bytesTxed
@@ -1397,7 +1363,7 @@
 
     // generate the transmission opportunities by grouping the RBGs of the same RNTI and
     // creating the correspondent DCIs
-    std::map<uint16_t, std::vector<uint16_t>>::iterator itMap = allocationMap.begin();
+    auto itMap = allocationMap.begin();
     while (itMap != allocationMap.end())
     {
         NS_LOG_DEBUG("Preparing DCI for RNTI " << (*itMap).first);
@@ -1417,10 +1383,8 @@
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
         uint16_t RgbPerRnti = (*itMap).second.size();
-        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-        itCqi = m_a30CqiRxed.find((*itMap).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itMap).first);
+        auto itCqi = m_a30CqiRxed.find((*itMap).first);
+        auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
@@ -1503,9 +1467,7 @@
         newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
 
         // create the rlc PDUs -> equally divide resources among actives LCs
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itBufReq;
-        for (itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
+        for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
         {
             if (((*itBufReq).first.m_rnti == (*itMap).first) &&
                 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
@@ -1527,8 +1489,7 @@
                     if (m_harqOn)
                     {
                         // store RLC PDU list for HARQ
-                        std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                            m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
+                        auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
                         if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                         {
                             NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1557,8 +1518,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1566,8 +1526,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1608,9 +1567,8 @@
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1625,17 +1583,15 @@
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
         else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
         {
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_a30CqiRxed.find(rnti);
+            auto it = m_a30CqiRxed.find(rnti);
             if (it == m_a30CqiRxed.end())
             {
                 // create the new entry
@@ -1648,8 +1604,7 @@
             {
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_a30CqiTimers.find(rnti);
+                auto itTimers = m_a30CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1663,7 +1618,7 @@
 double
 FdTbfqFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find(rnti);
+    auto itCqi = m_ueCqi.find(rnti);
     if (itCqi == m_ueCqi.end())
     {
         // no cqi info about this UE
@@ -1716,7 +1671,7 @@
 
     rbMap = m_ffrSapProvider->GetAvailableUlRbg();
 
-    for (std::vector<bool>::iterator it = rbMap.begin(); it != rbMap.end(); it++)
+    for (auto it = rbMap.begin(); it != rbMap.end(); it++)
     {
         if (*it)
         {
@@ -1746,8 +1701,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1755,16 +1709,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
                                  << " i " << i << " size " << params.m_ulInfoList.size());
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                     continue;
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1823,7 +1775,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
         {
@@ -1856,7 +1808,6 @@
     }
     int rbAllocated = 0;
 
-    std::map<uint16_t, fdtbfqsFlowPerf_t>::iterator itStats;
     if (m_nextRntiUl != 0)
     {
         for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
@@ -1878,7 +1829,7 @@
     }
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -1971,7 +1922,7 @@
             break;
         }
 
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -2042,15 +1993,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -2058,8 +2007,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -2113,8 +2061,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -2135,7 +2081,7 @@
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
             NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -2181,11 +2127,9 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
         NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
                           << " subframe no. " << (0xF & params.m_sfnSf));
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             return;
@@ -2194,7 +2138,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -2224,8 +2168,7 @@
                 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
                                   << sinr);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -2246,8 +2189,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -2274,8 +2216,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -2295,7 +2236,7 @@
 FdTbfqFfMacScheduler::RefreshDlCqiMaps()
 {
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -2303,12 +2244,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -2320,7 +2261,7 @@
     }
 
     // refresh DL CQI A30 Map
-    std::map<uint16_t, uint32_t>::iterator itA30 = m_a30CqiTimers.begin();
+    auto itA30 = m_a30CqiTimers.begin();
     while (itA30 != m_a30CqiTimers.end())
     {
         NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
@@ -2328,12 +2269,12 @@
         if ((*itA30).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find((*itA30).first);
+            auto itMap = m_a30CqiRxed.find((*itA30).first);
             NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
                           " Does not find CQI report for user " << (*itA30).first);
             NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
             m_a30CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itA30;
+            auto temp = itA30;
             itA30++;
             m_a30CqiTimers.erase(temp);
         }
@@ -2349,7 +2290,7 @@
 FdTbfqFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -2357,13 +2298,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -2378,9 +2319,8 @@
 void
 FdTbfqFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     LteFlowId_t flow(rnti, lcid);
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
     if (it != m_rlcBufferReq.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
@@ -2435,7 +2375,7 @@
 FdTbfqFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-amc.cc ns-3.40/src/lte/model/lte-amc.cc
--- ns-3.39/src/lte/model/lte-amc.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/lte-amc.cc	2023-09-27 13:30:37.818839600 -0700
@@ -554,11 +554,10 @@
     NS_LOG_FUNCTION(this);
 
     std::vector<int> cqi;
-    Values::const_iterator it;
 
     if (m_amcModel == PiroEW2010)
     {
-        for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
+        for (auto it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
         {
             double sinr_ = (*it);
             if (sinr_ == 0.0)
@@ -594,7 +593,7 @@
         NS_ASSERT_MSG(rbgSize > 0, " LteAmc-Vienna: RBG size must be greater than 0");
         std::vector<int> rbgMap;
         int rbId = 0;
-        for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
+        for (auto it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
         {
             rbgMap.push_back(rbId++);
             if ((rbId % rbgSize == 0) || ((it + 1) == sinr.ConstValuesEnd()))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-anr.cc ns-3.40/src/lte/model/lte-anr.cc
--- ns-3.39/src/lte/model/lte-anr.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/lte-anr.cc	2023-09-27 13:30:37.818839600 -0700
@@ -97,7 +97,7 @@
 {
     NS_LOG_FUNCTION(this << m_servingCellId << cellId);
 
-    NeighbourRelationTable_t::iterator it = m_neighbourRelationTable.find(cellId);
+    auto it = m_neighbourRelationTable.find(cellId);
     if (it != m_neighbourRelationTable.end())
     {
         NS_FATAL_ERROR("Cell ID " << cellId << " cannot be found in NRT");
@@ -157,8 +157,7 @@
     {
         if (measResults.haveMeasResultNeighCells && !(measResults.measResultListEutra.empty()))
         {
-            for (std::list<LteRrcSap::MeasResultEutra>::iterator it =
-                     measResults.measResultListEutra.begin();
+            for (auto it = measResults.measResultListEutra.begin();
                  it != measResults.measResultListEutra.end();
                  ++it)
             {
@@ -167,8 +166,7 @@
                               "RSRQ measure missing for cellId " << it->physCellId);
 
                 // Update Neighbour Relation Table
-                NeighbourRelationTable_t::iterator itNrt =
-                    m_neighbourRelationTable.find(it->physCellId);
+                auto itNrt = m_neighbourRelationTable.find(it->physCellId);
                 if (itNrt != m_neighbourRelationTable.end())
                 {
                     // Update neighbour relation entry
@@ -243,7 +241,7 @@
 const LteAnr::NeighbourRelation_t*
 LteAnr::Find(uint16_t cellId) const
 {
-    NeighbourRelationTable_t::const_iterator it = m_neighbourRelationTable.find(cellId);
+    auto it = m_neighbourRelationTable.find(cellId);
     if (it == m_neighbourRelationTable.end())
     {
         NS_FATAL_ERROR("Cell ID " << cellId << " cannot be found in NRT");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-asn1-header.cc ns-3.40/src/lte/model/lte-asn1-header.cc
--- ns-3.39/src/lte/model/lte-asn1-header.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/lte-asn1-header.cc	2023-09-27 13:30:37.818839600 -0700
@@ -23,7 +23,6 @@
 
 #include <cmath>
 #include <sstream>
-#include <stdio.h>
 
 namespace ns3
 {
@@ -165,7 +164,7 @@
     // Clause 16.11 ITU-T X.691
     else
     {
-        printf("FRAGMENTATION NEEDED!\n");
+        NS_LOG_DEBUG("Fragmentation needed!");
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-chunk-processor.cc ns-3.40/src/lte/model/lte-chunk-processor.cc
--- ns-3.39/src/lte/model/lte-chunk-processor.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/lte-chunk-processor.cc	2023-09-27 13:30:37.818839600 -0700
@@ -72,8 +72,8 @@
     NS_LOG_FUNCTION(this);
     if (m_totDuration.GetSeconds() > 0)
     {
-        std::vector<LteChunkProcessorCallback>::iterator it;
-        for (it = m_lteChunkProcessorCallbacks.begin(); it != m_lteChunkProcessorCallbacks.end();
+        for (auto it = m_lteChunkProcessorCallbacks.begin();
+             it != m_lteChunkProcessorCallbacks.end();
              it++)
         {
             (*it)((*m_sumValues) / m_totDuration.GetSeconds());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-common.cc ns-3.40/src/lte/model/lte-common.cc
--- ns-3.39/src/lte/model/lte-common.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/lte-common.cc	2023-09-27 13:30:37.818839600 -0700
@@ -143,7 +143,7 @@
     {
         val = -4096;
     }
-    int16_t valFp = (int16_t)(val * 8);
+    auto valFp = (int16_t)(val * 8);
     return (valFp);
 }
 
@@ -361,7 +361,7 @@
                                     << " for Q-QualMin IE value");
     }
 
-    double actual = static_cast<double>(qQualMinIeValue);
+    auto actual = static_cast<double>(qQualMinIeValue);
     NS_ASSERT(actual >= -34.0);
     NS_ASSERT(actual <= -3.0);
     return actual;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-enb-component-carrier-manager.cc ns-3.40/src/lte/model/lte-enb-component-carrier-manager.cc
--- ns-3.39/src/lte/model/lte-enb-component-carrier-manager.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/lte-enb-component-carrier-manager.cc	2023-09-27 13:30:37.818839600 -0700
@@ -84,8 +84,7 @@
 {
     NS_LOG_FUNCTION(this);
     bool res = false;
-    std::map<uint8_t, LteMacSapProvider*>::iterator it =
-        m_macSapProvidersMap.find(componentCarrierId);
+    auto it = m_macSapProvidersMap.find(componentCarrierId);
     if ((uint16_t)componentCarrierId > m_noOfComponentCarriers)
     {
         NS_FATAL_ERROR("Inconsistent componentCarrierId or you didn't call "
@@ -110,8 +109,7 @@
 {
     NS_LOG_FUNCTION(this);
     bool res = false;
-    std::map<uint8_t, LteCcmMacSapProvider*>::iterator it =
-        m_ccmMacSapProviderMap.find(componentCarrierId);
+    auto it = m_ccmMacSapProviderMap.find(componentCarrierId);
 
     if (it == m_ccmMacSapProviderMap.end())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-enb-mac.cc ns-3.40/src/lte/model/lte-enb-mac.cc
--- ns-3.39/src/lte/model/lte-enb-mac.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/lte-enb-mac.cc	2023-09-27 13:30:37.818839600 -0700
@@ -499,8 +499,7 @@
         // process received RACH preambles and notify the scheduler
         FfMacSchedSapProvider::SchedDlRachInfoReqParameters rachInfoReqParams;
         NS_ASSERT(subframeNo > 0 && subframeNo <= 10); // subframe in 1..10
-        for (std::map<uint8_t, uint32_t>::const_iterator it = m_receivedRachPreambleCount.begin();
-             it != m_receivedRachPreambleCount.end();
+        for (auto it = m_receivedRachPreambleCount.begin(); it != m_receivedRachPreambleCount.end();
              ++it)
         {
             NS_LOG_INFO(this << " preambleId " << (uint32_t)it->first << ": " << it->second
@@ -515,8 +514,7 @@
             else
             {
                 uint16_t rnti;
-                std::map<uint8_t, NcRaPreambleInfo>::iterator jt =
-                    m_allocatedNcRaPreambleMap.find(it->first);
+                auto jt = m_allocatedNcRaPreambleMap.find(it->first);
                 if (jt != m_allocatedNcRaPreambleMap.end())
                 {
                     rnti = jt->second.rnti;
@@ -716,10 +714,9 @@
 
     // store info of the packet received
 
-    //   std::map <uint16_t,UlInfoListElement_s>::iterator it;
     //   u_int rnti = tag.GetRnti ();
-    //  u_int lcid = tag.GetLcid ();
-    //   it = m_ulInfoListElements.find (tag.GetRnti ());
+    //   u_int lcid = tag.GetLcid ();
+    //   auto it = m_ulInfoListElements.find (tag.GetRnti ());
     //   if (it == m_ulInfoListElements.end ())
     //     {
     //       // new RNTI
@@ -749,10 +746,9 @@
     // forward the packet to the correspondent RLC
     uint16_t rnti = tag.GetRnti();
     uint8_t lcid = tag.GetLcid();
-    std::map<uint16_t, std::map<uint8_t, LteMacSapUser*>>::iterator rntiIt =
-        m_rlcAttached.find(rnti);
+    auto rntiIt = m_rlcAttached.find(rnti);
     NS_ASSERT_MSG(rntiIt != m_rlcAttached.end(), "could not find RNTI" << rnti);
-    std::map<uint8_t, LteMacSapUser*>::iterator lcidIt = rntiIt->second.find(lcid);
+    auto lcidIt = rntiIt->second.find(lcid);
     // NS_ASSERT_MSG (lcidIt != rntiIt->second.end (), "could not find LCID" << lcid);
 
     LteMacSapUser::ReceivePduParameters rxPduParams;
@@ -789,7 +785,7 @@
 {
     NS_LOG_FUNCTION(this << " rnti=" << rnti);
     std::map<uint8_t, LteMacSapUser*> empty;
-    std::pair<std::map<uint16_t, std::map<uint8_t, LteMacSapUser*>>::iterator, bool> ret =
+    auto ret =
         m_rlcAttached.insert(std::pair<uint16_t, std::map<uint8_t, LteMacSapUser*>>(rnti, empty));
     NS_ASSERT_MSG(ret.second, "element already present, RNTI already existed");
 
@@ -833,13 +829,12 @@
 
     NS_LOG_DEBUG("start checking for unprocessed preamble for rnti: " << rnti);
     // remove unprocessed preamble received for RACH during handover
-    std::map<uint8_t, NcRaPreambleInfo>::iterator jt = m_allocatedNcRaPreambleMap.begin();
+    auto jt = m_allocatedNcRaPreambleMap.begin();
     while (jt != m_allocatedNcRaPreambleMap.end())
     {
         if (jt->second.rnti == rnti)
         {
-            std::map<uint8_t, uint32_t>::const_iterator it =
-                m_receivedRachPreambleCount.find(jt->first);
+            auto it = m_receivedRachPreambleCount.find(jt->first);
             if (it != m_receivedRachPreambleCount.end())
             {
                 m_receivedRachPreambleCount.erase(it->first);
@@ -852,7 +847,7 @@
         }
     }
 
-    std::vector<MacCeListElement_s>::iterator itCeRxd = m_ulCeReceived.begin();
+    auto itCeRxd = m_ulCeReceived.begin();
     while (itCeRxd != m_ulCeReceived.end())
     {
         if (itCeRxd->m_rnti == rnti)
@@ -871,14 +866,11 @@
 {
     NS_LOG_FUNCTION(this << lcinfo.rnti << (uint16_t)lcinfo.lcId);
 
-    std::map<LteFlowId_t, LteMacSapUser*>::iterator it;
-
     LteFlowId_t flow(lcinfo.rnti, lcinfo.lcId);
 
-    std::map<uint16_t, std::map<uint8_t, LteMacSapUser*>>::iterator rntiIt =
-        m_rlcAttached.find(lcinfo.rnti);
+    auto rntiIt = m_rlcAttached.find(lcinfo.rnti);
     NS_ASSERT_MSG(rntiIt != m_rlcAttached.end(), "RNTI not found");
-    std::map<uint8_t, LteMacSapUser*>::iterator lcidIt = rntiIt->second.find(lcinfo.lcId);
+    auto lcidIt = rntiIt->second.find(lcinfo.lcId);
     if (lcidIt == rntiIt->second.end())
     {
         rntiIt->second.insert(std::pair<uint8_t, LteMacSapUser*>(lcinfo.lcId, msu));
@@ -928,8 +920,7 @@
     NS_LOG_FUNCTION(this);
 
     // Find user based on rnti and then erase lcid stored against the same
-    std::map<uint16_t, std::map<uint8_t, LteMacSapUser*>>::iterator rntiIt =
-        m_rlcAttached.find(rnti);
+    auto rntiIt = m_rlcAttached.find(rnti);
     rntiIt->second.erase(lcid);
 
     FfMacCschedSapProvider::CschedLcReleaseReqParameters params;
@@ -969,8 +960,7 @@
     uint8_t preambleId;
     for (preambleId = m_numberOfRaPreambles; preambleId < 64; ++preambleId)
     {
-        std::map<uint8_t, NcRaPreambleInfo>::iterator it =
-            m_allocatedNcRaPreambleMap.find(preambleId);
+        auto it = m_allocatedNcRaPreambleMap.find(preambleId);
         /**
          * Allocate preamble only if its free. The non-contention preamble
          * assigned to UE during handover or PDCCH order is valid only until the
@@ -1036,8 +1026,7 @@
     params.pdu->AddPacketTag(tag);
     params.componentCarrierId = m_componentCarrierId;
     // Store pkt in HARQ buffer
-    std::map<uint16_t, DlHarqProcessesBuffer_t>::iterator it =
-        m_miDlHarqProcessesPackets.find(params.rnti);
+    auto it = m_miDlHarqProcessesPackets.find(params.rnti);
     NS_ASSERT(it != m_miDlHarqProcessesPackets.end());
     NS_LOG_DEBUG(this << " LAYER " << (uint16_t)tag.GetLayer() << " HARQ ID "
                       << (uint16_t)params.harqProcessId);
@@ -1072,7 +1061,6 @@
     NS_LOG_FUNCTION(this);
     // Create DL PHY PDU
     Ptr<PacketBurst> pb = CreateObject<PacketBurst>();
-    std::map<LteFlowId_t, LteMacSapUser*>::iterator it;
     LteMacSapUser::TxOpportunityParameters txOpParams;
 
     for (std::size_t i = 0; i < ind.m_buildDataList.size(); i++)
@@ -1082,8 +1070,7 @@
             if (ind.m_buildDataList.at(i).m_dci.m_ndi.at(layer) == 1)
             {
                 // new data -> force emptying correspondent harq pkt buffer
-                std::map<uint16_t, DlHarqProcessesBuffer_t>::iterator it =
-                    m_miDlHarqProcessesPackets.find(ind.m_buildDataList.at(i).m_rnti);
+                auto it = m_miDlHarqProcessesPackets.find(ind.m_buildDataList.at(i).m_rnti);
                 NS_ASSERT(it != m_miDlHarqProcessesPackets.end());
                 for (std::size_t lcId = 0; lcId < (*it).second.size(); lcId++)
                 {
@@ -1102,10 +1089,9 @@
                     uint16_t rnti = ind.m_buildDataList.at(i).m_rnti;
                     uint8_t lcid =
                         ind.m_buildDataList.at(i).m_rlcPduList.at(j).at(k).m_logicalChannelIdentity;
-                    std::map<uint16_t, std::map<uint8_t, LteMacSapUser*>>::iterator rntiIt =
-                        m_rlcAttached.find(rnti);
+                    auto rntiIt = m_rlcAttached.find(rnti);
                     NS_ASSERT_MSG(rntiIt != m_rlcAttached.end(), "could not find RNTI" << rnti);
-                    std::map<uint8_t, LteMacSapUser*>::iterator lcidIt = rntiIt->second.find(lcid);
+                    auto lcidIt = rntiIt->second.find(lcid);
                     NS_ASSERT_MSG(lcidIt != rntiIt->second.end(),
                                   "could not find LCID" << (uint32_t)lcid << " carrier id:"
                                                         << (uint16_t)m_componentCarrierId);
@@ -1124,13 +1110,11 @@
                     if (ind.m_buildDataList.at(i).m_dci.m_tbsSize.at(k) > 0)
                     {
                         // HARQ retransmission -> retrieve TB from HARQ buffer
-                        std::map<uint16_t, DlHarqProcessesBuffer_t>::iterator it =
-                            m_miDlHarqProcessesPackets.find(ind.m_buildDataList.at(i).m_rnti);
+                        auto it = m_miDlHarqProcessesPackets.find(ind.m_buildDataList.at(i).m_rnti);
                         NS_ASSERT(it != m_miDlHarqProcessesPackets.end());
                         Ptr<PacketBurst> pb =
                             (*it).second.at(k).at(ind.m_buildDataList.at(i).m_dci.m_harqProcess);
-                        for (std::list<Ptr<Packet>>::const_iterator j = pb->Begin(); j != pb->End();
-                             ++j)
+                        for (auto j = pb->Begin(); j != pb->End(); ++j)
                         {
                             Ptr<Packet> pkt = (*j)->Copy();
                             m_enbPhySapProvider->SendMacPdu(pkt);
@@ -1198,8 +1182,7 @@
     rarMsg->SetRaRnti(raRnti);
     for (unsigned int i = 0; i < ind.m_buildRarList.size(); i++)
     {
-        std::map<uint16_t, uint32_t>::iterator itRapId =
-            m_rapIdRntiMap.find(ind.m_buildRarList.at(i).m_rnti);
+        auto itRapId = m_rapIdRntiMap.find(ind.m_buildRarList.at(i).m_rnti);
         if (itRapId == m_rapIdRntiMap.end())
         {
             NS_FATAL_ERROR("Unable to find rapId of RNTI " << ind.m_buildRarList.at(i).m_rnti);
@@ -1309,8 +1292,7 @@
 {
     NS_LOG_FUNCTION(this);
     // Update HARQ buffer
-    std::map<uint16_t, DlHarqProcessesBuffer_t>::iterator it =
-        m_miDlHarqProcessesPackets.find(params.m_rnti);
+    auto it = m_miDlHarqProcessesPackets.find(params.m_rnti);
     NS_ASSERT(it != m_miDlHarqProcessesPackets.end());
     for (std::size_t layer = 0; layer < params.m_harqStatus.size(); layer++)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-enb-phy.cc ns-3.40/src/lte/model/lte-enb-phy.cc
--- ns-3.39/src/lte/model/lte-enb-phy.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/lte-enb-phy.cc	2023-09-27 13:30:37.818839600 -0700
@@ -378,8 +378,7 @@
 LteEnbPhy::AddUePhy(uint16_t rnti)
 {
     NS_LOG_FUNCTION(this << rnti);
-    std::set<uint16_t>::iterator it;
-    it = m_ueAttached.find(rnti);
+    auto it = m_ueAttached.find(rnti);
     if (it == m_ueAttached.end())
     {
         m_ueAttached.insert(rnti);
@@ -396,8 +395,7 @@
 LteEnbPhy::DeleteUePhy(uint16_t rnti)
 {
     NS_LOG_FUNCTION(this << rnti);
-    std::set<uint16_t>::iterator it;
-    it = m_ueAttached.find(rnti);
+    auto it = m_ueAttached.find(rnti);
     if (it == m_ueAttached.end())
     {
         NS_LOG_ERROR("UE not attached");
@@ -461,7 +459,7 @@
     NS_LOG_FUNCTION(this);
     double rbgTxPower = m_txPower;
 
-    std::map<uint16_t, double>::iterator it = m_paMap.find(rnti);
+    auto it = m_paMap.find(rnti);
     if (it != m_paMap.end())
     {
         rbgTxPower = m_txPower + it->second;
@@ -525,8 +523,7 @@
 LteEnbPhy::ReceiveLteControlMessageList(std::list<Ptr<LteControlMessage>> msgList)
 {
     NS_LOG_FUNCTION(this);
-    std::list<Ptr<LteControlMessage>>::iterator it;
-    for (it = msgList.begin(); it != msgList.end(); it++)
+    for (auto it = msgList.begin(); it != msgList.end(); it++)
     {
         switch ((*it)->GetMessageType())
         {
@@ -626,12 +623,10 @@
 
     // update info on TB to be received
     std::list<UlDciLteControlMessage> uldcilist = DequeueUlDci();
-    std::list<UlDciLteControlMessage>::iterator dciIt = uldcilist.begin();
     NS_LOG_DEBUG(this << " eNB Expected TBs " << uldcilist.size());
-    for (dciIt = uldcilist.begin(); dciIt != uldcilist.end(); dciIt++)
+    for (auto dciIt = uldcilist.begin(); dciIt != uldcilist.end(); dciIt++)
     {
-        std::set<uint16_t>::iterator it2;
-        it2 = m_ueAttached.find((*dciIt).GetDci().m_rnti);
+        auto it2 = m_ueAttached.find((*dciIt).GetDci().m_rnti);
 
         if (it2 == m_ueAttached.end())
         {
@@ -674,8 +669,7 @@
     m_dlPowerAllocationMap.clear();
     if (!ctrlMsg.empty())
     {
-        std::list<Ptr<LteControlMessage>>::iterator it;
-        it = ctrlMsg.begin();
+        auto it = ctrlMsg.begin();
         while (it != ctrlMsg.end())
         {
             Ptr<LteControlMessage> msg = (*it);
@@ -726,10 +720,7 @@
             else if (msg->GetMessageType() == LteControlMessage::RAR)
             {
                 Ptr<RarLteControlMessage> rarMsg = DynamicCast<RarLteControlMessage>(msg);
-                for (std::list<RarLteControlMessage::Rar>::const_iterator it =
-                         rarMsg->RarListBegin();
-                     it != rarMsg->RarListEnd();
-                     ++it)
+                for (auto it = rarMsg->RarListBegin(); it != rarMsg->RarListEnd(); ++it)
                 {
                     if (it->rarPayload.m_grant.m_ulDelay)
                     {
@@ -870,10 +861,9 @@
 LteEnbPhy::CreatePuschCqiReport(const SpectrumValue& sinr)
 {
     NS_LOG_FUNCTION(this << sinr);
-    Values::const_iterator it;
     FfMacSchedSapProvider::SchedUlCqiInfoReqParameters ulcqi;
     ulcqi.m_ulCqi.m_type = UlCqi_s::PUSCH;
-    for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
+    for (auto it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
     {
         double sinrdb = 10 * std::log10((*it));
         // NS_LOG_DEBUG ("ULCQI RB " << i << " value " << sinrdb);
@@ -936,7 +926,7 @@
     NS_ASSERT_MSG(success, "DeleteUePhy() failed");
 
     // remove also P_A value
-    std::map<uint16_t, double>::iterator it = m_paMap.find(rnti);
+    auto it = m_paMap.find(rnti);
     if (it != m_paMap.end())
     {
         m_paMap.erase(it);
@@ -945,7 +935,7 @@
     // additional data to be removed
     m_uplinkSpectrumPhy->RemoveExpectedTb(rnti);
     // remove srs info to avoid trace errors
-    std::map<uint16_t, uint16_t>::iterator sit = m_srsSampleCounterMap.find(rnti);
+    auto sit = m_srsSampleCounterMap.find(rnti);
     if (sit != m_srsSampleCounterMap.end())
     {
         m_srsSampleCounterMap.erase(rnti);
@@ -955,7 +945,7 @@
 
     for (auto& ctrlMessageList : m_controlMessagesQueue)
     {
-        std::list<Ptr<LteControlMessage>>::iterator ctrlMsgListIt = ctrlMessageList.begin();
+        auto ctrlMsgListIt = ctrlMessageList.begin();
         while (ctrlMsgListIt != ctrlMessageList.end())
         {
             Ptr<LteControlMessage> msg = (*ctrlMsgListIt);
@@ -1000,7 +990,7 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, double>::iterator it = m_paMap.find(rnti);
+    auto it = m_paMap.find(rnti);
 
     if (it == m_paMap.end())
     {
@@ -1016,12 +1006,11 @@
 LteEnbPhy::CreateSrsCqiReport(const SpectrumValue& sinr)
 {
     NS_LOG_FUNCTION(this << sinr);
-    Values::const_iterator it;
     FfMacSchedSapProvider::SchedUlCqiInfoReqParameters ulcqi;
     ulcqi.m_ulCqi.m_type = UlCqi_s::SRS;
     int i = 0;
     double srsSum = 0.0;
-    for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
+    for (auto it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
     {
         double sinrdb = 10 * log10((*it));
         //       NS_LOG_DEBUG ("ULCQI RB " << i << " value " << sinrdb);
@@ -1048,7 +1037,7 @@
 LteEnbPhy::CreateSrsReport(uint16_t rnti, double srs)
 {
     NS_LOG_FUNCTION(this << rnti << srs);
-    std::map<uint16_t, uint16_t>::iterator it = m_srsSampleCounterMap.find(rnti);
+    auto it = m_srsSampleCounterMap.find(rnti);
     if (it == m_srsSampleCounterMap.end())
     {
         // create new entry
@@ -1119,7 +1108,7 @@
 
     NS_LOG_DEBUG(this << " ENB SRS P " << m_srsPeriodicity << " RNTI " << rnti << " offset "
                       << GetSrsSubframeOffset(srcCi) << " CI " << srcCi);
-    std::map<uint16_t, uint16_t>::iterator it = m_srsCounter.find(rnti);
+    auto it = m_srsCounter.find(rnti);
     if (it != m_srsCounter.end())
     {
         (*it).second = GetSrsSubframeOffset(srcCi) + 1;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-enb-rrc.cc ns-3.40/src/lte/model/lte-enb-rrc.cc
--- ns-3.39/src/lte/model/lte-enb-rrc.cc	2023-07-05 14:23:48.009428000 -0700
+++ ns-3.40/src/lte/model/lte-enb-rrc.cc	2023-09-27 13:30:37.818839600 -0700
@@ -320,9 +320,7 @@
 {
     delete m_drbPdcpSapUser;
     // delete eventual X2-U TEIDs
-    for (std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.begin();
-         it != m_drbMap.end();
-         ++it)
+    for (auto it = m_drbMap.begin(); it != m_drbMap.end(); ++it)
     {
         m_rrc->m_x2uTeidInfoMap.erase(it->second->m_gtpTeid);
     }
@@ -425,9 +423,8 @@
         LteEnbRrc::X2uTeidInfo x2uTeidInfo;
         x2uTeidInfo.rnti = m_rnti;
         x2uTeidInfo.drbid = drbid;
-        std::pair<std::map<uint32_t, LteEnbRrc::X2uTeidInfo>::iterator, bool> ret =
-            m_rrc->m_x2uTeidInfoMap.insert(
-                std::pair<uint32_t, LteEnbRrc::X2uTeidInfo>(gtpTeid, x2uTeidInfo));
+        auto ret = m_rrc->m_x2uTeidInfoMap.insert(
+            std::pair<uint32_t, LteEnbRrc::X2uTeidInfo>(gtpTeid, x2uTeidInfo));
         NS_ASSERT_MSG(ret.second == true, "overwriting a pre-existing entry in m_x2uTeidInfoMap");
     }
 
@@ -478,7 +475,7 @@
     // lcinfo.gbrDl = bearer.gbrQosInfo.gbrDl;
     // use a for cycle to send the AddLc to the appropriate Mac Sap
     // if the sap is not initialized the appropriated method has to be called
-    std::vector<LteCcmRrcSapProvider::LcsConfig>::iterator itLcOnCcMapping = lcOnCcMapping.begin();
+    auto itLcOnCcMapping = lcOnCcMapping.begin();
     NS_ASSERT_MSG(itLcOnCcMapping != lcOnCcMapping.end(), "Problem");
     for (itLcOnCcMapping = lcOnCcMapping.begin(); itLcOnCcMapping != lcOnCcMapping.end();
          ++itLcOnCcMapping)
@@ -523,9 +520,7 @@
 UeManager::RecordDataRadioBearersToBeStarted()
 {
     NS_LOG_FUNCTION(this << (uint32_t)m_rnti);
-    for (std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.begin();
-         it != m_drbMap.end();
-         ++it)
+    for (auto it = m_drbMap.begin(); it != m_drbMap.end(); ++it)
     {
         m_drbsToBeStarted.push_back(it->first);
     }
@@ -535,11 +530,9 @@
 UeManager::StartDataRadioBearers()
 {
     NS_LOG_FUNCTION(this << (uint32_t)m_rnti);
-    for (std::list<uint8_t>::iterator drbIdIt = m_drbsToBeStarted.begin();
-         drbIdIt != m_drbsToBeStarted.end();
-         ++drbIdIt)
+    for (auto drbIdIt = m_drbsToBeStarted.begin(); drbIdIt != m_drbsToBeStarted.end(); ++drbIdIt)
     {
-        std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator drbIt = m_drbMap.find(*drbIdIt);
+        auto drbIt = m_drbMap.find(*drbIdIt);
         NS_ASSERT(drbIt != m_drbMap.end());
         drbIt->second->m_rlc->Initialize();
         if (drbIt->second->m_pdcp)
@@ -555,7 +548,7 @@
 {
     NS_LOG_FUNCTION(this << (uint32_t)m_rnti << (uint32_t)drbid);
     uint8_t lcid = Drbid2Lcid(drbid);
-    std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.find(drbid);
+    auto it = m_drbMap.find(drbid);
     NS_ASSERT_MSG(it != m_drbMap.end(),
                   "request to remove radio bearer with unknown drbid " << drbid);
 
@@ -565,7 +558,7 @@
     m_drbMap.erase(it);
     std::vector<uint8_t> ccToRelease =
         m_rrc->m_ccmRrcSapProvider->ReleaseDataRadioBearer(m_rnti, lcid);
-    std::vector<uint8_t>::iterator itCcToRelease = ccToRelease.begin();
+    auto itCcToRelease = ccToRelease.begin();
     NS_ASSERT_MSG(itCcToRelease != ccToRelease.end(),
                   "request to remove radio bearer with unknown drbid (ComponentCarrierManager)");
     for (itCcToRelease = ccToRelease.begin(); itCcToRelease != ccToRelease.end(); ++itCcToRelease)
@@ -856,9 +849,7 @@
     sst.newEnbUeX2apId = params.newEnbUeX2apId;
     sst.sourceCellId = params.sourceCellId;
     sst.targetCellId = params.targetCellId;
-    for (std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator drbIt = m_drbMap.begin();
-         drbIt != m_drbMap.end();
-         ++drbIt)
+    for (auto drbIt = m_drbMap.begin(); drbIt != m_drbMap.end(); ++drbIt)
     {
         // SN status transfer is only for AM RLC
         if (drbIt->second->m_rlc->GetObject<LteRlcAm>())
@@ -939,12 +930,13 @@
     params.lcid = Bid2Lcid(bid);
     uint8_t drbid = Bid2Drbid(bid);
     // Transmit PDCP sdu only if DRB ID found in drbMap
-    std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.find(drbid);
+    auto it = m_drbMap.find(drbid);
     if (it != m_drbMap.end())
     {
         Ptr<LteDataRadioBearerInfo> bearerInfo = GetDataRadioBearerInfo(drbid);
         if (bearerInfo)
         {
+            NS_LOG_INFO("Send packet to PDCP layer");
             LtePdcpSapProvider* pdcpSapProvider = bearerInfo->m_pdcp->GetLtePdcpSapProvider();
             pdcpSapProvider->TransmitPdcpSdu(params);
         }
@@ -967,20 +959,20 @@
     case CONNECTION_REESTABLISHMENT:
     case HANDOVER_PREPARATION:
     case HANDOVER_PATH_SWITCH: {
-        NS_LOG_LOGIC("queueing data on PDCP for transmission over the air");
+        NS_LOG_INFO("queueing data on PDCP for transmission over the air");
         SendPacket(bid, p);
     }
     break;
 
     case HANDOVER_JOINING: {
         // Buffer data until RRC Connection Reconfiguration Complete message is received
-        NS_LOG_LOGIC("buffering data");
+        NS_LOG_INFO("buffering data");
         m_packetBuffer.emplace_back(bid, p);
     }
     break;
 
     case HANDOVER_LEAVING: {
-        NS_LOG_LOGIC("forwarding data to target eNB over X2-U");
+        NS_LOG_INFO("forwarding data to target eNB over X2-U");
         uint8_t drbid = Bid2Drbid(bid);
         EpcX2Sap::UeDataParams params;
         params.sourceCellId = m_rrc->ComponentCarrierToCellId(m_componentCarrierId);
@@ -1002,9 +994,7 @@
 {
     NS_LOG_FUNCTION(this);
     std::vector<EpcX2Sap::ErabToBeSetupItem> ret;
-    for (std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.begin();
-         it != m_drbMap.end();
-         ++it)
+    for (auto it = m_drbMap.begin(); it != m_drbMap.end(); ++it)
     {
         EpcX2Sap::ErabToBeSetupItem etbsi;
         etbsi.erabId = it->second->m_epsBearerIdentity;
@@ -1079,8 +1069,7 @@
 UeManager::RecvSnStatusTransfer(EpcX2SapUser::SnStatusTransferParams params)
 {
     NS_LOG_FUNCTION(this);
-    for (std::vector<EpcX2Sap::ErabsSubjectToStatusTransferItem>::iterator erabIt =
-             params.erabsSubjectToStatusTransferList.begin();
+    for (auto erabIt = params.erabsSubjectToStatusTransferList.begin();
          erabIt != params.erabsSubjectToStatusTransferList.end();
          ++erabIt)
     {
@@ -1088,7 +1077,7 @@
         // status.txSn = erabIt->dlPdcpSn;
         // status.rxSn = erabIt->ulPdcpSn;
         // uint8_t drbId = Bid2Drbid (erabIt->erabId);
-        // std::map <uint8_t, Ptr<LteDataRadioBearerInfo> >::iterator drbIt = m_drbMap.find (drbId);
+        // auto drbIt = m_drbMap.find (drbId);
         // NS_ASSERT_MSG (drbIt != m_drbMap.end (), "could not find DRBID " << (uint32_t) drbId);
         // drbIt->second->m_pdcp->SetStatus (status);
     }
@@ -1293,9 +1282,7 @@
         params.cellId = m_rrc->ComponentCarrierToCellId(m_componentCarrierId);
         params.mmeUeS1Id = m_imsi;
         SwitchToState(HANDOVER_PATH_SWITCH);
-        for (std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.begin();
-             it != m_drbMap.end();
-             ++it)
+        for (auto it = m_drbMap.begin(); it != m_drbMap.end(); ++it)
         {
             EpcEnbS1SapProvider::BearerToBeSwitched b;
             b.epsBearerId = it->second->m_epsBearerIdentity;
@@ -1362,8 +1349,7 @@
                  << (uint16_t)msg.measResults.measResultPCell.rsrpResult << " RSRQ "
                  << (uint16_t)msg.measResults.measResultPCell.rsrqResult);
 
-    for (std::list<LteRrcSap::MeasResultEutra>::iterator it =
-             msg.measResults.measResultListEutra.begin();
+    for (auto it = msg.measResults.measResultListEutra.begin();
          it != msg.measResults.measResultListEutra.end();
          ++it)
     {
@@ -1586,7 +1572,7 @@
 {
     NS_LOG_FUNCTION(this << (uint32_t)drbid);
     NS_ASSERT(0 != drbid);
-    std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.find(drbid);
+    auto it = m_drbMap.find(drbid);
     NS_ABORT_IF(it == m_drbMap.end());
     return it->second;
 }
@@ -1595,7 +1581,7 @@
 UeManager::RemoveDataRadioBearerInfo(uint8_t drbid)
 {
     NS_LOG_FUNCTION(this << (uint32_t)drbid);
-    std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.find(drbid);
+    auto it = m_drbMap.find(drbid);
     NS_ASSERT_MSG(it != m_drbMap.end(),
                   "request to remove radio bearer with unknown drbid " << drbid);
     m_drbMap.erase(it);
@@ -1642,9 +1628,7 @@
         rrcd.srbToAddModList.push_back(stam);
     }
 
-    for (std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.begin();
-         it != m_drbMap.end();
-         ++it)
+    for (auto it = m_drbMap.begin(); it != m_drbMap.end(); ++it)
     {
         LteRrcSap::DrbToAddMod dtam;
         dtam.epsBearerIdentity = it->second->m_epsBearerIdentity;
@@ -1939,7 +1923,6 @@
 TypeId
 LteEnbRrc::GetTypeId()
 {
-    NS_LOG_FUNCTION("LteEnbRrc::GetTypeId");
     static TypeId tid =
         TypeId("ns3::LteEnbRrc")
             .SetParent<Object>()
@@ -2351,7 +2334,7 @@
 LteEnbRrc::HasUeManager(uint16_t rnti) const
 {
     NS_LOG_FUNCTION(this << (uint32_t)rnti);
-    std::map<uint16_t, Ptr<UeManager>>::const_iterator it = m_ueMap.find(rnti);
+    auto it = m_ueMap.find(rnti);
     return (it != m_ueMap.end());
 }
 
@@ -2360,7 +2343,7 @@
 {
     NS_LOG_FUNCTION(this << (uint32_t)rnti);
     NS_ASSERT(0 != rnti);
-    std::map<uint16_t, Ptr<UeManager>>::iterator it = m_ueMap.find(rnti);
+    auto it = m_ueMap.find(rnti);
     NS_ASSERT_MSG(it != m_ueMap.end(), "UE manager for RNTI " << rnti << " not found");
     return it->second;
 }
@@ -2616,11 +2599,14 @@
 LteEnbRrc::SendData(Ptr<Packet> packet)
 {
     NS_LOG_FUNCTION(this << packet);
-
     EpsBearerTag tag;
     bool found = packet->RemovePacketTag(tag);
     NS_ASSERT_MSG(found, "no EpsBearerTag found in packet to be sent");
     Ptr<UeManager> ueManager = GetUeManager(tag.GetRnti());
+
+    NS_LOG_INFO("Sending a packet of " << packet->GetSize() << " bytes to IMSI "
+                                       << ueManager->GetImsi() << ", RNTI " << ueManager->GetRnti()
+                                       << ", BID " << (uint16_t)tag.GetBid());
     ueManager->SendData(tag.GetBid(), packet);
 
     return true;
@@ -2916,9 +2902,7 @@
     ackParams.sourceCellId = req.sourceCellId;
     ackParams.targetCellId = req.targetCellId;
 
-    for (std::vector<EpcX2Sap::ErabToBeSetupItem>::iterator it = req.bearers.begin();
-         it != req.bearers.end();
-         ++it)
+    for (auto it = req.bearers.begin(); it != req.bearers.end(); ++it)
     {
         ueManager->SetupDataRadioBearer(it->erabLevelQosParameters,
                                         it->erabId,
@@ -3083,7 +3067,7 @@
     NS_LOG_LOGIC("ueData = " << params.ueData);
     NS_LOG_LOGIC("ueData size = " << params.ueData->GetSize());
 
-    std::map<uint32_t, X2uTeidInfo>::iterator teidInfoIt = m_x2uTeidInfoMap.find(params.gtpTeid);
+    auto teidInfoIt = m_x2uTeidInfoMap.find(params.gtpTeid);
     if (teidInfoIt != m_x2uTeidInfoMap.end())
     {
         GetUeManager(teidInfoIt->second.rnti)->SendData(teidInfoIt->second.drbid, params.ueData);
@@ -3276,7 +3260,7 @@
 LteEnbRrc::RemoveUe(uint16_t rnti)
 {
     NS_LOG_FUNCTION(this << (uint32_t)rnti);
-    std::map<uint16_t, Ptr<UeManager>>::iterator it = m_ueMap.find(rnti);
+    auto it = m_ueMap.find(rnti);
     NS_ASSERT_MSG(it != m_ueMap.end(), "request to remove UE info with unknown rnti " << rnti);
     uint64_t imsi = it->second->GetImsi();
     uint16_t srsCi = (*it).second->GetSrsConfigurationIndex();
@@ -3438,7 +3422,7 @@
     else
     {
         // find a CI from the available ones
-        std::set<uint16_t>::reverse_iterator rit = m_ueSrsConfigurationIndexSet.rbegin();
+        auto rit = m_ueSrsConfigurationIndexSet.rbegin();
         NS_ASSERT(rit != m_ueSrsConfigurationIndexSet.rend());
         NS_LOG_DEBUG(this << " lower bound " << (*rit) << " of "
                           << g_srsCiHigh[m_srsCurrentPeriodicityId]);
@@ -3455,7 +3439,7 @@
                  srcCi < g_srsCiHigh[m_srsCurrentPeriodicityId];
                  srcCi++)
             {
-                std::set<uint16_t>::iterator it = m_ueSrsConfigurationIndexSet.find(srcCi);
+                auto it = m_ueSrsConfigurationIndexSet.find(srcCi);
                 if (it == m_ueSrsConfigurationIndexSet.end())
                 {
                     m_lastAllocatedConfigurationIndex = srcCi;
@@ -3472,7 +3456,7 @@
 LteEnbRrc::RemoveSrsConfigurationIndex(uint16_t srcCi)
 {
     NS_LOG_FUNCTION(this << srcCi);
-    std::set<uint16_t>::iterator it = m_ueSrsConfigurationIndexSet.find(srcCi);
+    auto it = m_ueSrsConfigurationIndexSet.find(srcCi);
     NS_ASSERT_MSG(it != m_ueSrsConfigurationIndexSet.end(),
                   "request to remove unknown SRS CI " << srcCi);
     m_ueSrsConfigurationIndexSet.erase(it);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-ffr-distributed-algorithm.cc ns-3.40/src/lte/model/lte-ffr-distributed-algorithm.cc
--- ns-3.39/src/lte/model/lte-ffr-distributed-algorithm.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-ffr-distributed-algorithm.cc	2023-09-27 13:30:37.818839600 -0700
@@ -247,7 +247,7 @@
 
     bool edgeRbg = m_dlEdgeRbgMap[rbgId];
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -288,7 +288,7 @@
 
     bool edgeRbg = m_ulEdgeRbgMap[rbId];
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -348,7 +348,7 @@
     //------------------------------------------------
     //  here Absolute mode is used
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         return 1;
@@ -397,7 +397,7 @@
     if (measResults.measId == m_rsrqMeasId)
     {
         // check if it is center or edge UE
-        std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+        auto it = m_ues.find(rnti);
         if (it == m_ues.end())
         {
             m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -431,7 +431,7 @@
     }
     else if (measResults.measId == m_rsrpMeasId)
     {
-        std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+        auto it = m_ues.find(rnti);
         if (it == m_ues.end())
         {
             m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -444,8 +444,7 @@
 
         if (measResults.haveMeasResultNeighCells && !measResults.measResultListEutra.empty())
         {
-            for (std::list<LteRrcSap::MeasResultEutra>::iterator it =
-                     measResults.measResultListEutra.begin();
+            for (auto it = measResults.measResultListEutra.begin();
                  it != measResults.measResultListEutra.end();
                  ++it)
             {
@@ -456,9 +455,7 @@
                 UpdateNeighbourMeasurements(rnti, it->physCellId, it->rsrpResult, it->rsrqResult);
 
                 bool found = false;
-                for (std::vector<uint16_t>::iterator ncIt = m_neighborCell.begin();
-                     ncIt != m_neighborCell.end();
-                     ncIt++)
+                for (auto ncIt = m_neighborCell.begin(); ncIt != m_neighborCell.end(); ncIt++)
                 {
                     if ((*ncIt) == it->physCellId)
                     {
@@ -499,14 +496,11 @@
     m_ulEdgeRbgMap.clear();
     m_ulEdgeRbgMap.resize(m_ulBandwidth, false);
 
-    MeasurementTable_t::iterator it1;
-    MeasurementRow_t::iterator it2;
     Ptr<UeMeasure> servingCellMeasures;
     Ptr<UeMeasure> neighbourCellMeasures;
 
     uint32_t edgeUeNum = 0;
-    std::map<uint16_t, uint8_t>::iterator areaIt;
-    for (areaIt = m_ues.begin(); areaIt != m_ues.end(); areaIt++)
+    for (auto areaIt = m_ues.begin(); areaIt != m_ues.end(); areaIt++)
     {
         if (areaIt->second == EdgeArea)
         {
@@ -516,9 +510,9 @@
 
     if (edgeUeNum != 0)
     {
-        for (it1 = m_ueMeasures.begin(); it1 != m_ueMeasures.end(); it1++)
+        for (auto it1 = m_ueMeasures.begin(); it1 != m_ueMeasures.end(); it1++)
         {
-            std::map<uint16_t, uint8_t>::iterator areaIt = m_ues.find(it1->first);
+            auto areaIt = m_ues.find(it1->first);
             if (areaIt->second != EdgeArea)
             {
                 continue;
@@ -527,7 +521,7 @@
             servingCellMeasures = nullptr;
             neighbourCellMeasures = nullptr;
 
-            it2 = it1->second.find(m_cellId);
+            auto it2 = it1->second.find(m_cellId);
             if (it2 != it1->second.end())
             {
                 servingCellMeasures = it2->second;
@@ -573,13 +567,12 @@
             metricA[i] = 0;
         }
 
-        std::map<uint16_t, uint32_t>::iterator cellIt;
-        for (cellIt = m_cellWeightMap.begin(); cellIt != m_cellWeightMap.end(); cellIt++)
+        for (auto cellIt = m_cellWeightMap.begin(); cellIt != m_cellWeightMap.end(); cellIt++)
         {
             NS_LOG_INFO("CellId: " << m_cellId << " NeighborCellId: " << cellIt->first
                                    << " Weight: " << cellIt->second);
 
-            std::map<uint16_t, std::vector<bool>>::iterator rntpIt = m_rntp.find(cellIt->first);
+            auto rntpIt = m_rntp.find(cellIt->first);
             if (rntpIt == m_rntp.end())
             {
                 continue;
@@ -596,15 +589,12 @@
 
         std::vector<uint16_t> sortedRbgByMetric;
         std::multimap<uint64_t, uint16_t> sortedMetricA;
-        for (std::map<uint16_t, uint64_t>::const_iterator it = metricA.begin(); it != metricA.end();
-             ++it)
+        for (auto it = metricA.begin(); it != metricA.end(); ++it)
         {
             sortedMetricA.insert(std::pair<uint64_t, uint16_t>(it->second, it->first));
         }
 
-        for (std::multimap<uint64_t, uint16_t>::const_iterator it = sortedMetricA.begin();
-             it != sortedMetricA.end();
-             ++it)
+        for (auto it = sortedMetricA.begin(); it != sortedMetricA.end(); ++it)
         {
             sortedRbgByMetric.push_back(it->second);
         }
@@ -625,9 +615,7 @@
         }
     }
 
-    for (std::vector<uint16_t>::iterator ncIt = m_neighborCell.begin();
-         ncIt != m_neighborCell.end();
-         ncIt++)
+    for (auto ncIt = m_neighborCell.begin(); ncIt != m_neighborCell.end(); ncIt++)
     {
         SendLoadInformation((*ncIt));
     }
@@ -674,7 +662,7 @@
     }
 
     uint16_t neighborCellId = params.cellInformationList[0].sourceCellId;
-    std::map<uint16_t, std::vector<bool>>::iterator it = m_rntp.find(neighborCellId);
+    auto it = m_rntp.find(neighborCellId);
     if (it != m_rntp.end())
     {
         it->second = params.cellInformationList[0].relativeNarrowbandTxBand.rntpPerPrbList;
@@ -695,22 +683,19 @@
 {
     NS_LOG_FUNCTION(this << rnti << cellId << (uint16_t)rsrq);
 
-    MeasurementTable_t::iterator it1;
-    it1 = m_ueMeasures.find(rnti);
+    auto it1 = m_ueMeasures.find(rnti);
 
     if (it1 == m_ueMeasures.end())
     {
         // insert a new UE entry
         MeasurementRow_t row;
-        std::pair<MeasurementTable_t::iterator, bool> ret;
-        ret = m_ueMeasures.insert(std::pair<uint16_t, MeasurementRow_t>(rnti, row));
+        auto ret = m_ueMeasures.insert(std::pair<uint16_t, MeasurementRow_t>(rnti, row));
         NS_ASSERT(ret.second);
         it1 = ret.first;
     }
 
     NS_ASSERT(it1 != m_ueMeasures.end());
-    std::map<uint16_t, Ptr<UeMeasure>>::iterator it2;
-    it2 = it1->second.find(cellId);
+    auto it2 = it1->second.find(cellId);
 
     if (it2 != it1->second.end())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-ffr-enhanced-algorithm.cc ns-3.40/src/lte/model/lte-ffr-enhanced-algorithm.cc
--- ns-3.39/src/lte/model/lte-ffr-enhanced-algorithm.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-ffr-enhanced-algorithm.cc	2023-09-27 13:30:37.818839600 -0700
@@ -478,8 +478,7 @@
 
     std::vector<bool> rbgMap = m_dlRbgMap;
 
-    std::map<uint16_t, std::vector<bool>>::iterator it;
-    for (it = m_dlRbgAvailableforUe.begin(); it != m_dlRbgAvailableforUe.end(); it++)
+    for (auto it = m_dlRbgAvailableforUe.begin(); it != m_dlRbgAvailableforUe.end(); it++)
     {
         NS_LOG_INFO("RNTI : " << it->first);
         std::vector<bool> rbgAvailableMap = it->second;
@@ -506,7 +505,7 @@
     bool isPrimarySegmentRbg = m_dlPrimarySegmentRbgMap[rbgId];
     bool isSecondarySegmentRbg = m_dlSecondarySegmentRbgMap[rbgId];
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -541,7 +540,7 @@
     {
         // check if RB can be used by UE based on CQI information
         NS_LOG_INFO("SECONDARY SEGMENT RNTI: " << rnti << "  rbgId: " << rbgId);
-        std::map<uint16_t, std::vector<bool>>::iterator it = m_dlRbgAvailableforUe.find(rnti);
+        auto it = m_dlRbgAvailableforUe.find(rnti);
         if (it != m_dlRbgAvailableforUe.end())
         {
             NS_LOG_INFO("RNTI: " << rnti << "  rbgId: " << rbgId
@@ -574,8 +573,7 @@
 
     std::vector<bool> rbgMap = m_ulRbgMap;
 
-    std::map<uint16_t, std::vector<bool>>::iterator it;
-    for (it = m_ulRbAvailableforUe.begin(); it != m_ulRbAvailableforUe.end(); it++)
+    for (auto it = m_ulRbAvailableforUe.begin(); it != m_ulRbAvailableforUe.end(); it++)
     {
         NS_LOG_INFO("RNTI : " << it->first);
         std::vector<bool> rbAvailableMap = it->second;
@@ -607,7 +605,7 @@
     bool isPrimarySegmentRbg = m_ulPrimarySegmentRbgMap[rbgId];
     bool isSecondarySegmentRbg = m_ulSecondarySegmentRbgMap[rbgId];
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -641,7 +639,7 @@
     {
         // check if RB can be used by UE based on CQI information
         NS_LOG_INFO("UL SECONDARY SEGMENT RNTI: " << rnti << "  rbgId: " << rbgId);
-        std::map<uint16_t, std::vector<bool>>::iterator it = m_ulRbAvailableforUe.find(rnti);
+        auto it = m_ulRbAvailableforUe.find(rnti);
         if (it != m_ulRbAvailableforUe.end())
         {
             NS_LOG_INFO("RNTI: " << rnti << "  rbgId: " << rbgId
@@ -670,10 +668,9 @@
         {
             NS_LOG_INFO("subband CQI reporting high layer configured");
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
 
-            std::map<uint16_t, uint8_t>::iterator ueIt = m_ues.find(rnti);
+            auto ueIt = m_ues.find(rnti);
             if (ueIt != m_ues.end())
             {
                 if (ueIt->second != CenterArea)
@@ -686,7 +683,7 @@
                 continue;
             }
 
-            it = m_dlCqi.find(rnti);
+            auto it = m_dlCqi.find(rnti);
             if (it == m_dlCqi.end())
             {
                 // create the new entry
@@ -708,8 +705,7 @@
 
     uint32_t rbgSize = GetRbgSize(m_dlBandwidth);
     m_dlRbgAvailableforUe.clear();
-    std::map<uint16_t, SbMeasResult_s>::iterator it;
-    for (it = m_dlCqi.begin(); it != m_dlCqi.end(); it++)
+    for (auto it = m_dlCqi.begin(); it != m_dlCqi.end(); it++)
     {
         uint16_t rnti = it->first;
         std::vector<bool> rbgAvailableMap;
@@ -741,9 +737,7 @@
     }
 
     m_ulRbAvailableforUe.clear();
-    for (std::map<uint16_t, std::vector<bool>>::iterator it = m_dlRbgAvailableforUe.begin();
-         it != m_dlRbgAvailableforUe.end();
-         it++)
+    for (auto it = m_dlRbgAvailableforUe.begin(); it != m_dlRbgAvailableforUe.end(); it++)
     {
         uint16_t rnti = it->first;
         std::vector<bool> dlRbgAvailableMap = it->second;
@@ -796,7 +790,7 @@
                                         uint16_t rb,
                                         std::map<uint16_t, std::vector<double>> ulCqiMap)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = ulCqiMap.find(rnti);
+    auto itCqi = ulCqiMap.find(rnti);
     if (itCqi == ulCqiMap.end())
     {
         // no cqi info about this UE
@@ -844,7 +838,7 @@
     //------------------------------------------------
     //  here Absolute mode is used
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         return 1;
@@ -903,7 +897,7 @@
     }
     else
     {
-        std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+        auto it = m_ues.find(rnti);
         if (it == m_ues.end())
         {
             m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-ffr-soft-algorithm.cc ns-3.40/src/lte/model/lte-ffr-soft-algorithm.cc
--- ns-3.39/src/lte/model/lte-ffr-soft-algorithm.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-ffr-soft-algorithm.cc	2023-09-27 13:30:37.818839600 -0700
@@ -424,7 +424,7 @@
     bool isMediumRbg = m_dlMediumRbgMap[rbgId];
     bool isEdgeRbg = m_dlEdgeRbgMap[rbgId];
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -485,7 +485,7 @@
     bool isMediumRbg = m_ulMediumRbgMap[rbgId];
     bool isEdgeRbg = m_ulEdgeRbgMap[rbgId];
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -563,7 +563,7 @@
     //------------------------------------------------
     //  here Absolute mode is used
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         return 1;
@@ -662,7 +662,7 @@
     }
     else
     {
-        std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+        auto it = m_ues.find(rnti);
         if (it == m_ues.end())
         {
             m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-fr-soft-algorithm.cc ns-3.40/src/lte/model/lte-fr-soft-algorithm.cc
--- ns-3.39/src/lte/model/lte-fr-soft-algorithm.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-fr-soft-algorithm.cc	2023-09-27 13:30:37.818839600 -0700
@@ -359,7 +359,7 @@
 
     bool edgeRbg = m_dlEdgeRbgMap[rbgId];
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -405,7 +405,7 @@
 
     bool edgeRbg = m_ulEdgeRbgMap[rbgId];
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -470,7 +470,7 @@
     //------------------------------------------------
     //  here Absolute mode is used
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         return 1;
@@ -536,7 +536,7 @@
     }
     else
     {
-        std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+        auto it = m_ues.find(rnti);
         if (it == m_ues.end())
         {
             m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-fr-strict-algorithm.cc ns-3.40/src/lte/model/lte-fr-strict-algorithm.cc
--- ns-3.39/src/lte/model/lte-fr-strict-algorithm.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-fr-strict-algorithm.cc	2023-09-27 13:30:37.818839600 -0700
@@ -397,7 +397,7 @@
 
     bool edgeRbg = m_dlEdgeRbgMap[rbgId];
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -438,7 +438,7 @@
 
     bool edgeRbg = m_ulEdgeRbgMap[rbgId];
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
@@ -498,7 +498,7 @@
     //------------------------------------------------
     //  here Absolute mode is used
 
-    std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
     if (it == m_ues.end())
     {
         return 1;
@@ -548,7 +548,7 @@
     }
     else
     {
-        std::map<uint16_t, uint8_t>::iterator it = m_ues.find(rnti);
+        auto it = m_ues.find(rnti);
         if (it == m_ues.end())
         {
             m_ues.insert(std::pair<uint16_t, uint8_t>(rnti, AreaUnset));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-harq-phy.cc ns-3.40/src/lte/model/lte-harq-phy.cc
--- ns-3.39/src/lte/model/lte-harq-phy.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-harq-phy.cc	2023-09-27 13:30:37.818839600 -0700
@@ -53,8 +53,7 @@
     NS_LOG_FUNCTION(this);
 
     // left shift UL HARQ buffers
-    std::map<uint16_t, std::vector<HarqProcessInfoList_t>>::iterator it;
-    for (it = m_miUlHarqProcessesInfoMap.begin(); it != m_miUlHarqProcessesInfoMap.end(); it++)
+    for (auto it = m_miUlHarqProcessesInfoMap.begin(); it != m_miUlHarqProcessesInfoMap.end(); it++)
     {
         (*it).second.erase((*it).second.begin());
         HarqProcessInfoList_t h;
@@ -87,8 +86,7 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, std::vector<HarqProcessInfoList_t>>::iterator it;
-    it = m_miUlHarqProcessesInfoMap.find(rnti);
+    auto it = m_miUlHarqProcessesInfoMap.find(rnti);
     NS_ASSERT_MSG(it != m_miUlHarqProcessesInfoMap.end(), " Does not find MI for RNTI");
     HarqProcessInfoList_t list = (*it).second.at(0);
     double mi = 0.0;
@@ -103,8 +101,7 @@
 LteHarqPhy::GetHarqProcessInfoUl(uint16_t rnti, uint8_t harqProcId)
 {
     NS_LOG_FUNCTION(this << rnti << (uint16_t)harqProcId);
-    std::map<uint16_t, std::vector<HarqProcessInfoList_t>>::iterator it;
-    it = m_miUlHarqProcessesInfoMap.find(rnti);
+    auto it = m_miUlHarqProcessesInfoMap.find(rnti);
     if (it == m_miUlHarqProcessesInfoMap.end())
     {
         // new entry
@@ -157,8 +154,7 @@
                                       uint16_t codeBytes)
 {
     NS_LOG_FUNCTION(this << rnti << mi);
-    std::map<uint16_t, std::vector<HarqProcessInfoList_t>>::iterator it;
-    it = m_miUlHarqProcessesInfoMap.find(rnti);
+    auto it = m_miUlHarqProcessesInfoMap.find(rnti);
     if (it == m_miUlHarqProcessesInfoMap.end())
     {
         // new entry
@@ -199,8 +195,7 @@
 LteHarqPhy::ResetUlHarqProcessStatus(uint16_t rnti, uint8_t id)
 {
     NS_LOG_FUNCTION(this << rnti << (uint16_t)id);
-    std::map<uint16_t, std::vector<HarqProcessInfoList_t>>::iterator it;
-    it = m_miUlHarqProcessesInfoMap.find(rnti);
+    auto it = m_miUlHarqProcessesInfoMap.find(rnti);
     if (it == m_miUlHarqProcessesInfoMap.end())
     {
         // new entry
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-interference.cc ns-3.40/src/lte/model/lte-interference.cc
--- ns-3.39/src/lte/model/lte-interference.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-interference.cc	2023-09-27 13:30:37.818839600 -0700
@@ -72,24 +72,17 @@
         m_rxSignal = rxPsd->Copy();
         m_lastChangeTime = Now();
         m_receiving = true;
-        for (std::list<Ptr<LteChunkProcessor>>::const_iterator it =
-                 m_rsPowerChunkProcessorList.begin();
-             it != m_rsPowerChunkProcessorList.end();
+        for (auto it = m_rsPowerChunkProcessorList.begin(); it != m_rsPowerChunkProcessorList.end();
              ++it)
         {
             (*it)->Start();
         }
-        for (std::list<Ptr<LteChunkProcessor>>::const_iterator it =
-                 m_interfChunkProcessorList.begin();
-             it != m_interfChunkProcessorList.end();
+        for (auto it = m_interfChunkProcessorList.begin(); it != m_interfChunkProcessorList.end();
              ++it)
         {
             (*it)->Start();
         }
-        for (std::list<Ptr<LteChunkProcessor>>::const_iterator it =
-                 m_sinrChunkProcessorList.begin();
-             it != m_sinrChunkProcessorList.end();
-             ++it)
+        for (auto it = m_sinrChunkProcessorList.begin(); it != m_sinrChunkProcessorList.end(); ++it)
         {
             (*it)->Start();
         }
@@ -117,24 +110,17 @@
     {
         ConditionallyEvaluateChunk();
         m_receiving = false;
-        for (std::list<Ptr<LteChunkProcessor>>::const_iterator it =
-                 m_rsPowerChunkProcessorList.begin();
-             it != m_rsPowerChunkProcessorList.end();
+        for (auto it = m_rsPowerChunkProcessorList.begin(); it != m_rsPowerChunkProcessorList.end();
              ++it)
         {
             (*it)->End();
         }
-        for (std::list<Ptr<LteChunkProcessor>>::const_iterator it =
-                 m_interfChunkProcessorList.begin();
-             it != m_interfChunkProcessorList.end();
+        for (auto it = m_interfChunkProcessorList.begin(); it != m_interfChunkProcessorList.end();
              ++it)
         {
             (*it)->End();
         }
-        for (std::list<Ptr<LteChunkProcessor>>::const_iterator it =
-                 m_sinrChunkProcessorList.begin();
-             it != m_sinrChunkProcessorList.end();
-             ++it)
+        for (auto it = m_sinrChunkProcessorList.begin(); it != m_sinrChunkProcessorList.end(); ++it)
         {
             (*it)->End();
         }
@@ -201,23 +187,16 @@
 
         SpectrumValue sinr = (*m_rxSignal) / interf;
         Time duration = Now() - m_lastChangeTime;
-        for (std::list<Ptr<LteChunkProcessor>>::const_iterator it =
-                 m_sinrChunkProcessorList.begin();
-             it != m_sinrChunkProcessorList.end();
-             ++it)
+        for (auto it = m_sinrChunkProcessorList.begin(); it != m_sinrChunkProcessorList.end(); ++it)
         {
             (*it)->EvaluateChunk(sinr, duration);
         }
-        for (std::list<Ptr<LteChunkProcessor>>::const_iterator it =
-                 m_interfChunkProcessorList.begin();
-             it != m_interfChunkProcessorList.end();
+        for (auto it = m_interfChunkProcessorList.begin(); it != m_interfChunkProcessorList.end();
              ++it)
         {
             (*it)->EvaluateChunk(interf, duration);
         }
-        for (std::list<Ptr<LteChunkProcessor>>::const_iterator it =
-                 m_rsPowerChunkProcessorList.begin();
-             it != m_rsPowerChunkProcessorList.end();
+        for (auto it = m_rsPowerChunkProcessorList.begin(); it != m_rsPowerChunkProcessorList.end();
              ++it)
         {
             (*it)->EvaluateChunk(*m_rxSignal, duration);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-mi-error-model.cc ns-3.40/src/lte/model/lte-mi-error-model.cc
--- ns-3.39/src/lte/model/lte-mi-error-model.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-mi-error-model.cc	2023-09-27 13:30:37.818839600 -0700
@@ -1042,7 +1042,7 @@
     NS_LOG_FUNCTION(sinr);
     double MI;
     double MIsum = 0.0;
-    Values::const_iterator sinrIt = sinr.ConstValuesBegin();
+    auto sinrIt = sinr.ConstValuesBegin();
     uint16_t rb = 0;
     NS_ASSERT(sinrIt != sinr.ConstValuesEnd());
     while (sinrIt != sinr.ConstValuesEnd())
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-pdcp.cc ns-3.40/src/lte/model/lte-pdcp.cc
--- ns-3.39/src/lte/model/lte-pdcp.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-pdcp.cc	2023-09-27 13:30:37.822839500 -0700
@@ -191,8 +191,6 @@
     }
 
     pdcpHeader.SetDcBit(LtePdcpHeader::DATA_PDU);
-
-    NS_LOG_LOGIC("PDCP header: " << pdcpHeader);
     p->AddHeader(pdcpHeader);
     p->AddByteTag(pdcpTag, 1, pdcpHeader.GetSerializedSize());
 
@@ -203,6 +201,7 @@
     txParams.lcid = m_lcid;
     txParams.pdcpPdu = p;
 
+    NS_LOG_INFO("Transmitting PDCP PDU with header: " << pdcpHeader);
     m_rlcSapProvider->TransmitPdcpPdu(txParams);
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-rlc-am.cc ns-3.40/src/lte/model/lte-rlc-am.cc
--- ns-3.39/src/lte/model/lte-rlc-am.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-rlc-am.cc	2023-09-27 13:30:37.822839500 -0700
@@ -238,7 +238,6 @@
                                                    << m_vrMs.GetValue());
         SequenceNumber10 sn;
         sn.SetModulusBase(m_vrR);
-        std::map<uint16_t, PduBuffer>::iterator pduIt;
         for (sn = m_vrR; sn < m_vrMs; sn++)
         {
             NS_LOG_LOGIC("SN = " << sn);
@@ -247,7 +246,7 @@
                 NS_LOG_LOGIC("Can't fit more NACKs in STATUS PDU");
                 break;
             }
-            pduIt = m_rxonBuffer.find(sn.GetValue());
+            auto pduIt = m_rxonBuffer.find(sn.GetValue());
             if (pduIt == m_rxonBuffer.end() || (!(pduIt->second.m_pduComplete)))
             {
                 NS_LOG_LOGIC("adding NACK_SN " << sn.GetValue());
@@ -258,7 +257,7 @@
         // 3GPP TS 36.322 section 6.2.2.1.4 ACK SN
         // find the  SN of the next not received RLC Data PDU
         // which is not reported as missing in the STATUS PDU.
-        pduIt = m_rxonBuffer.find(sn.GetValue());
+        auto pduIt = m_rxonBuffer.find(sn.GetValue());
         while ((sn < m_vrMs) && (pduIt != m_rxonBuffer.end()) && (pduIt->second.m_pduComplete))
         {
             NS_LOG_LOGIC("SN = " << sn << " < " << m_vrMs << " = " << (sn < m_vrMs));
@@ -660,8 +659,7 @@
 
     // Calculate FramingInfo flag according the status of the SDUs in the DataField
     uint8_t framingInfo = 0;
-    std::vector<Ptr<Packet>>::iterator it;
-    it = dataField.begin();
+    auto it = dataField.begin();
 
     // FIRST SEGMENT
     LteRlcSduStatusTag tag;
@@ -926,7 +924,7 @@
             //         - discard the duplicate byte segments.
             // note: re-segmentation of AMD PDU is currently not supported,
             // so we just check that the segment was not received before
-            std::map<uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find(seqNumber.GetValue());
+            auto it = m_rxonBuffer.find(seqNumber.GetValue());
             if (it != m_rxonBuffer.end())
             {
                 NS_ASSERT(!it->second.m_byteSegments.empty());
@@ -959,7 +957,7 @@
         //     - update VR(MS) to the SN of the first AMD PDU with SN > current VR(MS) for
         //       which not all byte segments have been received;
 
-        std::map<uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find(m_vrMs.GetValue());
+        auto it = m_rxonBuffer.find(m_vrMs.GetValue());
         if (it != m_rxonBuffer.end() && it->second.m_pduComplete)
         {
             int firstVrMs = m_vrMs.GetValue();
@@ -986,7 +984,7 @@
 
         if (seqNumber == m_vrR)
         {
-            std::map<uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find(seqNumber.GetValue());
+            auto it = m_rxonBuffer.find(seqNumber.GetValue());
             if (it != m_rxonBuffer.end() && it->second.m_pduComplete)
             {
                 it = m_rxonBuffer.find(m_vrR.GetValue());
@@ -1243,15 +1241,19 @@
         }
     } while (extensionBit == 1);
 
-    std::list<Ptr<Packet>>::iterator it;
-
     // Current reassembling state
     if (m_reassemblingState == WAITING_S0_FULL)
+    {
         NS_LOG_LOGIC("Reassembling State = 'WAITING_S0_FULL'");
+    }
     else if (m_reassemblingState == WAITING_SI_SF)
+    {
         NS_LOG_LOGIC("Reassembling State = 'WAITING_SI_SF'");
+    }
     else
+    {
         NS_LOG_LOGIC("Reassembling State = Unknown state");
+    }
 
     // Received framing Info
     NS_LOG_LOGIC("Framing Info = " << (uint16_t)framingInfo);
@@ -1271,7 +1273,7 @@
                 /**
                  * Deliver one or multiple PDUs
                  */
-                for (it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
+                for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
                 {
                     m_rlcSapUser->ReceivePdcpPdu(*it);
                 }
@@ -1401,7 +1403,7 @@
                 /**
                  * Deliver one or multiple PDUs
                  */
-                for (it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
+                for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
                 {
                     m_rlcSapUser->ReceivePdcpPdu(*it);
                 }
@@ -1702,7 +1704,7 @@
 
     m_vrMs = m_vrX;
     int firstVrMs = m_vrMs.GetValue();
-    std::map<uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find(m_vrMs.GetValue());
+    auto it = m_rxonBuffer.find(m_vrMs.GetValue());
     while (it != m_rxonBuffer.end() && it->second.m_pduComplete)
     {
         m_vrMs++;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-rlc-am-header.cc ns-3.40/src/lte/model/lte-rlc-am-header.cc
--- ns-3.39/src/lte/model/lte-rlc-am-header.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-rlc-am-header.cc	2023-09-27 13:30:37.822839500 -0700
@@ -248,8 +248,7 @@
     NS_LOG_FUNCTION(this);
     NS_ASSERT_MSG(m_dataControlBit == CONTROL_PDU && m_controlPduType == LteRlcAmHeader::STATUS_PDU,
                   "method allowed only for STATUS PDUs");
-    for (std::list<int>::iterator nackIt = m_nackSnList.begin(); nackIt != m_nackSnList.end();
-         ++nackIt)
+    for (auto nackIt = m_nackSnList.begin(); nackIt != m_nackSnList.end(); ++nackIt)
     {
         if ((*nackIt) == nack.GetValue())
         {
@@ -301,9 +300,9 @@
 void
 LteRlcAmHeader::Print(std::ostream& os) const
 {
-    std::list<uint8_t>::const_iterator it1 = m_extensionBits.begin();
-    std::list<uint16_t>::const_iterator it2 = m_lengthIndicators.begin();
-    std::list<int>::const_iterator it3 = m_nackSnList.begin();
+    auto it1 = m_extensionBits.begin();
+    auto it2 = m_lengthIndicators.begin();
+    auto it3 = m_nackSnList.begin();
 
     os << "Len=" << m_headerLength;
     os << " D/C=" << (uint16_t)m_dataControlBit;
@@ -362,9 +361,9 @@
 {
     Buffer::Iterator i = start;
 
-    std::list<uint8_t>::const_iterator it1 = m_extensionBits.begin();
-    std::list<uint16_t>::const_iterator it2 = m_lengthIndicators.begin();
-    std::list<int>::const_iterator it3 = m_nackSnList.begin();
+    auto it1 = m_extensionBits.begin();
+    auto it2 = m_lengthIndicators.begin();
+    auto it3 = m_nackSnList.begin();
 
     if (m_dataControlBit == DATA_PDU)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-rlc-header.cc ns-3.40/src/lte/model/lte-rlc-header.cc
--- ns-3.39/src/lte/model/lte-rlc-header.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-rlc-header.cc	2023-09-27 13:30:37.822839500 -0700
@@ -127,8 +127,8 @@
 void
 LteRlcHeader::Print(std::ostream& os) const
 {
-    std::list<uint8_t>::const_iterator it1 = m_extensionBits.begin();
-    std::list<uint16_t>::const_iterator it2 = m_lengthIndicators.begin();
+    auto it1 = m_extensionBits.begin();
+    auto it2 = m_lengthIndicators.begin();
 
     os << "Len=" << m_headerLength;
     os << " FI=" << (uint16_t)m_framingInfo;
@@ -168,8 +168,8 @@
 {
     Buffer::Iterator i = start;
 
-    std::list<uint8_t>::const_iterator it1 = m_extensionBits.begin();
-    std::list<uint16_t>::const_iterator it2 = m_lengthIndicators.begin();
+    auto it1 = m_extensionBits.begin();
+    auto it2 = m_lengthIndicators.begin();
 
     i.WriteU8(((m_framingInfo << 3) & 0x18) | (((*it1) << 2) & 0x04) |
               ((m_sequenceNumber.GetValue() >> 8) & 0x0003));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-rlc-um.cc ns-3.40/src/lte/model/lte-rlc-um.cc
--- ns-3.39/src/lte/model/lte-rlc-um.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-rlc-um.cc	2023-09-27 13:30:37.822839500 -0700
@@ -105,7 +105,6 @@
 LteRlcUm::DoTransmitPdcpPdu(Ptr<Packet> p)
 {
     NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << p->GetSize());
-
     if (m_txBufferSize + p->GetSize() <= m_maxTxBufferSize)
     {
         if (m_enablePdcpDiscarding)
@@ -123,7 +122,7 @@
             NS_LOG_DEBUG("head of line delay in MS:" << headOfLineDelayInMs);
             if (headOfLineDelayInMs > discardTimerMs)
             {
-                NS_LOG_DEBUG("Tx HOL is higher than this packet can allow. RLC SDU discarded");
+                NS_LOG_INFO("Tx HOL is higher than this packet can allow. RLC SDU discarded");
                 NS_LOG_DEBUG("headOfLineDelayInMs    = " << headOfLineDelayInMs);
                 NS_LOG_DEBUG("m_packetDelayBudgetMs    = " << m_packetDelayBudgetMs);
                 NS_LOG_DEBUG("packet size     = " << p->GetSize());
@@ -135,8 +134,7 @@
         LteRlcSduStatusTag tag;
         tag.SetStatus(LteRlcSduStatusTag::FULL_SDU);
         p->AddPacketTag(tag);
-
-        NS_LOG_LOGIC("Tx Buffer: New packet added");
+        NS_LOG_INFO("Adding RLC SDU to Tx Buffer after adding LteRlcSduStatusTag: FULL_SDU");
         m_txBuffer.emplace_back(p, Simulator::Now());
         m_txBufferSize += p->GetSize();
         NS_LOG_LOGIC("NumOfBuffers = " << m_txBuffer.size());
@@ -145,7 +143,7 @@
     else
     {
         // Discard full RLC SDU
-        NS_LOG_LOGIC("TxBuffer is full. RLC SDU discarded");
+        NS_LOG_INFO("Tx Buffer is full. RLC SDU discarded");
         NS_LOG_LOGIC("MaxTxBufferSize = " << m_maxTxBufferSize);
         NS_LOG_LOGIC("txBufferSize    = " << m_txBufferSize);
         NS_LOG_LOGIC("packet size     = " << p->GetSize());
@@ -165,11 +163,15 @@
 LteRlcUm::DoNotifyTxOpportunity(LteMacSapUser::TxOpportunityParameters txOpParams)
 {
     NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << txOpParams.bytes);
+    NS_LOG_INFO("RLC layer is preparing data for the following Tx opportunity of "
+                << txOpParams.bytes << " bytes for RNTI=" << m_rnti << ", LCID=" << (uint32_t)m_lcid
+                << ", CCID=" << (uint32_t)txOpParams.componentCarrierId << ", HARQ ID="
+                << (uint32_t)txOpParams.harqId << ", MIMO Layer=" << (uint32_t)txOpParams.layer);
 
     if (txOpParams.bytes <= 2)
     {
         // Stingy MAC: Header fix part is 2 bytes, we need more bytes for the data
-        NS_LOG_LOGIC("TX opportunity too small = " << txOpParams.bytes);
+        NS_LOG_INFO("TX opportunity too small - Only " << txOpParams.bytes << " bytes");
         return;
     }
 
@@ -364,8 +366,7 @@
     rlcHeader.SetSequenceNumber(m_sequenceNumber++);
 
     // Build RLC PDU with DataField and Header
-    std::vector<Ptr<Packet>>::iterator it;
-    it = dataField.begin();
+    auto it = dataField.begin();
 
     uint8_t framingInfo = 0;
 
@@ -431,6 +432,7 @@
     params.harqProcessId = txOpParams.harqId;
     params.componentCarrierId = txOpParams.componentCarrierId;
 
+    NS_LOG_INFO("Forward RLC PDU to MAC Layer");
     m_macSapProvider->TransmitPdu(params);
 
     if (!m_txBuffer.empty())
@@ -557,11 +559,10 @@
     {
         NS_LOG_LOGIC("Reception buffer contains SN = " << m_vrUr);
 
-        std::map<uint16_t, Ptr<Packet>>::iterator it;
         uint16_t newVrUr;
         SequenceNumber10 oldVrUr = m_vrUr;
 
-        it = m_rxBuffer.find(m_vrUr.GetValue());
+        auto it = m_rxBuffer.find(m_vrUr.GetValue());
         newVrUr = (it->first) + 1;
         while (m_rxBuffer.count(newVrUr) > 0)
         {
@@ -693,15 +694,19 @@
         }
     } while (extensionBit == 1);
 
-    std::list<Ptr<Packet>>::iterator it;
-
     // Current reassembling state
     if (m_reassemblingState == WAITING_S0_FULL)
+    {
         NS_LOG_LOGIC("Reassembling State = 'WAITING_S0_FULL'");
+    }
     else if (m_reassemblingState == WAITING_SI_SF)
+    {
         NS_LOG_LOGIC("Reassembling State = 'WAITING_SI_SF'");
+    }
     else
+    {
         NS_LOG_LOGIC("Reassembling State = Unknown state");
+    }
 
     // Received framing Info
     NS_LOG_LOGIC("Framing Info = " << (uint16_t)framingInfo);
@@ -720,7 +725,7 @@
                 /**
                  * Deliver one or multiple PDUs
                  */
-                for (it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
+                for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
                 {
                     m_rlcSapUser->ReceivePdcpPdu(*it);
                 }
@@ -900,7 +905,7 @@
                 /**
                  * Deliver one or multiple PDUs
                  */
-                for (it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
+                for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
                 {
                     m_rlcSapUser->ReceivePdcpPdu(*it);
                 }
@@ -1119,8 +1124,7 @@
 {
     NS_LOG_LOGIC("Reassemble Outside Window");
 
-    std::map<uint16_t, Ptr<Packet>>::iterator it;
-    it = m_rxBuffer.begin();
+    auto it = m_rxBuffer.begin();
 
     while ((it != m_rxBuffer.end()) && !IsInsideReorderingWindow(SequenceNumber10(it->first)))
     {
@@ -1129,7 +1133,7 @@
         // Reassemble RLC SDUs and deliver the PDCP PDU to upper layer
         ReassembleAndDeliver(it->second);
 
-        std::map<uint16_t, Ptr<Packet>>::iterator it_tmp = it;
+        auto it_tmp = it;
         ++it;
         m_rxBuffer.erase(it_tmp);
     }
@@ -1145,15 +1149,13 @@
 {
     NS_LOG_LOGIC("Reassemble SN between " << lowSeqNumber << " and " << highSeqNumber);
 
-    std::map<uint16_t, Ptr<Packet>>::iterator it;
-
     SequenceNumber10 reassembleSn = lowSeqNumber;
     NS_LOG_LOGIC("reassembleSN = " << reassembleSn);
     NS_LOG_LOGIC("highSeqNumber = " << highSeqNumber);
     while (reassembleSn < highSeqNumber)
     {
         NS_LOG_LOGIC("reassembleSn < highSeqNumber");
-        it = m_rxBuffer.find(reassembleSn.GetValue());
+        auto it = m_rxBuffer.find(reassembleSn.GetValue());
         NS_LOG_LOGIC("it->first  = " << it->first);
         NS_LOG_LOGIC("it->second = " << it->second);
         if (it != m_rxBuffer.end())
@@ -1214,10 +1216,9 @@
     //    - start t-Reordering;
     //    - set VR(UX) to VR(UH).
 
-    std::map<uint16_t, Ptr<Packet>>::iterator it;
     SequenceNumber10 newVrUr = m_vrUx;
 
-    while ((it = m_rxBuffer.find(newVrUr.GetValue())) != m_rxBuffer.end())
+    while (m_rxBuffer.find(newVrUr.GetValue()) != m_rxBuffer.end())
     {
         newVrUr++;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-rrc-header.cc ns-3.40/src/lte/model/lte-rrc-header.cc
--- ns-3.39/src/lte/model/lte-rrc-header.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-rrc-header.cc	2023-09-27 13:30:37.822839500 -0700
@@ -138,17 +138,17 @@
     SerializeSequenceOf(drbToAddModList.size(), MAX_DRB, 1);
 
     // Serialize the elements in the sequence-of list
-    std::list<LteRrcSap::DrbToAddMod>::iterator it = drbToAddModList.begin();
+    auto it = drbToAddModList.begin();
     for (; it != drbToAddModList.end(); it++)
     {
         // Serialize DRB-ToAddMod sequence
         // 5 optional fields. Extension marker is present.
         std::bitset<5> drbToAddModListOptionalFieldsPresent = std::bitset<5>();
-        drbToAddModListOptionalFieldsPresent.set(4, 1); // eps-BearerIdentity present
-        drbToAddModListOptionalFieldsPresent.set(3, 0); // pdcp-Config not present
-        drbToAddModListOptionalFieldsPresent.set(2, 1); // rlc-Config present
-        drbToAddModListOptionalFieldsPresent.set(1, 1); // logicalChannelIdentity present
-        drbToAddModListOptionalFieldsPresent.set(0, 1); // logicalChannelConfig present
+        drbToAddModListOptionalFieldsPresent.set(4, true);  // eps-BearerIdentity present
+        drbToAddModListOptionalFieldsPresent.set(3, false); // pdcp-Config not present
+        drbToAddModListOptionalFieldsPresent.set(2, true);  // rlc-Config present
+        drbToAddModListOptionalFieldsPresent.set(1, true);  // logicalChannelIdentity present
+        drbToAddModListOptionalFieldsPresent.set(0, true);  // logicalChannelConfig present
         SerializeSequence(drbToAddModListOptionalFieldsPresent, true);
 
         // Serialize eps-BearerIdentity::=INTEGER (0..15)
@@ -226,14 +226,14 @@
     SerializeSequenceOf(srbToAddModList.size(), 2, 1);
 
     // Serialize the elements in the sequence-of list
-    std::list<LteRrcSap::SrbToAddMod>::iterator it = srbToAddModList.begin();
+    auto it = srbToAddModList.begin();
     for (; it != srbToAddModList.end(); it++)
     {
         // Serialize SRB-ToAddMod sequence
         // 2 optional fields. Extension marker is present.
         std::bitset<2> srbToAddModListOptionalFieldsPresent = std::bitset<2>();
-        srbToAddModListOptionalFieldsPresent.set(1, 0); // rlc-Config not present
-        srbToAddModListOptionalFieldsPresent.set(0, 1); // logicalChannelConfig present
+        srbToAddModListOptionalFieldsPresent.set(1, false); // rlc-Config not present
+        srbToAddModListOptionalFieldsPresent.set(0, true);  // logicalChannelConfig present
         SerializeSequence(srbToAddModListOptionalFieldsPresent, true);
 
         // Serialize srb-Identity ::= INTEGER (1..2)
@@ -333,19 +333,19 @@
     optionalFieldsPhysicalConfigDedicated.set(
         9,
         physicalConfigDedicated.havePdschConfigDedicated); // pdsch-ConfigDedicated
-    optionalFieldsPhysicalConfigDedicated.set(8, 0);       // pucch-ConfigDedicated not present
-    optionalFieldsPhysicalConfigDedicated.set(7, 0);       // pusch-ConfigDedicated not present
-    optionalFieldsPhysicalConfigDedicated.set(6, 0); // uplinkPowerControlDedicated not present
-    optionalFieldsPhysicalConfigDedicated.set(5, 0); // tpc-PDCCH-ConfigPUCCH not present
-    optionalFieldsPhysicalConfigDedicated.set(4, 0); // tpc-PDCCH-ConfigPUSCH not present
-    optionalFieldsPhysicalConfigDedicated.set(3, 0); // cqi-ReportConfig not present
+    optionalFieldsPhysicalConfigDedicated.set(8, false);   // pucch-ConfigDedicated not present
+    optionalFieldsPhysicalConfigDedicated.set(7, false);   // pusch-ConfigDedicated not present
+    optionalFieldsPhysicalConfigDedicated.set(6, false); // uplinkPowerControlDedicated not present
+    optionalFieldsPhysicalConfigDedicated.set(5, false); // tpc-PDCCH-ConfigPUCCH not present
+    optionalFieldsPhysicalConfigDedicated.set(4, false); // tpc-PDCCH-ConfigPUSCH not present
+    optionalFieldsPhysicalConfigDedicated.set(3, false); // cqi-ReportConfig not present
     optionalFieldsPhysicalConfigDedicated.set(
         2,
         physicalConfigDedicated.haveSoundingRsUlConfigDedicated); // soundingRS-UL-ConfigDedicated
     optionalFieldsPhysicalConfigDedicated.set(
         1,
         physicalConfigDedicated.haveAntennaInfoDedicated); // antennaInfo
-    optionalFieldsPhysicalConfigDedicated.set(0, 0);       // schedulingRequestConfig not present
+    optionalFieldsPhysicalConfigDedicated.set(0, false);   // schedulingRequestConfig not present
     SerializeSequence(optionalFieldsPhysicalConfigDedicated, true);
 
     if (physicalConfigDedicated.havePdschConfigDedicated)
@@ -443,10 +443,9 @@
     optionalFieldsPresent.set(5, isSrbToAddModListPresent);  // srb-ToAddModList present
     optionalFieldsPresent.set(4, isDrbToAddModListPresent);  // drb-ToAddModList present
     optionalFieldsPresent.set(3, isDrbToReleaseListPresent); // drb-ToReleaseList present
-    optionalFieldsPresent.set(2, 0);                         // mac-MainConfig not present
-    optionalFieldsPresent.set(1, 0);                         // sps-Config not present
-    optionalFieldsPresent.set(0,
-                              (radioResourceConfigDedicated.havePhysicalConfigDedicated) ? 1 : 0);
+    optionalFieldsPresent.set(2, false);                     // mac-MainConfig not present
+    optionalFieldsPresent.set(1, false);                     // sps-Config not present
+    optionalFieldsPresent.set(0, radioResourceConfigDedicated.havePhysicalConfigDedicated);
     SerializeSequence(optionalFieldsPresent, true);
 
     // Serialize srbToAddModList
@@ -465,7 +464,7 @@
     if (isDrbToReleaseListPresent)
     {
         SerializeSequenceOf(radioResourceConfigDedicated.drbToReleaseList.size(), MAX_DRB, 1);
-        std::list<uint8_t>::iterator it = radioResourceConfigDedicated.drbToReleaseList.begin();
+        auto it = radioResourceConfigDedicated.drbToReleaseList.begin();
         for (; it != radioResourceConfigDedicated.drbToReleaseList.end(); it++)
         {
             // DRB-Identity ::= INTEGER (1..32)
@@ -485,9 +484,9 @@
 {
     // 3 optional fields, no extension marker.
     std::bitset<3> sysInfoBlk1Opts;
-    sysInfoBlk1Opts.set(2, 0); // p-Max absent
-    sysInfoBlk1Opts.set(1, 0); // tdd-Config absent
-    sysInfoBlk1Opts.set(0, 0); // nonCriticalExtension absent
+    sysInfoBlk1Opts.set(2, false); // p-Max absent
+    sysInfoBlk1Opts.set(1, false); // tdd-Config absent
+    sysInfoBlk1Opts.set(0, false); // nonCriticalExtension absent
     SerializeSequence(sysInfoBlk1Opts, false);
 
     // Serialize cellAccessRelatedInfo
@@ -548,15 +547,15 @@
 {
     // 9 optional fields. Extension marker yes.
     std::bitset<9> rrCfgCmmOpts;
-    rrCfgCmmOpts.set(8, 1); // rach-ConfigCommon is present
-    rrCfgCmmOpts.set(7, 0); // pdsch-ConfigCommon not present
-    rrCfgCmmOpts.set(6, 0); // phich-Config not present
-    rrCfgCmmOpts.set(5, 0); // pucch-ConfigCommon  not present
-    rrCfgCmmOpts.set(4, 0); // soundingRS-UL-ConfigCommon not present
-    rrCfgCmmOpts.set(3, 0); // uplinkPowerControlCommon not present
-    rrCfgCmmOpts.set(2, 0); // antennaInfoCommon not present
-    rrCfgCmmOpts.set(1, 0); // p-Max not present
-    rrCfgCmmOpts.set(0, 0); // tdd-Config not present
+    rrCfgCmmOpts.set(8, true);  // rach-ConfigCommon is present
+    rrCfgCmmOpts.set(7, false); // pdsch-ConfigCommon not present
+    rrCfgCmmOpts.set(6, false); // phich-Config not present
+    rrCfgCmmOpts.set(5, false); // pucch-ConfigCommon  not present
+    rrCfgCmmOpts.set(4, false); // soundingRS-UL-ConfigCommon not present
+    rrCfgCmmOpts.set(3, false); // uplinkPowerControlCommon not present
+    rrCfgCmmOpts.set(2, false); // antennaInfoCommon not present
+    rrCfgCmmOpts.set(1, false); // p-Max not present
+    rrCfgCmmOpts.set(0, false); // tdd-Config not present
 
     SerializeSequence(rrCfgCmmOpts, true);
 
@@ -719,8 +718,7 @@
         SerializeSequenceOf(measResults.measResultListEutra.size(), MAX_CELL_REPORT, 1);
 
         // serialize MeasResultEutra elements in the list
-        std::list<LteRrcSap::MeasResultEutra>::iterator it;
-        for (it = measResults.measResultListEutra.begin();
+        for (auto it = measResults.measResultListEutra.begin();
              it != measResults.measResultListEutra.end();
              it++)
         {
@@ -746,8 +744,7 @@
                 if (!it->cgiInfo.plmnIdentityList.empty())
                 {
                     SerializeSequenceOf(it->cgiInfo.plmnIdentityList.size(), 5, 1);
-                    std::list<uint32_t>::iterator it2;
-                    for (it2 = it->cgiInfo.plmnIdentityList.begin();
+                    for (auto it2 = it->cgiInfo.plmnIdentityList.begin();
                          it2 != it->cgiInfo.plmnIdentityList.end();
                          it2++)
                     {
@@ -1142,7 +1139,7 @@
     if (!measConfig.measObjectToRemoveList.empty())
     {
         SerializeSequenceOf(measConfig.measObjectToRemoveList.size(), MAX_OBJECT_ID, 1);
-        for (std::list<uint8_t>::iterator it = measConfig.measObjectToRemoveList.begin();
+        for (auto it = measConfig.measObjectToRemoveList.begin();
              it != measConfig.measObjectToRemoveList.end();
              it++)
         {
@@ -1153,8 +1150,7 @@
     if (!measConfig.measObjectToAddModList.empty())
     {
         SerializeSequenceOf(measConfig.measObjectToAddModList.size(), MAX_OBJECT_ID, 1);
-        for (std::list<LteRrcSap::MeasObjectToAddMod>::iterator it =
-                 measConfig.measObjectToAddModList.begin();
+        for (auto it = measConfig.measObjectToAddModList.begin();
              it != measConfig.measObjectToAddModList.end();
              it++)
         {
@@ -1184,8 +1180,7 @@
             if (!it->measObjectEutra.cellsToRemoveList.empty())
             {
                 SerializeSequenceOf(it->measObjectEutra.cellsToRemoveList.size(), MAX_CELL_MEAS, 1);
-                for (std::list<uint8_t>::iterator it2 =
-                         it->measObjectEutra.cellsToRemoveList.begin();
+                for (auto it2 = it->measObjectEutra.cellsToRemoveList.begin();
                      it2 != it->measObjectEutra.cellsToRemoveList.end();
                      it2++)
                 {
@@ -1196,8 +1191,7 @@
             if (!it->measObjectEutra.cellsToAddModList.empty())
             {
                 SerializeSequenceOf(it->measObjectEutra.cellsToAddModList.size(), MAX_CELL_MEAS, 1);
-                for (std::list<LteRrcSap::CellsToAddMod>::iterator it2 =
-                         it->measObjectEutra.cellsToAddModList.begin();
+                for (auto it2 = it->measObjectEutra.cellsToAddModList.begin();
                      it2 != it->measObjectEutra.cellsToAddModList.end();
                      it2++)
                 {
@@ -1219,8 +1213,7 @@
                 SerializeSequenceOf(it->measObjectEutra.blackCellsToRemoveList.size(),
                                     MAX_CELL_MEAS,
                                     1);
-                for (std::list<uint8_t>::iterator it2 =
-                         it->measObjectEutra.blackCellsToRemoveList.begin();
+                for (auto it2 = it->measObjectEutra.blackCellsToRemoveList.begin();
                      it2 != it->measObjectEutra.blackCellsToRemoveList.end();
                      it2++)
                 {
@@ -1233,8 +1226,7 @@
                 SerializeSequenceOf(it->measObjectEutra.blackCellsToAddModList.size(),
                                     MAX_CELL_MEAS,
                                     1);
-                for (std::list<LteRrcSap::BlackCellsToAddMod>::iterator it2 =
-                         it->measObjectEutra.blackCellsToAddModList.begin();
+                for (auto it2 = it->measObjectEutra.blackCellsToAddModList.begin();
                      it2 != it->measObjectEutra.blackCellsToAddModList.end();
                      it2++)
                 {
@@ -1243,7 +1235,7 @@
 
                     // Serialize PhysCellIdRange
                     // range optional
-                    std::bitset<1> rangePresent = std::bitset<1>(it2->physCellIdRange.haveRange);
+                    std::bitset<1> rangePresent(it2->physCellIdRange.haveRange);
                     SerializeSequence(rangePresent, false);
                     SerializeInteger(it2->physCellIdRange.start, 0, 503);
                     if (it2->physCellIdRange.haveRange)
@@ -1309,7 +1301,7 @@
     if (!measConfig.reportConfigToRemoveList.empty())
     {
         SerializeSequenceOf(measConfig.reportConfigToRemoveList.size(), MAX_REPORT_CONFIG_ID, 1);
-        for (std::list<uint8_t>::iterator it = measConfig.reportConfigToRemoveList.begin();
+        for (auto it = measConfig.reportConfigToRemoveList.begin();
              it != measConfig.reportConfigToRemoveList.end();
              it++)
         {
@@ -1320,8 +1312,7 @@
     if (!measConfig.reportConfigToAddModList.empty())
     {
         SerializeSequenceOf(measConfig.reportConfigToAddModList.size(), MAX_REPORT_CONFIG_ID, 1);
-        for (std::list<LteRrcSap::ReportConfigToAddMod>::iterator it =
-                 measConfig.reportConfigToAddModList.begin();
+        for (auto it = measConfig.reportConfigToAddModList.begin();
              it != measConfig.reportConfigToAddModList.end();
              it++)
         {
@@ -1546,7 +1537,7 @@
     if (!measConfig.measIdToRemoveList.empty())
     {
         SerializeSequenceOf(measConfig.measIdToRemoveList.size(), MAX_MEAS_ID, 1);
-        for (std::list<uint8_t>::iterator it = measConfig.measIdToRemoveList.begin();
+        for (auto it = measConfig.measIdToRemoveList.begin();
              it != measConfig.measIdToRemoveList.end();
              it++)
         {
@@ -1557,8 +1548,7 @@
     if (!measConfig.measIdToAddModList.empty())
     {
         SerializeSequenceOf(measConfig.measIdToAddModList.size(), MAX_MEAS_ID, 1);
-        for (std::list<LteRrcSap::MeasIdToAddMod>::iterator it =
-                 measConfig.measIdToAddModList.begin();
+        for (auto it = measConfig.measIdToAddModList.begin();
              it != measConfig.measIdToAddModList.end();
              it++)
         {
@@ -1573,7 +1563,7 @@
         // QuantityConfig sequence
         // 4 optional fields, only first (EUTRA) present. Extension marker yes.
         std::bitset<4> quantityConfigOpts(0);
-        quantityConfigOpts.set(3, 1);
+        quantityConfigOpts.set(3, true);
         SerializeSequence(quantityConfigOpts, true);
         SerializeSequence(std::bitset<0>(), false);
 
@@ -1826,7 +1816,7 @@
         !nonCriticalExtension.sCellToAddModList.empty()); // sCellToAddModList-r10
     noncriticalExtension_v1020.set(
         0,
-        0); // No nonCriticalExtension RRCConnectionReconfiguration-v1130-IEs
+        false); // No nonCriticalExtension RRCConnectionReconfiguration-v1130-IEs
     SerializeSequence(noncriticalExtension_v1020, false);
 
     if (!nonCriticalExtension.sCellToReleaseList.empty())
@@ -1844,9 +1834,9 @@
         for (auto& it : nonCriticalExtension.sCellToAddModList)
         {
             std::bitset<4> sCellToAddMod_r10;
-            sCellToAddMod_r10.set(3, 1); // sCellIndex
-            sCellToAddMod_r10.set(2, 1); // CellIdentification
-            sCellToAddMod_r10.set(1, 1); // RadioResourceConfigCommonSCell
+            sCellToAddMod_r10.set(3, true); // sCellIndex
+            sCellToAddMod_r10.set(2, true); // CellIdentification
+            sCellToAddMod_r10.set(1, true); // RadioResourceConfigCommonSCell
             sCellToAddMod_r10.set(
                 0,
                 it.haveRadioResourceConfigDedicatedSCell); // No nonCriticalExtension RRC
@@ -1855,8 +1845,8 @@
 
             // Serialize CellIdentification
             std::bitset<2> cellIdentification_r10;
-            cellIdentification_r10.set(1, 1); // phyCellId-r10
-            cellIdentification_r10.set(0, 1); // dl-CarrierFreq-r10
+            cellIdentification_r10.set(1, true); // phyCellId-r10
+            cellIdentification_r10.set(0, true); // dl-CarrierFreq-r10
             SerializeSequence(cellIdentification_r10, false);
 
             SerializeInteger(it.cellIdentification.physCellId, 1, 65536);
@@ -1888,23 +1878,23 @@
     {
         // 5 optional fields. Extension marker not present.
         std::bitset<5> nonUlConfiguration_r10;
-        nonUlConfiguration_r10.set(4, 1); // Dl- bandwidth --> convert in enum
-        nonUlConfiguration_r10.set(3, 1); // AntennaInfoCommon-r10
-        nonUlConfiguration_r10.set(2, 0); // phich-Config-r10 Not Implemented
-        nonUlConfiguration_r10.set(1, 1); // pdschConfigCommon
-        nonUlConfiguration_r10.set(0, 0); // Tdd-Config-r10 Not Implemented
+        nonUlConfiguration_r10.set(4, true);  // Dl- bandwidth --> convert in enum
+        nonUlConfiguration_r10.set(3, true);  // AntennaInfoCommon-r10
+        nonUlConfiguration_r10.set(2, false); // phich-Config-r10 Not Implemented
+        nonUlConfiguration_r10.set(1, true);  // pdschConfigCommon
+        nonUlConfiguration_r10.set(0, false); // Tdd-Config-r10 Not Implemented
         SerializeSequence(nonUlConfiguration_r10, false);
 
         SerializeInteger(rrccsc.nonUlConfiguration.dlBandwidth, 6, 100);
 
         std::bitset<1> antennaInfoCommon_r10;
-        antennaInfoCommon_r10.set(0, 1);
+        antennaInfoCommon_r10.set(0, true);
         SerializeSequence(antennaInfoCommon_r10, false);
         SerializeInteger(rrccsc.nonUlConfiguration.antennaInfoCommon.antennaPortsCount, 0, 65536);
 
         std::bitset<2> pdschConfigCommon_r10;
-        pdschConfigCommon_r10.set(1, 1);
-        pdschConfigCommon_r10.set(0, 1);
+        pdschConfigCommon_r10.set(1, true);
+        pdschConfigCommon_r10.set(0, true);
         SerializeSequence(pdschConfigCommon_r10, false);
 
         SerializeInteger(rrccsc.nonUlConfiguration.pdschConfigCommon.referenceSignalPower, -60, 50);
@@ -1915,20 +1905,20 @@
         // Serialize Ul Configuration
         //  7 optional fields. Extension marker present.
         std::bitset<7> UlConfiguration_r10;
-        UlConfiguration_r10.set(6, 1); // ul-Configuration-r10
-        UlConfiguration_r10.set(5, 0); // p-Max-r10 Not Implemented
-        UlConfiguration_r10.set(4, 1); // uplinkPowerControlCommonSCell-r10
-        UlConfiguration_r10.set(3, 0); // soundingRS-UL-ConfigCommon-r10
-        UlConfiguration_r10.set(2, 0); // ul-CyclicPrefixLength-r10
-        UlConfiguration_r10.set(1, 1); // prach-ConfigSCell-r10
-        UlConfiguration_r10.set(0, 0); // pusch-ConfigCommon-r10 Not Implemented
+        UlConfiguration_r10.set(6, true);  // ul-Configuration-r10
+        UlConfiguration_r10.set(5, false); // p-Max-r10 Not Implemented
+        UlConfiguration_r10.set(4, true);  // uplinkPowerControlCommonSCell-r10
+        UlConfiguration_r10.set(3, false); // soundingRS-UL-ConfigCommon-r10
+        UlConfiguration_r10.set(2, false); // ul-CyclicPrefixLength-r10
+        UlConfiguration_r10.set(1, true);  // prach-ConfigSCell-r10
+        UlConfiguration_r10.set(0, false); // pusch-ConfigCommon-r10 Not Implemented
         SerializeSequence(UlConfiguration_r10, true);
 
         // Serialize ulFreqInfo
         std::bitset<3> FreqInfo_r10;
-        FreqInfo_r10.set(2, 1); // ulCarrierFreq
-        FreqInfo_r10.set(1, 1); // UlBandwidth
-        FreqInfo_r10.set(0, 0); // additionalSpectrumEmissionSCell-r10 Not Implemented
+        FreqInfo_r10.set(2, true);  // ulCarrierFreq
+        FreqInfo_r10.set(1, true);  // UlBandwidth
+        FreqInfo_r10.set(0, false); // additionalSpectrumEmissionSCell-r10 Not Implemented
         SerializeSequence(FreqInfo_r10, false);
 
         SerializeInteger(rrccsc.ulConfiguration.ulFreqInfo.ulCarrierFreq, 0, MAX_EARFCN);
@@ -1936,8 +1926,8 @@
 
         // Serialize UlPowerControlCommonSCell
         std::bitset<2> UlPowerControlCommonSCell_r10;
-        UlPowerControlCommonSCell_r10.set(1, 0); // p0-NominalPUSCH-r10 Not Implemented
-        UlPowerControlCommonSCell_r10.set(0, 1); // alpha
+        UlPowerControlCommonSCell_r10.set(1, false); // p0-NominalPUSCH-r10 Not Implemented
+        UlPowerControlCommonSCell_r10.set(0, true);  // alpha
         SerializeSequence(UlPowerControlCommonSCell_r10, false);
 
         SerializeInteger(rrccsc.ulConfiguration.ulPowerControlCommonSCell.alpha, 0, 65536);
@@ -1947,7 +1937,7 @@
 
         // Serialize PrachConfigSCell
         std::bitset<1> prachConfigSCell_r10;
-        prachConfigSCell_r10.set(0, 1);
+        prachConfigSCell_r10.set(0, true);
         SerializeSequence(prachConfigSCell_r10, false);
         SerializeInteger(rrccsc.ulConfiguration.prachConfigSCell.index, 0, 256);
     }
@@ -1959,7 +1949,7 @@
 {
     // Serialize RadioResourceConfigDedicatedSCell
     std::bitset<1> RadioResourceConfigDedicatedSCell_r10;
-    RadioResourceConfigDedicatedSCell_r10.set(0, 1);
+    RadioResourceConfigDedicatedSCell_r10.set(0, true);
     SerializeSequence(RadioResourceConfigDedicatedSCell_r10, false);
 
     LteRrcSap::PhysicalConfigDedicatedSCell pcdsc = rrcdsc.physicalConfigDedicatedSCell;
@@ -1980,8 +1970,8 @@
         // Serialize NonUl configuration
         std::bitset<4> nulOpt;
         nulOpt.set(3, pcdsc.haveAntennaInfoDedicated);
-        nulOpt.set(2, 0); // crossCarrierSchedulingConfig-r10 Not Implemented
-        nulOpt.set(1, 0); // csi-RS-Config-r10 Not Implemented
+        nulOpt.set(2, false); // crossCarrierSchedulingConfig-r10 Not Implemented
+        nulOpt.set(1, false); // csi-RS-Config-r10 Not Implemented
         nulOpt.set(0, pcdsc.havePdschConfigDedicated); // pdsch-ConfigDedicated-r10
         SerializeSequence(nulOpt, false);
 
@@ -2024,12 +2014,12 @@
         // Serialize Ul Configuration
         std::bitset<7> ulOpt;
         ulOpt.set(6, pcdsc.haveAntennaInfoUlDedicated); // antennaInfoUL-r10
-        ulOpt.set(5, 0); // pusch-ConfigDedicatedSCell-r10 not present
-        ulOpt.set(4, 0); // uplinkPowerControlDedicatedSCell-r10 not present
-        ulOpt.set(3, 0); // cqi-ReportConfigSCell-r10 not present
+        ulOpt.set(5, false); // pusch-ConfigDedicatedSCell-r10 not present
+        ulOpt.set(4, false); // uplinkPowerControlDedicatedSCell-r10 not present
+        ulOpt.set(3, false); // cqi-ReportConfigSCell-r10 not present
         ulOpt.set(2, pcdsc.haveSoundingRsUlConfigDedicated); // soundingRS-UL-ConfigDedicated-r10
-        ulOpt.set(1, 0); // soundingRS-UL-ConfigDedicated-v1020 not present
-        ulOpt.set(0, 0); // soundingRS-UL-ConfigDedicatedAperiodic-r10 not present
+        ulOpt.set(1, false); // soundingRS-UL-ConfigDedicated-v1020 not present
+        ulOpt.set(0, false); // soundingRS-UL-ConfigDedicatedAperiodic-r10 not present
         SerializeSequence(ulOpt, false);
 
         if (pcdsc.haveAntennaInfoUlDedicated)
@@ -3068,8 +3058,7 @@
                      LteRrcSap::RadioResourceConfigDedicated radioResourceConfigDedicated) const
 {
     os << "   srbToAddModList: " << std::endl;
-    std::list<LteRrcSap::SrbToAddMod>::iterator it =
-        radioResourceConfigDedicated.srbToAddModList.begin();
+    auto it = radioResourceConfigDedicated.srbToAddModList.begin();
     for (; it != radioResourceConfigDedicated.srbToAddModList.end(); it++)
     {
         os << "      srbIdentity: " << (int)it->srbIdentity << std::endl;
@@ -3085,8 +3074,7 @@
     os << std::endl;
 
     os << "   drbToAddModList: " << std::endl;
-    std::list<LteRrcSap::DrbToAddMod>::iterator it2 =
-        radioResourceConfigDedicated.drbToAddModList.begin();
+    auto it2 = radioResourceConfigDedicated.drbToAddModList.begin();
     for (; it2 != radioResourceConfigDedicated.drbToAddModList.end(); it2++)
     {
         os << "      epsBearerIdentity: " << (int)it2->epsBearerIdentity << std::endl;
@@ -3105,7 +3093,7 @@
     os << std::endl;
 
     os << "   drbToReleaseList: ";
-    std::list<uint8_t>::iterator it3 = radioResourceConfigDedicated.drbToReleaseList.begin();
+    auto it3 = radioResourceConfigDedicated.drbToReleaseList.begin();
     for (; it3 != radioResourceConfigDedicated.drbToReleaseList.end(); it3++)
     {
         os << (int)*it3 << ", ";
@@ -5336,9 +5324,9 @@
     std::bitset<6> options;
     options.set(5, m_haveMeasConfig);
     options.set(4, m_haveMobilityControlInfo);
-    options.set(3, 0); // No dedicatedInfoNASList
+    options.set(3, false); // No dedicatedInfoNASList
     options.set(2, m_haveRadioResourceConfigDedicated);
-    options.set(1, 0);                          // No securityConfigHO
+    options.set(1, false);                      // No securityConfigHO
     options.set(0, m_haveNonCriticalExtension); // Implemented nonCriticalExtension because
                                                 // compatibility with R10 - CA
     SerializeSequence(options, false);
@@ -5356,7 +5344,7 @@
         std::bitset<4> mobCtrlIntoOptional;
         mobCtrlIntoOptional.set(3, m_mobilityControlInfo.haveCarrierFreq);
         mobCtrlIntoOptional.set(2, m_mobilityControlInfo.haveCarrierBandwidth);
-        mobCtrlIntoOptional.set(1, 0); // No additionalSpectrumEmission
+        mobCtrlIntoOptional.set(1, false); // No additionalSpectrumEmission
         mobCtrlIntoOptional.set(0, m_mobilityControlInfo.haveRachConfigDedicated);
         SerializeSequence(mobCtrlIntoOptional, true);
 
@@ -5409,7 +5397,7 @@
         // Serialize NonCriticalExtension RRCConnectionReconfiguration-v890-IEs sequence:
         // 2 optional fields. Extension marker not present.
         std::bitset<2> noncriticalExtension_v890;
-        noncriticalExtension_v890.set(1, 0); // No lateNonCriticalExtension
+        noncriticalExtension_v890.set(1, false); // No lateNonCriticalExtension
         noncriticalExtension_v890.set(
             0,
             m_haveNonCriticalExtension); // Implemented nonCriticalExtension because compatibility
@@ -5420,8 +5408,8 @@
         // Serialize NonCriticalExtension RRCConnectionReconfiguration-v920-IEs sequence:
         // 3 optional fields. Extension marker not present.
         std::bitset<3> noncriticalExtension_v920;
-        noncriticalExtension_v920.set(1, 0); // No otherConfig-r9
-        noncriticalExtension_v920.set(1, 0); // No fullConfig-r9
+        noncriticalExtension_v920.set(1, false); // No otherConfig-r9
+        noncriticalExtension_v920.set(1, false); // No fullConfig-r9
         // Enable RRCCoonectionReconfiguration-v1020-IEs
         noncriticalExtension_v920.set(
             0,
@@ -5601,7 +5589,7 @@
         {
             os << "  measObjectToRemoveList: ";
             std::list<uint8_t> auxList = m_measConfig.measObjectToRemoveList;
-            std::list<uint8_t>::iterator it = auxList.begin();
+            auto it = auxList.begin();
             for (; it != auxList.end(); it++)
             {
                 os << (int)*it << ", ";
@@ -5612,7 +5600,7 @@
         {
             os << "  reportConfigToRemoveList: ";
             std::list<uint8_t> auxList = m_measConfig.reportConfigToRemoveList;
-            std::list<uint8_t>::iterator it = auxList.begin();
+            auto it = auxList.begin();
             for (; it != auxList.end(); it++)
             {
                 os << (int)*it << ", ";
@@ -5623,7 +5611,7 @@
         {
             os << "  measIdToRemoveList: ";
             std::list<uint8_t> auxList = m_measConfig.measIdToRemoveList;
-            std::list<uint8_t>::iterator it = auxList.begin();
+            auto it = auxList.begin();
             for (; it != auxList.end(); it++)
             {
                 os << (int)*it << ", ";
@@ -5635,7 +5623,7 @@
         {
             os << "  measObjectToAddMod: " << std::endl;
             std::list<LteRrcSap::MeasObjectToAddMod> auxList = m_measConfig.measObjectToAddModList;
-            std::list<LteRrcSap::MeasObjectToAddMod>::iterator it = auxList.begin();
+            auto it = auxList.begin();
             for (; it != auxList.end(); it++)
             {
                 os << "    measObjectId: " << (int)it->measObjectId << std::endl;
@@ -5652,7 +5640,7 @@
                 {
                     os << "    cellsToRemoveList: ";
                     std::list<uint8_t> auxList = it->measObjectEutra.cellsToRemoveList;
-                    std::list<uint8_t>::iterator it = auxList.begin();
+                    auto it = auxList.begin();
                     for (; it != auxList.end(); it++)
                     {
                         os << (int)*it << ", ";
@@ -5664,7 +5652,7 @@
                 {
                     os << "    blackCellsToRemoveList: ";
                     std::list<uint8_t> auxList = it->measObjectEutra.blackCellsToRemoveList;
-                    std::list<uint8_t>::iterator it = auxList.begin();
+                    auto it = auxList.begin();
                     for (; it != auxList.end(); it++)
                     {
                         os << (int)*it << ", ";
@@ -5677,7 +5665,7 @@
                     os << "    cellsToAddModList: " << std::endl;
                     std::list<LteRrcSap::CellsToAddMod> auxList =
                         it->measObjectEutra.cellsToAddModList;
-                    std::list<LteRrcSap::CellsToAddMod>::iterator it = auxList.begin();
+                    auto it = auxList.begin();
                     for (; it != auxList.end(); it++)
                     {
                         os << "      cellIndex: " << (int)it->cellIndex << std::endl;
@@ -5693,7 +5681,7 @@
                     os << "    blackCellsToAddModList: " << std::endl;
                     std::list<LteRrcSap::BlackCellsToAddMod> auxList =
                         it->measObjectEutra.blackCellsToAddModList;
-                    std::list<LteRrcSap::BlackCellsToAddMod>::iterator it = auxList.begin();
+                    auto it = auxList.begin();
                     for (; it != auxList.end(); it++)
                     {
                         os << "      cellIndex: " << (int)it->cellIndex << std::endl;
@@ -5720,7 +5708,7 @@
             os << "  reportConfigToAddModList: " << std::endl;
             std::list<LteRrcSap::ReportConfigToAddMod> auxList =
                 m_measConfig.reportConfigToAddModList;
-            std::list<LteRrcSap::ReportConfigToAddMod>::iterator it = auxList.begin();
+            auto it = auxList.begin();
             for (; it != auxList.end(); it++)
             {
                 os << "    reportConfigId: " << (int)it->reportConfigId << std::endl;
@@ -5778,7 +5766,7 @@
         {
             os << "  measIdToAddModList: " << std::endl;
             std::list<LteRrcSap::MeasIdToAddMod> auxList = m_measConfig.measIdToAddModList;
-            std::list<LteRrcSap::MeasIdToAddMod>::iterator it = auxList.begin();
+            auto it = auxList.begin();
             for (; it != auxList.end(); it++)
             {
                 os << "    measId: " << (int)it->measId << std::endl;
@@ -6015,10 +6003,10 @@
     // Serialize HandoverPreparationInformation-r8-IEs sequence
     // 4 optional fields, no extension marker.
     std::bitset<4> handoverPrepInfoOpts;
-    handoverPrepInfoOpts.set(3, 1); // as-Config present
-    handoverPrepInfoOpts.set(2, 0); // rrm-Config not present
-    handoverPrepInfoOpts.set(1, 0); // as-Context not present
-    handoverPrepInfoOpts.set(0, 0); // nonCriticalExtension not present
+    handoverPrepInfoOpts.set(3, true);  // as-Config present
+    handoverPrepInfoOpts.set(2, false); // rrm-Config not present
+    handoverPrepInfoOpts.set(1, false); // as-Context not present
+    handoverPrepInfoOpts.set(0, false); // nonCriticalExtension not present
     SerializeSequence(handoverPrepInfoOpts, false);
 
     // Serialize ue-RadioAccessCapabilityInfo
@@ -7062,7 +7050,7 @@
     {
         std::list<LteRrcSap::MeasResultEutra> measResultListEutra =
             m_measurementReport.measResults.measResultListEutra;
-        std::list<LteRrcSap::MeasResultEutra>::iterator it = measResultListEutra.begin();
+        auto it = measResultListEutra.begin();
         for (; it != measResultListEutra.end(); it++)
         {
             os << "   physCellId =" << (int)it->physCellId << std::endl;
@@ -7076,7 +7064,7 @@
                    << std::endl;
                 if (!it->cgiInfo.plmnIdentityList.empty())
                 {
-                    for (std::list<uint32_t>::iterator it2 = it->cgiInfo.plmnIdentityList.begin();
+                    for (auto it2 = it->cgiInfo.plmnIdentityList.begin();
                          it2 != it->cgiInfo.plmnIdentityList.end();
                          it2++)
                     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-rrc-protocol-ideal.cc ns-3.40/src/lte/model/lte-rrc-protocol-ideal.cc
--- ns-3.39/src/lte/model/lte-rrc-protocol-ideal.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-rrc-protocol-ideal.cc	2023-09-27 13:30:37.822839500 -0700
@@ -206,9 +206,9 @@
 
     // walk list of all nodes to get the peer eNB
     Ptr<LteEnbNetDevice> enbDev;
-    NodeList::Iterator listEnd = NodeList::End();
+    auto listEnd = NodeList::End();
     bool found = false;
-    for (NodeList::Iterator i = NodeList::Begin(); (i != listEnd) && (!found); ++i)
+    for (auto i = NodeList::Begin(); (i != listEnd) && (!found); ++i)
     {
         Ptr<Node> node = *i;
         int nDevs = node->GetNDevices();
@@ -288,8 +288,7 @@
 LteUeRrcSapProvider*
 LteEnbRrcProtocolIdeal::GetUeRrcSapProvider(uint16_t rnti)
 {
-    std::map<uint16_t, LteUeRrcSapProvider*>::const_iterator it;
-    it = m_enbRrcSapProviderMap.find(rnti);
+    auto it = m_enbRrcSapProviderMap.find(rnti);
     NS_ASSERT_MSG(it != m_enbRrcSapProviderMap.end(), "could not find RNTI = " << rnti);
     return it->second;
 }
@@ -297,8 +296,7 @@
 void
 LteEnbRrcProtocolIdeal::SetUeRrcSapProvider(uint16_t rnti, LteUeRrcSapProvider* p)
 {
-    std::map<uint16_t, LteUeRrcSapProvider*>::iterator it;
-    it = m_enbRrcSapProviderMap.find(rnti);
+    auto it = m_enbRrcSapProviderMap.find(rnti);
     // assign UE RRC only if the RNTI is found at eNB
     if (it != m_enbRrcSapProviderMap.end())
     {
@@ -359,7 +357,7 @@
     NS_LOG_FUNCTION(this << cellId);
     // walk list of all nodes to get UEs with this cellId
     Ptr<LteUeRrc> ueRrc;
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> node = *i;
         int nDevs = node->GetNDevices();
@@ -576,8 +574,7 @@
     p->RemoveHeader(h);
     uint32_t msgId = h.GetMsgId();
     NS_LOG_INFO(" decoding msgId = " << msgId);
-    std::map<uint32_t, LteRrcSap::HandoverPreparationInfo>::iterator it =
-        g_handoverPreparationInfoMsgMap.find(msgId);
+    auto it = g_handoverPreparationInfoMsgMap.find(msgId);
     NS_ASSERT_MSG(it != g_handoverPreparationInfoMsgMap.end(), "msgId " << msgId << " not found");
     LteRrcSap::HandoverPreparationInfo msg = it->second;
     g_handoverPreparationInfoMsgMap.erase(it);
@@ -699,8 +696,7 @@
     p->RemoveHeader(h);
     uint32_t msgId = h.GetMsgId();
     NS_LOG_INFO(" decoding msgId = " << msgId);
-    std::map<uint32_t, LteRrcSap::RrcConnectionReconfiguration>::iterator it =
-        g_handoverCommandMsgMap.find(msgId);
+    auto it = g_handoverCommandMsgMap.find(msgId);
     NS_ASSERT_MSG(it != g_handoverCommandMsgMap.end(), "msgId " << msgId << " not found");
     LteRrcSap::RrcConnectionReconfiguration msg = it->second;
     g_handoverCommandMsgMap.erase(it);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-rrc-protocol-real.cc ns-3.40/src/lte/model/lte-rrc-protocol-real.cc
--- ns-3.39/src/lte/model/lte-rrc-protocol-real.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-rrc-protocol-real.cc	2023-09-27 13:30:37.822839500 -0700
@@ -269,9 +269,9 @@
 
     // walk list of all nodes to get the peer eNB
     Ptr<LteEnbNetDevice> enbDev;
-    NodeList::Iterator listEnd = NodeList::End();
+    auto listEnd = NodeList::End();
     bool found = false;
-    for (NodeList::Iterator i = NodeList::Begin(); (i != listEnd) && (!found); ++i)
+    for (auto i = NodeList::Begin(); (i != listEnd) && (!found); ++i)
     {
         Ptr<Node> node = *i;
         int nDevs = node->GetNDevices();
@@ -400,8 +400,7 @@
 {
     NS_LOG_FUNCTION(this);
     delete m_enbRrcSapUser;
-    for (std::map<uint16_t, LteEnbRrcSapProvider::CompleteSetupUeParameters>::iterator it =
-             m_completeSetupUeParametersMap.begin();
+    for (auto it = m_completeSetupUeParametersMap.begin();
          it != m_completeSetupUeParametersMap.end();
          ++it)
     {
@@ -442,8 +441,7 @@
 LteUeRrcSapProvider*
 LteEnbRrcProtocolReal::GetUeRrcSapProvider(uint16_t rnti)
 {
-    std::map<uint16_t, LteUeRrcSapProvider*>::const_iterator it;
-    it = m_enbRrcSapProviderMap.find(rnti);
+    auto it = m_enbRrcSapProviderMap.find(rnti);
     NS_ASSERT_MSG(it != m_enbRrcSapProviderMap.end(), "could not find RNTI = " << rnti);
     return it->second;
 }
@@ -451,8 +449,7 @@
 void
 LteEnbRrcProtocolReal::SetUeRrcSapProvider(uint16_t rnti, LteUeRrcSapProvider* p)
 {
-    std::map<uint16_t, LteUeRrcSapProvider*>::iterator it;
-    it = m_enbRrcSapProviderMap.find(rnti);
+    auto it = m_enbRrcSapProviderMap.find(rnti);
     // assign UE RRC only if the RNTI is found at eNB
     if (it != m_enbRrcSapProviderMap.end())
     {
@@ -503,8 +500,7 @@
     m_setupUeParametersMap[rnti] = params;
 
     LteEnbRrcSapProvider::CompleteSetupUeParameters completeSetupUeParameters;
-    std::map<uint16_t, LteEnbRrcSapProvider::CompleteSetupUeParameters>::iterator csupIt =
-        m_completeSetupUeParametersMap.find(rnti);
+    auto csupIt = m_completeSetupUeParametersMap.find(rnti);
     if (csupIt == m_completeSetupUeParametersMap.end())
     {
         // Create LteRlcSapUser, LtePdcpSapUser
@@ -527,8 +523,7 @@
 LteEnbRrcProtocolReal::DoRemoveUe(uint16_t rnti)
 {
     NS_LOG_FUNCTION(this << rnti);
-    std::map<uint16_t, LteEnbRrcSapProvider::CompleteSetupUeParameters>::iterator it =
-        m_completeSetupUeParametersMap.find(rnti);
+    auto it = m_completeSetupUeParametersMap.find(rnti);
     NS_ASSERT(it != m_completeSetupUeParametersMap.end());
     delete it->second.srb0SapUser;
     delete it->second.srb1SapUser;
@@ -543,7 +538,7 @@
     NS_LOG_FUNCTION(this << cellId);
     // walk list of all nodes to get UEs with this cellId
     Ptr<LteUeRrc> ueRrc;
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> node = *i;
         int nDevs = node->GetNDevices();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-spectrum-phy.cc ns-3.40/src/lte/model/lte-spectrum-phy.cc
--- ns-3.39/src/lte/model/lte-spectrum-phy.cc	2023-07-05 14:23:48.013428000 -0700
+++ ns-3.40/src/lte/model/lte-spectrum-phy.cc	2023-09-27 13:30:37.822839500 -0700
@@ -911,11 +911,10 @@
     TbId_t tbId;
     tbId.m_rnti = rnti;
     tbId.m_layer = layer;
-    expectedTbs_t::iterator it;
-    it = m_expectedTbs.find(tbId);
+    auto it = m_expectedTbs.find(tbId);
     if (it != m_expectedTbs.end())
     {
-        // might be a TB of an unreceived packet (due to high progpalosses)
+        // might be a TB of an unreceived packet (due to high propagation losses)
         m_expectedTbs.erase(it);
     }
     // insert new entry
@@ -933,8 +932,7 @@
     for (uint8_t i = 0; i < 2; i++)
     {
         tbId.m_layer = i;
-        expectedTbs_t::iterator it;
-        it = m_expectedTbs.find(tbId);
+        auto it = m_expectedTbs.find(tbId);
         if (it != m_expectedTbs.end())
         {
             m_expectedTbs.erase(it);
@@ -955,7 +953,7 @@
     m_interferenceData->EndRx();
     NS_LOG_DEBUG(this << " No. of burts " << m_rxPacketBurstList.size());
     NS_LOG_DEBUG(this << " Expected TBs " << m_expectedTbs.size());
-    expectedTbs_t::iterator itTb = m_expectedTbs.begin();
+    auto itTb = m_expectedTbs.begin();
 
     // apply transmission mode gain
     NS_LOG_DEBUG(this << " txMode " << (uint16_t)m_transmissionMode << " gain "
@@ -1029,11 +1027,9 @@
         itTb++;
     }
     std::map<uint16_t, DlInfoListElement_s> harqDlInfoMap;
-    for (std::list<Ptr<PacketBurst>>::const_iterator i = m_rxPacketBurstList.begin();
-         i != m_rxPacketBurstList.end();
-         ++i)
+    for (auto i = m_rxPacketBurstList.begin(); i != m_rxPacketBurstList.end(); ++i)
     {
-        for (std::list<Ptr<Packet>>::const_iterator j = (*i)->Begin(); j != (*i)->End(); ++j)
+        for (auto j = (*i)->Begin(); j != (*i)->End(); ++j)
         {
             // retrieve TB info of this packet
             LteRadioBearerTag tag;
@@ -1094,8 +1090,7 @@
                     }
                     else
                     {
-                        std::map<uint16_t, DlInfoListElement_s>::iterator itHarq =
-                            harqDlInfoMap.find(tbId.m_rnti);
+                        auto itHarq = harqDlInfoMap.find(tbId.m_rnti);
                         if (itHarq == harqDlInfoMap.end())
                         {
                             DlInfoListElement_s harqDlInfo;
@@ -1170,8 +1165,7 @@
     }
 
     // send DL HARQ feedback to LtePhy
-    std::map<uint16_t, DlInfoListElement_s>::iterator itHarq;
-    for (itHarq = harqDlInfoMap.begin(); itHarq != harqDlInfoMap.end(); itHarq++)
+    for (auto itHarq = harqDlInfoMap.begin(); itHarq != harqDlInfoMap.end(); itHarq++)
     {
         if (!m_ltePhyDlHarqFeedbackCallback.IsNull())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-spectrum-value-helper.cc ns-3.40/src/lte/model/lte-spectrum-value-helper.cc
--- ns-3.39/src/lte/model/lte-spectrum-value-helper.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/lte-spectrum-value-helper.cc	2023-09-27 13:30:37.822839500 -0700
@@ -43,7 +43,7 @@
 ostream&
 operator<<(ostream& os, const vector<int>& v)
 {
-    vector<int>::const_iterator it = v.begin();
+    auto it = v.begin();
     while (it != v.end())
     {
         os << *it << " ";
@@ -252,7 +252,7 @@
     NS_LOG_FUNCTION(earfcn << txBandwidthConfiguration);
     Ptr<SpectrumModel> ret;
     LteSpectrumModelId key(earfcn, txBandwidthConfiguration);
-    std::map<LteSpectrumModelId, Ptr<SpectrumModel>>::iterator it = g_lteSpectrumModelMap.find(key);
+    auto it = g_lteSpectrumModelMap.find(key);
     if (it != g_lteSpectrumModelMap.end())
     {
         ret = it->second;
@@ -297,7 +297,7 @@
 
     double txPowerDensity = (powerTxW / (txBandwidthConfiguration * 180000));
 
-    for (std::vector<int>::iterator it = activeRbs.begin(); it != activeRbs.end(); it++)
+    for (auto it = activeRbs.begin(); it != activeRbs.end(); it++)
     {
         int rbId = (*it);
         (*txPsd)[rbId] = txPowerDensity;
@@ -323,11 +323,11 @@
     // powerTx is expressed in dBm. We must convert it into natural unit.
     double basicPowerTxW = std::pow(10., (powerTx - 30) / 10);
 
-    for (std::vector<int>::iterator it = activeRbs.begin(); it != activeRbs.end(); it++)
+    for (auto it = activeRbs.begin(); it != activeRbs.end(); it++)
     {
         int rbId = (*it);
 
-        std::map<int, double>::iterator powerIt = powerTxMap.find(rbId);
+        auto powerIt = powerTxMap.find(rbId);
 
         double txPowerDensity;
 
@@ -365,7 +365,7 @@
 
     double txPowerDensity = (powerTxW / (activeRbs.size() * 180000));
 
-    for (std::vector<int>::iterator it = activeRbs.begin(); it != activeRbs.end(); it++)
+    for (auto it = activeRbs.begin(); it != activeRbs.end(); it++)
     {
         int rbId = (*it);
         (*txPsd)[rbId] = txPowerDensity;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-ue-component-carrier-manager.cc ns-3.40/src/lte/model/lte-ue-component-carrier-manager.cc
--- ns-3.39/src/lte/model/lte-ue-component-carrier-manager.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/lte-ue-component-carrier-manager.cc	2023-09-27 13:30:37.822839500 -0700
@@ -77,8 +77,7 @@
 {
     NS_LOG_FUNCTION(this);
     bool result = false;
-    std::map<uint8_t, LteMacSapProvider*>::iterator it;
-    it = m_macSapProvidersMap.find(componentCarrierId);
+    auto it = m_macSapProvidersMap.find(componentCarrierId);
     if (componentCarrierId > m_noOfComponentCarriers)
     {
         NS_FATAL_ERROR("Inconsistent componentCarrierId or you didn't call "
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-ue-mac.cc ns-3.40/src/lte/model/lte-ue-mac.cc
--- ns-3.39/src/lte/model/lte-ue-mac.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/lte-ue-mac.cc	2023-09-27 13:30:37.822839500 -0700
@@ -333,9 +333,7 @@
 {
     NS_LOG_FUNCTION(this << (uint32_t)params.lcid);
 
-    std::map<uint8_t, LteMacSapProvider::ReportBufferStatusParameters>::iterator it;
-
-    it = m_ulBsrReceived.find(params.lcid);
+    auto it = m_ulBsrReceived.find(params.lcid);
     if (it != m_ulBsrReceived.end())
     {
         // update entry
@@ -371,13 +369,11 @@
     bsr.m_macCeType = MacCeListElement_s::BSR;
 
     // BSR is reported for each LCG
-    std::map<uint8_t, LteMacSapProvider::ReportBufferStatusParameters>::iterator it;
     std::vector<uint32_t> queue(4, 0); // one value per each of the 4 LCGs, initialized to 0
-    for (it = m_ulBsrReceived.begin(); it != m_ulBsrReceived.end(); it++)
+    for (auto it = m_ulBsrReceived.begin(); it != m_ulBsrReceived.end(); it++)
     {
         uint8_t lcid = it->first;
-        std::map<uint8_t, LcInfo>::iterator lcInfoMapIt;
-        lcInfoMapIt = m_lcInfoMap.find(lcid);
+        auto lcInfoMapIt = m_lcInfoMap.find(lcid);
         NS_ASSERT(lcInfoMapIt != m_lcInfoMap.end());
         NS_ASSERT_MSG((lcid != 0) ||
                           (((*it).second.txQueueSize == 0) && ((*it).second.retxQueueSize == 0) &&
@@ -462,10 +458,9 @@
     // trigger tx opportunity for Message 3 over LC 0
     // this is needed since Message 3's UL GRANT is in the RAR, not in UL-DCIs
     const uint8_t lc0Lcid = 0;
-    std::map<uint8_t, LcInfo>::iterator lc0InfoIt = m_lcInfoMap.find(lc0Lcid);
+    auto lc0InfoIt = m_lcInfoMap.find(lc0Lcid);
     NS_ASSERT(lc0InfoIt != m_lcInfoMap.end());
-    std::map<uint8_t, LteMacSapProvider::ReportBufferStatusParameters>::iterator lc0BsrIt =
-        m_ulBsrReceived.find(lc0Lcid);
+    auto lc0BsrIt = m_ulBsrReceived.find(lc0Lcid);
     if ((lc0BsrIt != m_ulBsrReceived.end()) && (lc0BsrIt->second.txQueueSize > 0))
     {
         NS_ASSERT_MSG(raResponse.m_grant.m_tbSize > lc0BsrIt->second.txQueueSize,
@@ -596,7 +591,7 @@
 LteUeMac::DoReset()
 {
     NS_LOG_FUNCTION(this);
-    std::map<uint8_t, LcInfo>::iterator it = m_lcInfoMap.begin();
+    auto it = m_lcInfoMap.begin();
     while (it != m_lcInfoMap.end())
     {
         // don't delete CCCH)
@@ -633,7 +628,7 @@
     if (tag.GetRnti() == m_rnti)
     {
         // packet is for the current user
-        std::map<uint8_t, LcInfo>::const_iterator it = m_lcInfoMap.find(tag.GetLcid());
+        auto it = m_lcInfoMap.find(tag.GetLcid());
         if (it != m_lcInfoMap.end())
         {
             LteMacSapUser::ReceivePduParameters rxPduParams;
@@ -663,10 +658,9 @@
             Ptr<PacketBurst> pb = CreateObject<PacketBurst>();
             m_miUlHarqProcessesPacket.at(m_harqProcessId) = pb;
             // Retrieve data from RLC
-            std::map<uint8_t, LteMacSapProvider::ReportBufferStatusParameters>::iterator itBsr;
             uint16_t activeLcs = 0;
             uint32_t statusPduMinSize = 0;
-            for (itBsr = m_ulBsrReceived.begin(); itBsr != m_ulBsrReceived.end(); itBsr++)
+            for (auto itBsr = m_ulBsrReceived.begin(); itBsr != m_ulBsrReceived.end(); itBsr++)
             {
                 if (((*itBsr).second.statusPduSize > 0) || ((*itBsr).second.retxQueueSize > 0) ||
                     ((*itBsr).second.txQueueSize > 0))
@@ -688,7 +682,6 @@
                 NS_LOG_ERROR(this << " No active flows for this UL-DCI");
                 return;
             }
-            std::map<uint8_t, LcInfo>::iterator it;
             uint32_t bytesPerActiveLc = dci.m_tbSize / activeLcs;
             bool statusPduPriority = false;
             if ((statusPduMinSize != 0) && (bytesPerActiveLc < statusPduMinSize))
@@ -709,9 +702,9 @@
 
             LteMacSapUser::TxOpportunityParameters txOpParams;
 
-            for (it = m_lcInfoMap.begin(); it != m_lcInfoMap.end(); it++)
+            for (auto it = m_lcInfoMap.begin(); it != m_lcInfoMap.end(); it++)
             {
-                itBsr = m_ulBsrReceived.find((*it).first);
+                auto itBsr = m_ulBsrReceived.find((*it).first);
                 NS_LOG_DEBUG(this << " Processing LC " << (uint32_t)(*it).first
                                   << " bytesPerActiveLc " << bytesPerActiveLc);
                 if ((itBsr != m_ulBsrReceived.end()) &&
@@ -849,7 +842,7 @@
             // HARQ retransmission -> retrieve data from HARQ buffer
             NS_LOG_DEBUG(this << " UE MAC RETX HARQ " << (uint16_t)m_harqProcessId);
             Ptr<PacketBurst> pb = m_miUlHarqProcessesPacket.at(m_harqProcessId);
-            for (std::list<Ptr<Packet>>::const_iterator j = pb->Begin(); j != pb->End(); ++j)
+            for (auto j = pb->Begin(); j != pb->End(); ++j)
             {
                 Ptr<Packet> pkt = (*j)->Copy();
                 m_uePhySapProvider->SendMacPdu(pkt);
@@ -867,10 +860,7 @@
                               << (uint32_t)m_raRnti);
             if (raRnti == m_raRnti) // RAR corresponds to TX subframe of preamble
             {
-                for (std::list<RarLteControlMessage::Rar>::const_iterator it =
-                         rarMsg->RarListBegin();
-                     it != rarMsg->RarListEnd();
-                     ++it)
+                for (auto it = rarMsg->RarListBegin(); it != rarMsg->RarListEnd(); ++it)
                 {
                     if (it->rapId == m_raPreambleId) // RAR is for me
                     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-ue-net-device.cc ns-3.40/src/lte/model/lte-ue-net-device.cc
--- ns-3.39/src/lte/model/lte-ue-net-device.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/lte-ue-net-device.cc	2023-09-27 13:30:37.822839500 -0700
@@ -267,8 +267,7 @@
     m_isConstructed = true;
     UpdateConfig();
 
-    std::map<uint8_t, Ptr<ComponentCarrierUe>>::iterator it;
-    for (it = m_ccMap.begin(); it != m_ccMap.end(); ++it)
+    for (auto it = m_ccMap.begin(); it != m_ccMap.end(); ++it)
     {
         it->second->GetPhy()->Initialize();
         it->second->GetMac()->Initialize();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-ue-phy.cc ns-3.40/src/lte/model/lte-ue-phy.cc
--- ns-3.39/src/lte/model/lte-ue-phy.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/lte-ue-phy.cc	2023-09-27 13:30:37.822839500 -0700
@@ -609,8 +609,8 @@
         // RSRP evaluated as averaged received power among RBs
         double sum = 0.0;
         uint8_t rbNum = 0;
-        Values::const_iterator it;
-        for (it = m_rsReceivedPower.ConstValuesBegin(); it != m_rsReceivedPower.ConstValuesEnd();
+        for (auto it = m_rsReceivedPower.ConstValuesBegin();
+             it != m_rsReceivedPower.ConstValuesEnd();
              it++)
         {
             // convert PSD [W/Hz] to linear power [W] for the single RE
@@ -648,14 +648,14 @@
         // measure instantaneous RSRQ now
         NS_ASSERT_MSG(m_rsInterferencePowerUpdated, " RS interference power info obsolete");
 
-        std::list<PssElement>::iterator itPss = m_pssList.begin();
+        auto itPss = m_pssList.begin();
         while (itPss != m_pssList.end())
         {
             uint16_t rbNum = 0;
             double rssiSum = 0.0;
 
-            Values::const_iterator itIntN = m_rsInterferencePower.ConstValuesBegin();
-            Values::const_iterator itPj = m_rsReceivedPower.ConstValuesBegin();
+            auto itIntN = m_rsInterferencePower.ConstValuesBegin();
+            auto itPj = m_rsReceivedPower.ConstValuesBegin();
             for (itPj = m_rsReceivedPower.ConstValuesBegin();
                  itPj != m_rsReceivedPower.ConstValuesEnd();
                  itIntN++, itPj++)
@@ -675,8 +675,7 @@
                 NS_LOG_INFO(this << " PSS RNTI " << m_rnti << " cellId " << m_cellId << " has RSRQ "
                                  << rsrq_dB << " and RBnum " << rbNum);
                 // store measurements
-                std::map<uint16_t, UeMeasurementsElement>::iterator itMeasMap;
-                itMeasMap = m_ueMeasurementsMap.find((*itPss).cellId);
+                auto itMeasMap = m_ueMeasurementsMap.find((*itPss).cellId);
                 if (itMeasMap != m_ueMeasurementsMap.end())
                 {
                     (*itMeasMap).second.rsrqSum += rsrq_dB;
@@ -706,9 +705,8 @@
     // averaged SINR among RBs
     double sum = 0.0;
     uint8_t rbNum = 0;
-    Values::const_iterator it;
 
-    for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
+    for (auto it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
     {
         sum += (*it);
         rbNum++;
@@ -818,8 +816,8 @@
     if (m_enableUplinkPowerControl)
     {
         double sum = 0;
-        Values::const_iterator it;
-        for (it = m_rsReceivedPower.ConstValuesBegin(); it != m_rsReceivedPower.ConstValuesEnd();
+        for (auto it = m_rsReceivedPower.ConstValuesBegin();
+             it != m_rsReceivedPower.ConstValuesEnd();
              it++)
         {
             double powerTxW = ((*it) * 180000);
@@ -940,8 +938,7 @@
 
     LteUeCphySapUser::UeMeasurementsParameters ret;
 
-    std::map<uint16_t, UeMeasurementsElement>::iterator it;
-    for (it = m_ueMeasurementsMap.begin(); it != m_ueMeasurementsMap.end(); it++)
+    for (auto it = m_ueMeasurementsMap.begin(); it != m_ueMeasurementsMap.end(); it++)
     {
         double avg_rsrp = (*it).second.rsrpSum / (double)(*it).second.rsrpNum;
         double avg_rsrq = (*it).second.rsrqSum / (double)(*it).second.rsrqNum;
@@ -968,7 +965,7 @@
                                (*it).first,
                                avg_rsrp,
                                avg_rsrq,
-                               ((*it).first == m_cellId ? 1 : 0),
+                               (*it).first == m_cellId,
                                m_componentCarrierId);
     }
 
@@ -1029,10 +1026,9 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::list<Ptr<LteControlMessage>>::iterator it;
     NS_LOG_DEBUG(this << " I am rnti = " << m_rnti << " and I received msgs "
                       << (uint16_t)msgList.size());
-    for (it = msgList.begin(); it != msgList.end(); it++)
+    for (auto it = msgList.begin(); it != msgList.end(); it++)
     {
         Ptr<LteControlMessage> msg = (*it);
 
@@ -1135,10 +1131,7 @@
             Ptr<RarLteControlMessage> rarMsg = DynamicCast<RarLteControlMessage>(msg);
             if (rarMsg->GetRaRnti() == m_raRnti)
             {
-                for (std::list<RarLteControlMessage::Rar>::const_iterator it =
-                         rarMsg->RarListBegin();
-                     it != rarMsg->RarListEnd();
-                     ++it)
+                for (auto it = rarMsg->RarListBegin(); it != rarMsg->RarListEnd(); ++it)
                 {
                     if (it->rapId != m_raPreambleId)
                     {
@@ -1195,8 +1188,7 @@
 
     double sum = 0.0;
     uint16_t nRB = 0;
-    Values::const_iterator itPi;
-    for (itPi = p->ConstValuesBegin(); itPi != p->ConstValuesEnd(); itPi++)
+    for (auto itPi = p->ConstValuesBegin(); itPi != p->ConstValuesEnd(); itPi++)
     {
         // convert PSD [W/Hz] to linear power [W] for the single RE
         double powerTxW = ((*itPi) * 180000.0) / 12.0;
@@ -1211,8 +1203,7 @@
     // note that m_pssReceptionThreshold does not apply here
 
     // store measurements
-    std::map<uint16_t, UeMeasurementsElement>::iterator itMeasMap =
-        m_ueMeasurementsMap.find(cellId);
+    auto itMeasMap = m_ueMeasurementsMap.find(cellId);
     if (itMeasMap == m_ueMeasurementsMap.end())
     {
         // insert new entry
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-ue-phy.h ns-3.40/src/lte/model/lte-ue-phy.h
--- ns-3.39/src/lte/model/lte-ue-phy.h	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/lte-ue-phy.h	2023-09-27 13:30:37.822839500 -0700
@@ -698,7 +698,7 @@
 
     uint16_t m_srsPeriodicity;    ///< SRS periodicity
     uint16_t m_srsSubframeOffset; ///< SRS subframe offset
-    uint16_t m_srsConfigured;     ///< SRS configured
+    bool m_srsConfigured;         ///< SRS configured
     Time m_srsStartTime;          ///< SRS start time
 
     double m_paLinear; ///< PA linear
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/lte-ue-rrc.cc ns-3.40/src/lte/model/lte-ue-rrc.cc
--- ns-3.39/src/lte/model/lte-ue-rrc.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/lte-ue-rrc.cc	2023-09-27 13:30:37.826839700 -0700
@@ -591,7 +591,7 @@
 
     if (drbid != 0)
     {
-        std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.find(drbid);
+        auto it = m_drbMap.find(drbid);
         NS_ASSERT_MSG(it != m_drbMap.end(), "could not find bearer with drbid == " << drbid);
 
         LtePdcpSapProvider::TransmitPdcpSduParameters params;
@@ -681,8 +681,7 @@
         m_rrcSapUser->SendRrcConnectionReconfigurationCompleted(msg);
 
         // 3GPP TS 36.331 section 5.5.6.1 Measurements related actions upon handover
-        std::map<uint8_t, LteRrcSap::MeasIdToAddMod>::iterator measIdIt;
-        for (measIdIt = m_varMeasConfig.measIdList.begin();
+        for (auto measIdIt = m_varMeasConfig.measIdList.begin();
              measIdIt != m_varMeasConfig.measIdList.end();
              ++measIdIt)
         {
@@ -917,8 +916,7 @@
     // layer 3 filtering does not apply in IDLE mode
     bool useLayer3Filtering = (m_state == CONNECTED_NORMALLY);
     bool triggering = true;
-    std::vector<LteUeCphySapUser::UeMeasurementsElement>::iterator newMeasIt;
-    for (newMeasIt = params.m_ueMeasurementsList.begin();
+    for (auto newMeasIt = params.m_ueMeasurementsList.begin();
          newMeasIt != params.m_ueMeasurementsList.end();
          ++newMeasIt)
     {
@@ -943,8 +941,7 @@
     {
         if (triggering)
         {
-            std::map<uint8_t, LteRrcSap::MeasIdToAddMod>::iterator measIdIt;
-            for (measIdIt = m_varMeasConfig.measIdList.begin();
+            for (auto measIdIt = m_varMeasConfig.measIdList.begin();
                  measIdIt != m_varMeasConfig.measIdList.end();
                  ++measIdIt)
             {
@@ -1248,8 +1245,7 @@
     double maxRsrp = -std::numeric_limits<double>::infinity();
     double minRsrp = -140.0; // Minimum RSRP in dBm a UE can report
 
-    std::map<uint16_t, MeasValues>::iterator it;
-    for (it = m_storedMeasValues.begin(); it != m_storedMeasValues.end(); it++)
+    for (auto it = m_storedMeasValues.begin(); it != m_storedMeasValues.end(); it++)
     {
         /*
          * This block attempts to find a cell with strongest RSRP and has not
@@ -1257,8 +1253,7 @@
          */
         if (maxRsrp < it->second.rsrp && it->second.rsrp > minRsrp)
         {
-            std::set<uint16_t>::const_iterator itCell;
-            itCell = m_acceptableCell.find(it->first);
+            auto itCell = m_acceptableCell.find(it->first);
             if (itCell == m_acceptableCell.end())
             {
                 maxRsrpCellId = it->first;
@@ -1294,7 +1289,7 @@
 
     bool isSuitableCell = false;
     bool isAcceptableCell = false;
-    std::map<uint16_t, MeasValues>::iterator storedMeasIt = m_storedMeasValues.find(cellId);
+    auto storedMeasIt = m_storedMeasValues.find(cellId);
     double qRxLevMeas = storedMeasIt->second.rsrp;
     double qRxLevMin =
         EutranMeasurementMapping::IeValue2ActualQRxLevMin(m_lastSib1.cellSelectionInfo.qRxLevMin);
@@ -1437,7 +1432,7 @@
         m_cphySapProvider.at(0)->SetPa(paDouble);
     }
 
-    std::list<LteRrcSap::SrbToAddMod>::const_iterator stamIt = rrcd.srbToAddModList.begin();
+    auto stamIt = rrcd.srbToAddModList.begin();
     if (stamIt != rrcd.srbToAddModList.end())
     {
         if (!m_srb1)
@@ -1498,8 +1493,7 @@
         }
     }
 
-    std::list<LteRrcSap::DrbToAddMod>::const_iterator dtamIt;
-    for (dtamIt = rrcd.drbToAddModList.begin(); dtamIt != rrcd.drbToAddModList.end(); ++dtamIt)
+    for (auto dtamIt = rrcd.drbToAddModList.begin(); dtamIt != rrcd.drbToAddModList.end(); ++dtamIt)
     {
         NS_LOG_INFO(this << " IMSI " << m_imsi << " adding/modifying DRBID "
                          << (uint32_t)dtamIt->drbIdentity << " LC "
@@ -1507,8 +1501,7 @@
         NS_ASSERT_MSG(dtamIt->logicalChannelIdentity > 2,
                       "LCID value " << dtamIt->logicalChannelIdentity << " is reserved for SRBs");
 
-        std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator drbMapIt =
-            m_drbMap.find(dtamIt->drbIdentity);
+        auto drbMapIt = m_drbMap.find(dtamIt->drbIdentity);
         if (drbMapIt == m_drbMap.end())
         {
             NS_LOG_INFO("New Data Radio Bearer");
@@ -1585,8 +1578,7 @@
                                            rlc->GetLteMacSapUser());
 
             NS_LOG_DEBUG("Size of lcOnCcMapping vector " << lcOnCcMapping.size());
-            std::vector<LteUeCcmRrcSapProvider::LcsConfig>::iterator itLcOnCcMapping =
-                lcOnCcMapping.begin();
+            auto itLcOnCcMapping = lcOnCcMapping.begin();
             NS_ASSERT_MSG(itLcOnCcMapping != lcOnCcMapping.end(),
                           "Component carrier manager failed to add LC for data radio bearer");
 
@@ -1617,12 +1609,12 @@
         }
     }
 
-    std::list<uint8_t>::iterator dtdmIt;
-    for (dtdmIt = rrcd.drbToReleaseList.begin(); dtdmIt != rrcd.drbToReleaseList.end(); ++dtdmIt)
+    for (auto dtdmIt = rrcd.drbToReleaseList.begin(); dtdmIt != rrcd.drbToReleaseList.end();
+         ++dtdmIt)
     {
         uint8_t drbid = *dtdmIt;
         NS_LOG_INFO(this << " IMSI " << m_imsi << " releasing DRB " << (uint32_t)drbid);
-        std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.find(drbid);
+        auto it = m_drbMap.find(drbid);
         NS_ASSERT_MSG(it != m_drbMap.end(), "could not find bearer with given lcid");
         m_drbMap.erase(it);
         m_bid2DrbidMap.erase(drbid);
@@ -1642,15 +1634,12 @@
     // perform the actions specified in 3GPP TS 36.331 section 5.5.2.1
 
     // 3GPP TS 36.331 section 5.5.2.4 Measurement object removal
-    for (std::list<uint8_t>::iterator it = mc.measObjectToRemoveList.begin();
-         it != mc.measObjectToRemoveList.end();
-         ++it)
+    for (auto it = mc.measObjectToRemoveList.begin(); it != mc.measObjectToRemoveList.end(); ++it)
     {
         uint8_t measObjectId = *it;
         NS_LOG_LOGIC(this << " deleting measObjectId " << (uint32_t)measObjectId);
         m_varMeasConfig.measObjectList.erase(measObjectId);
-        std::map<uint8_t, LteRrcSap::MeasIdToAddMod>::iterator measIdIt =
-            m_varMeasConfig.measIdList.begin();
+        auto measIdIt = m_varMeasConfig.measIdList.begin();
         while (measIdIt != m_varMeasConfig.measIdList.end())
         {
             if (measIdIt->second.measObjectId == measObjectId)
@@ -1672,9 +1661,7 @@
     }
 
     // 3GPP TS 36.331 section 5.5.2.5  Measurement object addition/ modification
-    for (std::list<LteRrcSap::MeasObjectToAddMod>::iterator it = mc.measObjectToAddModList.begin();
-         it != mc.measObjectToAddModList.end();
-         ++it)
+    for (auto it = mc.measObjectToAddModList.begin(); it != mc.measObjectToAddModList.end(); ++it)
     {
         // simplifying assumptions
         NS_ASSERT_MSG(it->measObjectEutra.cellsToRemoveList.empty(),
@@ -1689,14 +1676,12 @@
                       "cellForWhichToReportCGI is not supported");
 
         uint8_t measObjectId = it->measObjectId;
-        std::map<uint8_t, LteRrcSap::MeasObjectToAddMod>::iterator measObjectIt =
-            m_varMeasConfig.measObjectList.find(measObjectId);
+        auto measObjectIt = m_varMeasConfig.measObjectList.find(measObjectId);
         if (measObjectIt != m_varMeasConfig.measObjectList.end())
         {
             NS_LOG_LOGIC("measObjectId " << (uint32_t)measObjectId << " exists, updating entry");
             measObjectIt->second = *it;
-            for (std::map<uint8_t, LteRrcSap::MeasIdToAddMod>::iterator measIdIt =
-                     m_varMeasConfig.measIdList.begin();
+            for (auto measIdIt = m_varMeasConfig.measIdList.begin();
                  measIdIt != m_varMeasConfig.measIdList.end();
                  ++measIdIt)
             {
@@ -1717,15 +1702,13 @@
     }
 
     // 3GPP TS 36.331 section 5.5.2.6 Reporting configuration removal
-    for (std::list<uint8_t>::iterator it = mc.reportConfigToRemoveList.begin();
-         it != mc.reportConfigToRemoveList.end();
+    for (auto it = mc.reportConfigToRemoveList.begin(); it != mc.reportConfigToRemoveList.end();
          ++it)
     {
         uint8_t reportConfigId = *it;
         NS_LOG_LOGIC(this << " deleting reportConfigId " << (uint32_t)reportConfigId);
         m_varMeasConfig.reportConfigList.erase(reportConfigId);
-        std::map<uint8_t, LteRrcSap::MeasIdToAddMod>::iterator measIdIt =
-            m_varMeasConfig.measIdList.begin();
+        auto measIdIt = m_varMeasConfig.measIdList.begin();
         while (measIdIt != m_varMeasConfig.measIdList.end())
         {
             if (measIdIt->second.reportConfigId == reportConfigId)
@@ -1747,9 +1730,7 @@
     }
 
     // 3GPP TS 36.331 section 5.5.2.7 Reporting configuration addition/ modification
-    for (std::list<LteRrcSap::ReportConfigToAddMod>::iterator it =
-             mc.reportConfigToAddModList.begin();
-         it != mc.reportConfigToAddModList.end();
+    for (auto it = mc.reportConfigToAddModList.begin(); it != mc.reportConfigToAddModList.end();
          ++it)
     {
         // simplifying assumptions
@@ -1757,15 +1738,13 @@
                       "only trigger type EVENT is supported");
 
         uint8_t reportConfigId = it->reportConfigId;
-        std::map<uint8_t, LteRrcSap::ReportConfigToAddMod>::iterator reportConfigIt =
-            m_varMeasConfig.reportConfigList.find(reportConfigId);
+        auto reportConfigIt = m_varMeasConfig.reportConfigList.find(reportConfigId);
         if (reportConfigIt != m_varMeasConfig.reportConfigList.end())
         {
             NS_LOG_LOGIC("reportConfigId " << (uint32_t)reportConfigId
                                            << " exists, updating entry");
             m_varMeasConfig.reportConfigList[reportConfigId] = *it;
-            for (std::map<uint8_t, LteRrcSap::MeasIdToAddMod>::iterator measIdIt =
-                     m_varMeasConfig.measIdList.begin();
+            for (auto measIdIt = m_varMeasConfig.measIdList.begin();
                  measIdIt != m_varMeasConfig.measIdList.end();
                  ++measIdIt)
             {
@@ -1805,8 +1784,7 @@
         NS_LOG_LOGIC(this << " new filter coefficients: aRsrp=" << m_varMeasConfig.aRsrp
                           << ", aRsrq=" << m_varMeasConfig.aRsrq);
 
-        for (std::map<uint8_t, LteRrcSap::MeasIdToAddMod>::iterator measIdIt =
-                 m_varMeasConfig.measIdList.begin();
+        for (auto measIdIt = m_varMeasConfig.measIdList.begin();
              measIdIt != m_varMeasConfig.measIdList.end();
              ++measIdIt)
         {
@@ -1815,9 +1793,7 @@
     }
 
     // 3GPP TS 36.331 section 5.5.2.2 Measurement identity removal
-    for (std::list<uint8_t>::iterator it = mc.measIdToRemoveList.begin();
-         it != mc.measIdToRemoveList.end();
-         ++it)
+    for (auto it = mc.measIdToRemoveList.begin(); it != mc.measIdToRemoveList.end(); ++it)
     {
         uint8_t measId = *it;
         NS_LOG_LOGIC(this << " deleting measId " << (uint32_t)measId);
@@ -1830,9 +1806,7 @@
     }
 
     // 3GPP TS 36.331 section 5.5.2.3 Measurement identity addition/ modification
-    for (std::list<LteRrcSap::MeasIdToAddMod>::iterator it = mc.measIdToAddModList.begin();
-         it != mc.measIdToAddModList.end();
-         ++it)
+    for (auto it = mc.measIdToAddModList.begin(); it != mc.measIdToAddModList.end(); ++it)
     {
         NS_LOG_LOGIC(this << " measId " << (uint32_t)it->measId
                           << " (measObjectId=" << (uint32_t)it->measObjectId
@@ -1842,8 +1816,7 @@
         NS_ASSERT(m_varMeasConfig.reportConfigList.find(it->reportConfigId) !=
                   m_varMeasConfig.reportConfigList.end());
         m_varMeasConfig.measIdList[it->measId] = *it; // side effect: create new entry if not exists
-        std::map<uint8_t, VarMeasReport>::iterator measReportIt =
-            m_varMeasReportList.find(it->measId);
+        auto measReportIt = m_varMeasReportList.find(it->measId);
         if (measReportIt != m_varMeasReportList.end())
         {
             measReportIt->second.periodicReportTimer.Cancel();
@@ -1884,7 +1857,7 @@
 {
     NS_LOG_FUNCTION(this << cellId << +componentCarrierId << rsrp << rsrq << useLayer3Filtering);
 
-    std::map<uint16_t, MeasValues>::iterator storedMeasIt = m_storedMeasValues.find(cellId);
+    auto storedMeasIt = m_storedMeasValues.find(cellId);
 
     if (storedMeasIt != m_storedMeasValues.end())
     {
@@ -1921,8 +1894,7 @@
         v.carrierFreq = m_cphySapProvider.at(componentCarrierId)->GetDlEarfcn();
 
         std::pair<uint16_t, MeasValues> val(cellId, v);
-        std::pair<std::map<uint16_t, MeasValues>::iterator, bool> ret =
-            m_storedMeasValues.insert(val);
+        auto ret = m_storedMeasValues.insert(val);
         NS_ASSERT_MSG(ret.second == true, "element already existed");
         storedMeasIt = ret.first;
     }
@@ -1939,22 +1911,19 @@
 {
     NS_LOG_FUNCTION(this << (uint16_t)measId);
 
-    std::map<uint8_t, LteRrcSap::MeasIdToAddMod>::iterator measIdIt =
-        m_varMeasConfig.measIdList.find(measId);
+    auto measIdIt = m_varMeasConfig.measIdList.find(measId);
     NS_ASSERT(measIdIt != m_varMeasConfig.measIdList.end());
     NS_ASSERT(measIdIt->first == measIdIt->second.measId);
 
-    std::map<uint8_t, LteRrcSap::ReportConfigToAddMod>::iterator reportConfigIt =
-        m_varMeasConfig.reportConfigList.find(measIdIt->second.reportConfigId);
+    auto reportConfigIt = m_varMeasConfig.reportConfigList.find(measIdIt->second.reportConfigId);
     NS_ASSERT(reportConfigIt != m_varMeasConfig.reportConfigList.end());
     LteRrcSap::ReportConfigEutra& reportConfigEutra = reportConfigIt->second.reportConfigEutra;
 
-    std::map<uint8_t, LteRrcSap::MeasObjectToAddMod>::iterator measObjectIt =
-        m_varMeasConfig.measObjectList.find(measIdIt->second.measObjectId);
+    auto measObjectIt = m_varMeasConfig.measObjectList.find(measIdIt->second.measObjectId);
     NS_ASSERT(measObjectIt != m_varMeasConfig.measObjectList.end());
     LteRrcSap::MeasObjectEutra& measObjectEutra = measObjectIt->second.measObjectEutra;
 
-    std::map<uint8_t, VarMeasReport>::iterator measReportIt = m_varMeasReportList.find(measId);
+    auto measReportIt = m_varMeasReportList.find(measId);
     bool isMeasIdInReportList = (measReportIt != m_varMeasReportList.end());
 
     // we don't check the purpose field, as it is only included for
@@ -2202,7 +2171,7 @@
             break;
         }
 
-        for (std::map<uint16_t, MeasValues>::iterator storedMeasIt = m_storedMeasValues.begin();
+        for (auto storedMeasIt = m_storedMeasValues.begin();
              storedMeasIt != m_storedMeasValues.end();
              ++storedMeasIt)
         {
@@ -2310,7 +2279,7 @@
             break;
         }
 
-        for (std::map<uint16_t, MeasValues>::iterator storedMeasIt = m_storedMeasValues.begin();
+        for (auto storedMeasIt = m_storedMeasValues.begin();
              storedMeasIt != m_storedMeasValues.end();
              ++storedMeasIt)
         {
@@ -2427,7 +2396,7 @@
 
         if (entryCond)
         {
-            for (std::map<uint16_t, MeasValues>::iterator storedMeasIt = m_storedMeasValues.begin();
+            for (auto storedMeasIt = m_storedMeasValues.begin();
                  storedMeasIt != m_storedMeasValues.end();
                  ++storedMeasIt)
             {
@@ -2500,8 +2469,7 @@
                 {
                     // leaving condition #2 does not have to be checked
 
-                    for (std::map<uint16_t, MeasValues>::iterator storedMeasIt =
-                             m_storedMeasValues.begin();
+                    for (auto storedMeasIt = m_storedMeasValues.begin();
                          storedMeasIt != m_storedMeasValues.end();
                          ++storedMeasIt)
                     {
@@ -2523,8 +2491,7 @@
                 {
                     // leaving condition #2 has to be checked to cancel time-to-trigger
 
-                    for (std::map<uint16_t, MeasValues>::iterator storedMeasIt =
-                             m_storedMeasValues.begin();
+                    for (auto storedMeasIt = m_storedMeasValues.begin();
                          storedMeasIt != m_storedMeasValues.end();
                          ++storedMeasIt)
                     {
@@ -2592,8 +2559,7 @@
 
                 // check leaving condition #2
 
-                for (std::map<uint16_t, MeasValues>::iterator storedMeasIt =
-                         m_storedMeasValues.begin();
+                for (auto storedMeasIt = m_storedMeasValues.begin();
                      storedMeasIt != m_storedMeasValues.end();
                      ++storedMeasIt)
                 {
@@ -2670,8 +2636,7 @@
                                           this,
                                           measId,
                                           concernedCellsEntry);
-            std::map<uint8_t, std::list<PendingTrigger_t>>::iterator enteringTriggerIt =
-                m_enteringTriggerQueue.find(measId);
+            auto enteringTriggerIt = m_enteringTriggerQueue.find(measId);
             NS_ASSERT(enteringTriggerIt != m_enteringTriggerQueue.end());
             enteringTriggerIt->second.push_back(t);
         }
@@ -2699,8 +2664,7 @@
                                           measId,
                                           concernedCellsLeaving,
                                           reportOnLeave);
-            std::map<uint8_t, std::list<PendingTrigger_t>>::iterator leavingTriggerIt =
-                m_leavingTriggerQueue.find(measId);
+            auto leavingTriggerIt = m_leavingTriggerQueue.find(measId);
             NS_ASSERT(leavingTriggerIt != m_leavingTriggerQueue.end());
             leavingTriggerIt->second.push_back(t);
         }
@@ -2713,14 +2677,12 @@
 {
     NS_LOG_FUNCTION(this << (uint16_t)measId);
 
-    std::map<uint8_t, std::list<PendingTrigger_t>>::iterator it1 =
-        m_enteringTriggerQueue.find(measId);
+    auto it1 = m_enteringTriggerQueue.find(measId);
     NS_ASSERT(it1 != m_enteringTriggerQueue.end());
 
     if (!it1->second.empty())
     {
-        std::list<PendingTrigger_t>::iterator it2;
-        for (it2 = it1->second.begin(); it2 != it1->second.end(); ++it2)
+        for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2)
         {
             NS_ASSERT(it2->measId == measId);
             NS_LOG_LOGIC(this << " canceling entering time-to-trigger event at "
@@ -2737,17 +2699,15 @@
 {
     NS_LOG_FUNCTION(this << (uint16_t)measId << cellId);
 
-    std::map<uint8_t, std::list<PendingTrigger_t>>::iterator it1 =
-        m_enteringTriggerQueue.find(measId);
+    auto it1 = m_enteringTriggerQueue.find(measId);
     NS_ASSERT(it1 != m_enteringTriggerQueue.end());
 
-    std::list<PendingTrigger_t>::iterator it2 = it1->second.begin();
+    auto it2 = it1->second.begin();
     while (it2 != it1->second.end())
     {
         NS_ASSERT(it2->measId == measId);
 
-        ConcernedCells_t::iterator it3;
-        for (it3 = it2->concernedCells.begin(); it3 != it2->concernedCells.end(); ++it3)
+        for (auto it3 = it2->concernedCells.begin(); it3 != it2->concernedCells.end(); ++it3)
         {
             if (*it3 == cellId)
             {
@@ -2774,14 +2734,12 @@
 {
     NS_LOG_FUNCTION(this << (uint16_t)measId);
 
-    std::map<uint8_t, std::list<PendingTrigger_t>>::iterator it1 =
-        m_leavingTriggerQueue.find(measId);
+    auto it1 = m_leavingTriggerQueue.find(measId);
     NS_ASSERT(it1 != m_leavingTriggerQueue.end());
 
     if (!it1->second.empty())
     {
-        std::list<PendingTrigger_t>::iterator it2;
-        for (it2 = it1->second.begin(); it2 != it1->second.end(); ++it2)
+        for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2)
         {
             NS_ASSERT(it2->measId == measId);
             NS_LOG_LOGIC(this << " canceling leaving time-to-trigger event at "
@@ -2798,17 +2756,15 @@
 {
     NS_LOG_FUNCTION(this << (uint16_t)measId << cellId);
 
-    std::map<uint8_t, std::list<PendingTrigger_t>>::iterator it1 =
-        m_leavingTriggerQueue.find(measId);
+    auto it1 = m_leavingTriggerQueue.find(measId);
     NS_ASSERT(it1 != m_leavingTriggerQueue.end());
 
-    std::list<PendingTrigger_t>::iterator it2 = it1->second.begin();
+    auto it2 = it1->second.begin();
     while (it2 != it1->second.end())
     {
         NS_ASSERT(it2->measId == measId);
 
-        ConcernedCells_t::iterator it3;
-        for (it3 = it2->concernedCells.begin(); it3 != it2->concernedCells.end(); ++it3)
+        for (auto it3 = it2->concernedCells.begin(); it3 != it2->concernedCells.end(); ++it3)
         {
             if (*it3 == cellId)
             {
@@ -2836,23 +2792,21 @@
     NS_LOG_FUNCTION(this << (uint16_t)measId);
     NS_ASSERT(!enteringCells.empty());
 
-    std::map<uint8_t, VarMeasReport>::iterator measReportIt = m_varMeasReportList.find(measId);
+    auto measReportIt = m_varMeasReportList.find(measId);
 
     if (measReportIt == m_varMeasReportList.end())
     {
         VarMeasReport r;
         r.measId = measId;
         std::pair<uint8_t, VarMeasReport> val(measId, r);
-        std::pair<std::map<uint8_t, VarMeasReport>::iterator, bool> ret =
-            m_varMeasReportList.insert(val);
+        auto ret = m_varMeasReportList.insert(val);
         NS_ASSERT_MSG(ret.second == true, "element already existed");
         measReportIt = ret.first;
     }
 
     NS_ASSERT(measReportIt != m_varMeasReportList.end());
 
-    for (ConcernedCells_t::const_iterator it = enteringCells.begin(); it != enteringCells.end();
-         ++it)
+    for (auto it = enteringCells.begin(); it != enteringCells.end(); ++it)
     {
         measReportIt->second.cellsTriggeredList.insert(*it);
     }
@@ -2870,8 +2824,7 @@
                                 measId);
     }
 
-    std::map<uint8_t, std::list<PendingTrigger_t>>::iterator enteringTriggerIt =
-        m_enteringTriggerQueue.find(measId);
+    auto enteringTriggerIt = m_enteringTriggerQueue.find(measId);
     NS_ASSERT(enteringTriggerIt != m_enteringTriggerQueue.end());
     if (!enteringTriggerIt->second.empty())
     {
@@ -2890,9 +2843,7 @@
              * we clean up the time-to-trigger queue. This case might occur when
              * time-to-trigger > 200 ms.
              */
-            for (ConcernedCells_t::const_iterator it = enteringCells.begin();
-                 it != enteringCells.end();
-                 ++it)
+            for (auto it = enteringCells.begin(); it != enteringCells.end(); ++it)
             {
                 CancelEnteringTrigger(measId, *it);
             }
@@ -2908,10 +2859,10 @@
     NS_LOG_FUNCTION(this << (uint16_t)measId);
     NS_ASSERT(!leavingCells.empty());
 
-    std::map<uint8_t, VarMeasReport>::iterator measReportIt = m_varMeasReportList.find(measId);
+    auto measReportIt = m_varMeasReportList.find(measId);
     NS_ASSERT(measReportIt != m_varMeasReportList.end());
 
-    for (ConcernedCells_t::const_iterator it = leavingCells.begin(); it != leavingCells.end(); ++it)
+    for (auto it = leavingCells.begin(); it != leavingCells.end(); ++it)
     {
         measReportIt->second.cellsTriggeredList.erase(*it);
     }
@@ -2928,8 +2879,7 @@
         m_varMeasReportList.erase(measReportIt);
     }
 
-    std::map<uint8_t, std::list<PendingTrigger_t>>::iterator leavingTriggerIt =
-        m_leavingTriggerQueue.find(measId);
+    auto leavingTriggerIt = m_leavingTriggerQueue.find(measId);
     NS_ASSERT(leavingTriggerIt != m_leavingTriggerQueue.end());
     if (!leavingTriggerIt->second.empty())
     {
@@ -2948,9 +2898,7 @@
              * we clean up the time-to-trigger queue. This case might occur when
              * time-to-trigger > 200 ms.
              */
-            for (ConcernedCells_t::const_iterator it = leavingCells.begin();
-                 it != leavingCells.end();
-                 ++it)
+            for (auto it = leavingCells.begin(); it != leavingCells.end(); ++it)
             {
                 CancelLeavingTrigger(measId, *it);
             }
@@ -2966,7 +2914,7 @@
     NS_LOG_FUNCTION(this << (uint16_t)measId);
 
     // remove the measurement reporting entry for this measId from the VarMeasReportList
-    std::map<uint8_t, VarMeasReport>::iterator measReportIt = m_varMeasReportList.find(measId);
+    auto measReportIt = m_varMeasReportList.find(measId);
     if (measReportIt != m_varMeasReportList.end())
     {
         NS_LOG_LOGIC(this << " deleting existing report for measId " << (uint16_t)measId);
@@ -2984,12 +2932,10 @@
     NS_LOG_FUNCTION(this << (uint16_t)measId);
     //  3GPP TS 36.331 section 5.5.5 Measurement reporting
 
-    std::map<uint8_t, LteRrcSap::MeasIdToAddMod>::iterator measIdIt =
-        m_varMeasConfig.measIdList.find(measId);
+    auto measIdIt = m_varMeasConfig.measIdList.find(measId);
     NS_ASSERT(measIdIt != m_varMeasConfig.measIdList.end());
 
-    std::map<uint8_t, LteRrcSap::ReportConfigToAddMod>::iterator reportConfigIt =
-        m_varMeasConfig.reportConfigList.find(measIdIt->second.reportConfigId);
+    auto reportConfigIt = m_varMeasConfig.reportConfigList.find(measIdIt->second.reportConfigId);
     NS_ASSERT(reportConfigIt != m_varMeasConfig.reportConfigList.end());
     LteRrcSap::ReportConfigEutra& reportConfigEutra = reportConfigIt->second.reportConfigEutra;
 
@@ -2997,14 +2943,14 @@
     LteRrcSap::MeasResults& measResults = measurementReport.measResults;
     measResults.measId = measId;
 
-    std::map<uint8_t, VarMeasReport>::iterator measReportIt = m_varMeasReportList.find(measId);
+    auto measReportIt = m_varMeasReportList.find(measId);
     if (measReportIt == m_varMeasReportList.end())
     {
         NS_LOG_ERROR("no entry found in m_varMeasReportList for measId " << (uint32_t)measId);
     }
     else
     {
-        std::map<uint16_t, MeasValues>::iterator servingMeasIt = m_storedMeasValues.find(m_cellId);
+        auto servingMeasIt = m_storedMeasValues.find(m_cellId);
         NS_ASSERT(servingMeasIt != m_storedMeasValues.end());
         measResults.measResultPCell.rsrpResult =
             EutranMeasurementMapping::Dbm2RsrpRange(servingMeasIt->second.rsrp);
@@ -3045,16 +2991,14 @@
         if (!(measReportIt->second.cellsTriggeredList.empty()))
         {
             std::multimap<double, uint16_t> sortedNeighCells;
-            for (std::set<uint16_t>::iterator cellsTriggeredIt =
-                     measReportIt->second.cellsTriggeredList.begin();
+            for (auto cellsTriggeredIt = measReportIt->second.cellsTriggeredList.begin();
                  cellsTriggeredIt != measReportIt->second.cellsTriggeredList.end();
                  ++cellsTriggeredIt)
             {
                 uint16_t cellId = *cellsTriggeredIt;
                 if (cellId != m_cellId)
                 {
-                    std::map<uint16_t, MeasValues>::iterator neighborMeasIt =
-                        m_storedMeasValues.find(cellId);
+                    auto neighborMeasIt = m_storedMeasValues.find(cellId);
                     double triggerValue;
                     switch (reportConfigEutra.triggerQuantity)
                     {
@@ -3080,8 +3024,7 @@
                  ++sortedNeighCellsIt, ++count)
             {
                 uint16_t cellId = sortedNeighCellsIt->second;
-                std::map<uint16_t, MeasValues>::iterator neighborMeasIt =
-                    m_storedMeasValues.find(cellId);
+                auto neighborMeasIt = m_storedMeasValues.find(cellId);
                 NS_ASSERT(neighborMeasIt != m_storedMeasValues.end());
                 LteRrcSap::MeasResultEutra measResultEutra;
                 measResultEutra.physCellId = cellId;
@@ -3191,8 +3134,7 @@
     m_storedMeasValues.clear();
     ResetRlfParams();
 
-    std::map<uint8_t, LteRrcSap::MeasIdToAddMod>::iterator measIdIt;
-    for (measIdIt = m_varMeasConfig.measIdList.begin();
+    for (auto measIdIt = m_varMeasConfig.measIdList.begin();
          measIdIt != m_varMeasConfig.measIdList.end();
          ++measIdIt)
     {
@@ -3268,7 +3210,7 @@
 uint8_t
 LteUeRrc::Bid2Drbid(uint8_t bid)
 {
-    std::map<uint8_t, uint8_t>::iterator it = m_bid2DrbidMap.find(bid);
+    auto it = m_bid2DrbidMap.find(bid);
     // NS_ASSERT_MSG (it != m_bid2DrbidMap.end (), "could not find BID " << bid);
     if (it == m_bid2DrbidMap.end())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/no-op-component-carrier-manager.cc ns-3.40/src/lte/model/no-op-component-carrier-manager.cc
--- ns-3.39/src/lte/model/no-op-component-carrier-manager.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/no-op-component-carrier-manager.cc	2023-09-27 13:30:37.826839700 -0700
@@ -81,8 +81,7 @@
 NoOpComponentCarrierManager::DoTransmitPdu(LteMacSapProvider::TransmitPduParameters params)
 {
     NS_LOG_FUNCTION(this);
-    std::map<uint8_t, LteMacSapProvider*>::iterator it =
-        m_macSapProvidersMap.find(params.componentCarrierId);
+    auto it = m_macSapProvidersMap.find(params.componentCarrierId);
     NS_ASSERT_MSG(it != m_macSapProvidersMap.end(),
                   "could not find Sap for ComponentCarrier " << params.componentCarrierId);
     // with this algorithm all traffic is on Primary Carrier
@@ -95,8 +94,7 @@
 {
     NS_LOG_FUNCTION(this);
     auto ueManager = m_ccmRrcSapUser->GetUeManager(params.rnti);
-    std::map<uint8_t, LteMacSapProvider*>::iterator it =
-        m_macSapProvidersMap.find(ueManager->GetComponentCarrierId());
+    auto it = m_macSapProvidersMap.find(ueManager->GetComponentCarrierId());
     NS_ASSERT_MSG(it != m_macSapProvidersMap.end(), "could not find Sap for ComponentCarrier ");
     it->second->ReportBufferStatus(params);
 }
@@ -138,7 +136,6 @@
 NoOpComponentCarrierManager::DoAddUe(uint16_t rnti, uint8_t state)
 {
     NS_LOG_FUNCTION(this << rnti << (uint16_t)state);
-    std::map<uint16_t, uint8_t>::iterator eccIt; // m_enabledComponentCarrier iterator
     auto ueInfoIt = m_ueInfo.find(rnti);
     if (ueInfoIt == m_ueInfo.end())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/pf-ff-mac-scheduler.cc ns-3.40/src/lte/model/pf-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/pf-ff-mac-scheduler.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/pf-ff-mac-scheduler.cc	2023-09-27 13:30:37.826839700 -0700
@@ -161,7 +161,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, double>(params.m_rnti, params.m_transmissionMode));
@@ -207,10 +207,9 @@
 {
     NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
 
-    std::map<uint16_t, pfsFlowPerf_t>::iterator it;
     for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
     {
-        it = m_flowStatsDl.find(params.m_rnti);
+        auto it = m_flowStatsDl.find(params.m_rnti);
 
         if (it == m_flowStatsDl.end())
         {
@@ -237,15 +236,13 @@
     NS_LOG_FUNCTION(this);
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).first.m_rnti == params.m_rnti) &&
                 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
             {
-                temp = it;
+                auto temp = it;
                 it++;
                 m_rlcBufferReq.erase(temp);
             }
@@ -275,14 +272,12 @@
     m_flowStatsDl.erase(params.m_rnti);
     m_flowStatsUl.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).first.m_rnti == params.m_rnti)
         {
-            temp = it;
+            auto temp = it;
             it++;
             m_rlcBufferReq.erase(temp);
         }
@@ -304,11 +299,9 @@
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
 
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-
     LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
 
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
 
     if (it == m_rlcBufferReq.end())
     {
@@ -355,9 +348,8 @@
 unsigned int
 PfFfMacScheduler::LcActivePerFlow(uint16_t rnti)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     unsigned int lcActive = 0;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
                                              ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
@@ -378,13 +370,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -408,13 +399,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -443,8 +433,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -454,8 +443,7 @@
                 // reset HARQ process
 
                 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -495,7 +483,7 @@
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
 
     rbgMap = m_ffrSapProvider->GetAvailableDlRbg();
-    for (std::vector<bool>::iterator it = rbgMap.begin(); it != rbgMap.end(); it++)
+    for (auto it = rbgMap.begin(); it != rbgMap.end(); it++)
     {
         if (*it)
         {
@@ -505,9 +493,9 @@
 
     FfMacSchedSapUser::SchedDlConfigIndParameters ret;
 
-    //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    // update UL HARQ proc id
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -523,7 +511,7 @@
     uint16_t tmpFfrRbStartOffset = 0;
     uint16_t index = 0;
 
-    for (std::vector<bool>::iterator it = ulRbMap.begin(); it != ulRbMap.end(); it++)
+    for (auto it = ulRbMap.begin(); it != ulRbMap.end(); it++)
     {
         if (*it)
         {
@@ -554,8 +542,7 @@
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
     rbStart = ffrRbStartOffset;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -619,15 +606,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -669,7 +654,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -697,8 +682,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -719,16 +703,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -815,8 +797,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -893,8 +874,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -907,15 +887,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -946,17 +925,16 @@
         NS_LOG_INFO(this << " ALLOCATION for RBG " << i << " of " << rbgNum);
         if (!rbgMap.at(i))
         {
-            std::map<uint16_t, pfsFlowPerf_t>::iterator it;
-            std::map<uint16_t, pfsFlowPerf_t>::iterator itMax = m_flowStatsDl.end();
+            auto itMax = m_flowStatsDl.end();
             double rcqiMax = 0.0;
-            for (it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
+            for (auto it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
             {
                 if (!m_ffrSapProvider->IsDlRbgAvailableForUe(i, (*it).first))
                 {
                     continue;
                 }
 
-                std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+                auto itRnti = rntiAllocated.find((*it).first);
                 if (itRnti != rntiAllocated.end() || !HarqProcessAvailability((*it).first))
                 {
                     // UE already allocated for HARQ or without HARQ process available -> drop it
@@ -972,10 +950,8 @@
                     }
                     continue;
                 }
-                std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-                itCqi = m_a30CqiRxed.find((*it).first);
-                std::map<uint16_t, uint8_t>::iterator itTxMode;
-                itTxMode = m_uesTxMode.find((*it).first);
+                auto itCqi = m_a30CqiRxed.find((*it).first);
+                auto itTxMode = m_uesTxMode.find((*it).first);
                 if (itTxMode == m_uesTxMode.end())
                 {
                     NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
@@ -984,10 +960,7 @@
                 std::vector<uint8_t> sbCqi;
                 if (itCqi == m_a30CqiRxed.end())
                 {
-                    for (uint8_t k = 0; k < nLayer; k++)
-                    {
-                        sbCqi.push_back(1); // start with lowest value
-                    }
+                    sbCqi = std::vector<uint8_t>(nLayer, 1); // start with lowest value
                 }
                 else
                 {
@@ -1046,8 +1019,7 @@
             else
             {
                 rbgMap.at(i) = true;
-                std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-                itMap = allocationMap.find((*itMax).first);
+                auto itMap = allocationMap.find((*itMax).first);
                 if (itMap == allocationMap.end())
                 {
                     // insert new element
@@ -1066,15 +1038,14 @@
     }     // end for RBGs
 
     // reset TTI stats of users
-    std::map<uint16_t, pfsFlowPerf_t>::iterator itStats;
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         (*itStats).second.lastTtiBytesTrasmitted = 0;
     }
 
     // generate the transmission opportunities by grouping the RBGs of the same RNTI and
     // creating the correspondent DCIs
-    std::map<uint16_t, std::vector<uint16_t>>::iterator itMap = allocationMap.begin();
+    auto itMap = allocationMap.begin();
     while (itMap != allocationMap.end())
     {
         // create new BuildDataListElement_s for this LC
@@ -1093,10 +1064,8 @@
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
         uint16_t RgbPerRnti = (*itMap).second.size();
-        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-        itCqi = m_a30CqiRxed.find((*itMap).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itMap).first);
+        auto itCqi = m_a30CqiRxed.find((*itMap).first);
+        auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
@@ -1181,9 +1150,7 @@
         newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
 
         // create the rlc PDUs -> equally divide resources among actives LCs
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itBufReq;
-        for (itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
+        for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
         {
             if (((*itBufReq).first.m_rnti == (*itMap).first) &&
                 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
@@ -1205,8 +1172,7 @@
                     if (m_harqOn)
                     {
                         // store RLC PDU list for HARQ
-                        std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                            m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
+                        auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
                         if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                         {
                             NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1235,8 +1201,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1244,8 +1209,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1257,8 +1221,7 @@
 
         ret.m_buildDataList.push_back(newEl);
         // update UE stats
-        std::map<uint16_t, pfsFlowPerf_t>::iterator it;
-        it = m_flowStatsDl.find((*itMap).first);
+        auto it = m_flowStatsDl.find((*itMap).first);
         if (it != m_flowStatsDl.end())
         {
             (*it).second.lastTtiBytesTrasmitted = bytesTxed;
@@ -1275,7 +1238,7 @@
 
     // update UEs stats
     NS_LOG_INFO(this << " Update UEs statistics");
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
         // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
@@ -1313,9 +1276,8 @@
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1330,17 +1292,15 @@
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
         else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
         {
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_a30CqiRxed.find(rnti);
+            auto it = m_a30CqiRxed.find(rnti);
             if (it == m_a30CqiRxed.end())
             {
                 // create the new entry
@@ -1353,8 +1313,7 @@
             {
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_a30CqiTimers.find(rnti);
+                auto itTimers = m_a30CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1368,7 +1327,7 @@
 double
 PfFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find(rnti);
+    auto itCqi = m_ueCqi.find(rnti);
     if (itCqi == m_ueCqi.end())
     {
         // no cqi info about this UE
@@ -1420,7 +1379,7 @@
     rbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
     rbMap = m_ffrSapProvider->GetAvailableUlRbg();
 
-    for (std::vector<bool>::iterator it = rbMap.begin(); it != rbMap.end(); it++)
+    for (auto it = rbMap.begin(); it != rbMap.end(); it++)
     {
         if (*it)
         {
@@ -1451,8 +1410,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1460,16 +1418,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
                                  << " i " << i << " size " << params.m_ulInfoList.size());
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                     continue;
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1528,7 +1484,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
         {
@@ -1562,7 +1518,6 @@
 
     int rbAllocated = 0;
 
-    std::map<uint16_t, pfsFlowPerf_t>::iterator itStats;
     if (m_nextRntiUl != 0)
     {
         for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
@@ -1584,7 +1539,7 @@
     }
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -1676,7 +1631,7 @@
             break;
         }
 
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -1747,15 +1702,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -1763,8 +1716,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -1780,7 +1732,7 @@
                          << (uint16_t)harqId);
 
         // update TTI  UE stats
-        itStats = m_flowStatsUl.find((*it).first);
+        auto itStats = m_flowStatsUl.find((*it).first);
         if (itStats != m_flowStatsUl.end())
         {
             (*itStats).second.lastTtiBytesTrasmitted = uldci.m_tbSize;
@@ -1806,7 +1758,7 @@
 
     // Update global UE stats
     // update UEs stats
-    for (itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
+    for (auto itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
     {
         (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
         // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
@@ -1843,8 +1795,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -1865,7 +1815,7 @@
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
             NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -1914,11 +1864,9 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
         NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
                           << " subframe no. " << (0xF & params.m_sfnSf));
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             return;
@@ -1927,7 +1875,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -1957,8 +1905,7 @@
                 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
                                   << sinr);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1981,8 +1928,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -2009,8 +1955,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -2030,7 +1975,7 @@
 PfFfMacScheduler::RefreshDlCqiMaps()
 {
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -2038,12 +1983,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -2055,7 +2000,7 @@
     }
 
     // refresh DL CQI A30 Map
-    std::map<uint16_t, uint32_t>::iterator itA30 = m_a30CqiTimers.begin();
+    auto itA30 = m_a30CqiTimers.begin();
     while (itA30 != m_a30CqiTimers.end())
     {
         NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
@@ -2063,12 +2008,12 @@
         if ((*itA30).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find((*itA30).first);
+            auto itMap = m_a30CqiRxed.find((*itA30).first);
             NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
                           " Does not find CQI report for user " << (*itA30).first);
             NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
             m_a30CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itA30;
+            auto temp = itA30;
             itA30++;
             m_a30CqiTimers.erase(temp);
         }
@@ -2084,7 +2029,7 @@
 PfFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -2092,13 +2037,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -2113,9 +2058,8 @@
 void
 PfFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     LteFlowId_t flow(rnti, lcid);
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
     if (it != m_rlcBufferReq.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
@@ -2170,7 +2114,7 @@
 PfFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/pss-ff-mac-scheduler.cc ns-3.40/src/lte/model/pss-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/pss-ff-mac-scheduler.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/pss-ff-mac-scheduler.cc	2023-09-27 13:30:37.826839700 -0700
@@ -174,7 +174,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, double>(params.m_rnti, params.m_transmissionMode));
@@ -220,10 +220,9 @@
 {
     NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
 
-    std::map<uint16_t, pssFlowPerf_t>::iterator it;
     for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
     {
-        it = m_flowStatsDl.find(params.m_rnti);
+        auto it = m_flowStatsDl.find(params.m_rnti);
 
         if (it == m_flowStatsDl.end())
         {
@@ -269,15 +268,13 @@
     NS_LOG_FUNCTION(this);
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).first.m_rnti == params.m_rnti) &&
                 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
             {
-                temp = it;
+                auto temp = it;
                 it++;
                 m_rlcBufferReq.erase(temp);
             }
@@ -307,14 +304,12 @@
     m_flowStatsDl.erase(params.m_rnti);
     m_flowStatsUl.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).first.m_rnti == params.m_rnti)
         {
-            temp = it;
+            auto temp = it;
             it++;
             m_rlcBufferReq.erase(temp);
         }
@@ -336,11 +331,9 @@
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
 
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-
     LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
 
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
 
     if (it == m_rlcBufferReq.end())
     {
@@ -387,9 +380,8 @@
 unsigned int
 PssFfMacScheduler::LcActivePerFlow(uint16_t rnti)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     unsigned int lcActive = 0;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
                                              ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
@@ -410,13 +402,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -440,13 +431,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -475,8 +465,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -486,8 +475,7 @@
                 // reset HARQ process
 
                 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -527,7 +515,7 @@
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
 
     rbgMap = m_ffrSapProvider->GetAvailableDlRbg();
-    for (std::vector<bool>::iterator it = rbgMap.begin(); it != rbgMap.end(); it++)
+    for (auto it = rbgMap.begin(); it != rbgMap.end(); it++)
     {
         if (*it)
         {
@@ -537,9 +525,9 @@
 
     FfMacSchedSapUser::SchedDlConfigIndParameters ret;
 
-    //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    // update UL HARQ proc id
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -555,7 +543,7 @@
     uint16_t tmpFfrRbStartOffset = 0;
     uint16_t index = 0;
 
-    for (std::vector<bool>::iterator it = ulRbMap.begin(); it != ulRbMap.end(); it++)
+    for (auto it = ulRbMap.begin(); it != ulRbMap.end(); it++)
     {
         if (*it)
         {
@@ -586,8 +574,7 @@
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
     rbStart = ffrRbStartOffset;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -651,15 +638,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -701,7 +686,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -729,8 +714,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -751,16 +735,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -847,8 +829,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -925,8 +906,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -939,15 +919,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -973,12 +952,11 @@
         return;
     }
 
-    std::map<uint16_t, pssFlowPerf_t>::iterator it;
     std::map<uint16_t, pssFlowPerf_t> tdUeSet; // the result of TD scheduler
 
     // schedulability check
     std::map<uint16_t, pssFlowPerf_t> ueSet;
-    for (it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
+    for (auto it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
     {
         if (LcActivePerFlow((*it).first) > 0)
         {
@@ -992,9 +970,9 @@
         // Time Domain scheduler
         std::vector<std::pair<double, uint16_t>> ueSet1;
         std::vector<std::pair<double, uint16_t>> ueSet2;
-        for (it = ueSet.begin(); it != ueSet.end(); it++)
+        for (auto it = ueSet.begin(); it != ueSet.end(); it++)
         {
-            std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+            auto itRnti = rntiAllocated.find((*it).first);
             if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*it).first)))
             {
                 // UE already allocated for HARQ or without HARQ process available -> drop it
@@ -1016,10 +994,8 @@
                 metric = 1 / (*it).second.lastAveragedThroughput;
 
                 // check first what are channel conditions for this UE, if CQI!=0
-                std::map<uint16_t, uint8_t>::iterator itCqi;
-                itCqi = m_p10CqiRxed.find((*it).first);
-                std::map<uint16_t, uint8_t>::iterator itTxMode;
-                itTxMode = m_uesTxMode.find((*it).first);
+                auto itCqi = m_p10CqiRxed.find((*it).first);
+                auto itTxMode = m_uesTxMode.find((*it).first);
                 if (itTxMode == m_uesTxMode.end())
                 {
                     NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
@@ -1046,10 +1022,8 @@
             else
             {
                 // calculate TD PF metric
-                std::map<uint16_t, uint8_t>::iterator itCqi;
-                itCqi = m_p10CqiRxed.find((*it).first);
-                std::map<uint16_t, uint8_t>::iterator itTxMode;
-                itTxMode = m_uesTxMode.find((*it).first);
+                auto itCqi = m_p10CqiRxed.find((*it).first);
+                auto itTxMode = m_uesTxMode.find((*it).first);
                 if (itTxMode == m_uesTxMode.end())
                 {
                     NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
@@ -1112,19 +1086,16 @@
                 }
             }
 
-            std::vector<std::pair<double, uint16_t>>::iterator itSet;
-            for (itSet = ueSet1.begin(); itSet != ueSet1.end() && nMux != 0; itSet++)
+            for (auto itSet = ueSet1.begin(); itSet != ueSet1.end() && nMux != 0; itSet++)
             {
-                std::map<uint16_t, pssFlowPerf_t>::iterator itUe;
-                itUe = m_flowStatsDl.find((*itSet).second);
+                auto itUe = m_flowStatsDl.find((*itSet).second);
                 tdUeSet.insert(std::pair<uint16_t, pssFlowPerf_t>((*itUe).first, (*itUe).second));
                 nMux--;
             }
 
-            for (itSet = ueSet2.begin(); itSet != ueSet2.end() && nMux != 0; itSet++)
+            for (auto itSet = ueSet2.begin(); itSet != ueSet2.end() && nMux != 0; itSet++)
             {
-                std::map<uint16_t, pssFlowPerf_t>::iterator itUe;
-                itUe = m_flowStatsDl.find((*itSet).second);
+                auto itUe = m_flowStatsDl.find((*itSet).second);
                 tdUeSet.insert(std::pair<uint16_t, pssFlowPerf_t>((*itUe).first, (*itUe).second));
                 nMux--;
             }
@@ -1133,15 +1104,13 @@
             {
                 // FD scheduler: Carrier over Interference to Average (CoItA)
                 std::map<uint16_t, uint8_t> sbCqiSum;
-                for (it = tdUeSet.begin(); it != tdUeSet.end(); it++)
+                for (auto it = tdUeSet.begin(); it != tdUeSet.end(); it++)
                 {
                     uint8_t sum = 0;
                     for (int i = 0; i < rbgNum; i++)
                     {
-                        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-                        itCqi = m_a30CqiRxed.find((*it).first);
-                        std::map<uint16_t, uint8_t>::iterator itTxMode;
-                        itTxMode = m_uesTxMode.find((*it).first);
+                        auto itCqi = m_a30CqiRxed.find((*it).first);
+                        auto itTxMode = m_uesTxMode.find((*it).first);
                         if (itTxMode == m_uesTxMode.end())
                         {
                             NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
@@ -1150,10 +1119,7 @@
                         std::vector<uint8_t> sbCqis;
                         if (itCqi == m_a30CqiRxed.end())
                         {
-                            for (uint8_t k = 0; k < nLayer; k++)
-                            {
-                                sbCqis.push_back(1); // start with lowest value
-                            }
+                            sbCqis = std::vector<uint8_t>(nLayer, 1); // start with lowest value
                         }
                         else
                         {
@@ -1198,9 +1164,9 @@
                         continue;
                     }
 
-                    std::map<uint16_t, pssFlowPerf_t>::iterator itMax = tdUeSet.end();
+                    auto itMax = tdUeSet.end();
                     double metricMax = 0.0;
-                    for (it = tdUeSet.begin(); it != tdUeSet.end(); it++)
+                    for (auto it = tdUeSet.begin(); it != tdUeSet.end(); it++)
                     {
                         if (!m_ffrSapProvider->IsDlRbgAvailableForUe(i, (*it).first))
                         {
@@ -1215,13 +1181,10 @@
                             weight = 1.0;
                         }
 
-                        std::map<uint16_t, uint8_t>::iterator itSbCqiSum;
-                        itSbCqiSum = sbCqiSum.find((*it).first);
+                        auto itSbCqiSum = sbCqiSum.find((*it).first);
 
-                        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-                        itCqi = m_a30CqiRxed.find((*it).first);
-                        std::map<uint16_t, uint8_t>::iterator itTxMode;
-                        itTxMode = m_uesTxMode.find((*it).first);
+                        auto itCqi = m_a30CqiRxed.find((*it).first);
+                        auto itTxMode = m_uesTxMode.find((*it).first);
                         if (itTxMode == m_uesTxMode.end())
                         {
                             NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
@@ -1230,10 +1193,7 @@
                         std::vector<uint8_t> sbCqis;
                         if (itCqi == m_a30CqiRxed.end())
                         {
-                            for (uint8_t k = 0; k < nLayer; k++)
-                            {
-                                sbCqis.push_back(1); // start with lowest value
-                            }
+                            sbCqis = std::vector<uint8_t>(nLayer, 1); // start with lowest value
                         }
                         else
                         {
@@ -1308,9 +1268,9 @@
                         continue;
                     }
 
-                    std::map<uint16_t, pssFlowPerf_t>::iterator itMax = tdUeSet.end();
+                    auto itMax = tdUeSet.end();
                     double metricMax = 0.0;
-                    for (it = tdUeSet.begin(); it != tdUeSet.end(); it++)
+                    for (auto it = tdUeSet.begin(); it != tdUeSet.end(); it++)
                     {
                         if (!m_ffrSapProvider->IsDlRbgAvailableForUe(i, (*it).first))
                         {
@@ -1324,10 +1284,8 @@
                             weight = 1.0;
                         }
 
-                        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-                        itCqi = m_a30CqiRxed.find((*it).first);
-                        std::map<uint16_t, uint8_t>::iterator itTxMode;
-                        itTxMode = m_uesTxMode.find((*it).first);
+                        auto itCqi = m_a30CqiRxed.find((*it).first);
+                        auto itTxMode = m_uesTxMode.find((*it).first);
                         if (itTxMode == m_uesTxMode.end())
                         {
                             NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
@@ -1336,10 +1294,7 @@
                         std::vector<uint8_t> sbCqis;
                         if (itCqi == m_a30CqiRxed.end())
                         {
-                            for (uint8_t k = 0; k < nLayer; k++)
-                            {
-                                sbCqis.push_back(1); // start with lowest value
-                            }
+                            sbCqis = std::vector<uint8_t>(nLayer, 1); // start with lowest value
                         }
                         else
                         {
@@ -1406,15 +1361,14 @@
     } // end if ueSet
 
     // reset TTI stats of users
-    std::map<uint16_t, pssFlowPerf_t>::iterator itStats;
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         (*itStats).second.lastTtiBytesTransmitted = 0;
     }
 
     // generate the transmission opportunities by grouping the RBGs of the same RNTI and
     // creating the correspondent DCIs
-    std::map<uint16_t, std::vector<uint16_t>>::iterator itMap = allocationMap.begin();
+    auto itMap = allocationMap.begin();
     while (itMap != allocationMap.end())
     {
         // create new BuildDataListElement_s for this LC
@@ -1433,10 +1387,8 @@
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
         uint16_t RgbPerRnti = (*itMap).second.size();
-        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-        itCqi = m_a30CqiRxed.find((*itMap).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itMap).first);
+        auto itCqi = m_a30CqiRxed.find((*itMap).first);
+        auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
@@ -1521,9 +1473,7 @@
         newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
 
         // create the rlc PDUs -> equally divide resources among actives LCs
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itBufReq;
-        for (itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
+        for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
         {
             if (((*itBufReq).first.m_rnti == (*itMap).first) &&
                 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
@@ -1545,8 +1495,7 @@
                     if (m_harqOn)
                     {
                         // store RLC PDU list for HARQ
-                        std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                            m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
+                        auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
                         if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                         {
                             NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1575,8 +1524,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1584,8 +1532,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1597,8 +1544,7 @@
 
         ret.m_buildDataList.push_back(newEl);
         // update UE stats
-        std::map<uint16_t, pssFlowPerf_t>::iterator it;
-        it = m_flowStatsDl.find((*itMap).first);
+        auto it = m_flowStatsDl.find((*itMap).first);
         if (it != m_flowStatsDl.end())
         {
             (*it).second.lastTtiBytesTransmitted = bytesTxed;
@@ -1615,9 +1561,9 @@
 
     // update UEs stats
     NS_LOG_INFO(this << " Update UEs statistics");
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
-        std::map<uint16_t, pssFlowPerf_t>::iterator itUeScheduleted = tdUeSet.end();
+        auto itUeScheduleted = tdUeSet.end();
         itUeScheduleted = tdUeSet.find((*itStats).first);
         if (itUeScheduleted != tdUeSet.end())
         {
@@ -1660,9 +1606,8 @@
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1677,17 +1622,15 @@
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
         else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
         {
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_a30CqiRxed.find(rnti);
+            auto it = m_a30CqiRxed.find(rnti);
             if (it == m_a30CqiRxed.end())
             {
                 // create the new entry
@@ -1700,8 +1643,7 @@
             {
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_a30CqiTimers.find(rnti);
+                auto itTimers = m_a30CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1715,7 +1657,7 @@
 double
 PssFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find(rnti);
+    auto itCqi = m_ueCqi.find(rnti);
     if (itCqi == m_ueCqi.end())
     {
         // no cqi info about this UE
@@ -1768,7 +1710,7 @@
 
     rbMap = m_ffrSapProvider->GetAvailableUlRbg();
 
-    for (std::vector<bool>::iterator it = rbMap.begin(); it != rbMap.end(); it++)
+    for (auto it = rbMap.begin(); it != rbMap.end(); it++)
     {
         if (*it)
         {
@@ -1798,8 +1740,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1807,16 +1748,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
                                  << " i " << i << " size " << params.m_ulInfoList.size());
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                     continue;
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1875,7 +1814,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
         {
@@ -1908,7 +1847,6 @@
     }
     int rbAllocated = 0;
 
-    std::map<uint16_t, pssFlowPerf_t>::iterator itStats;
     if (m_nextRntiUl != 0)
     {
         for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
@@ -1930,7 +1868,7 @@
     }
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -2023,7 +1961,7 @@
             break;
         }
 
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -2094,15 +2032,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -2110,8 +2046,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -2165,8 +2100,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -2187,7 +2120,7 @@
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
             NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -2233,11 +2166,9 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
         NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
                           << " subframe no. " << (0xF & params.m_sfnSf));
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             return;
@@ -2246,7 +2177,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -2276,8 +2207,7 @@
                 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
                                   << sinr);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -2298,8 +2228,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -2326,8 +2255,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -2347,7 +2275,7 @@
 PssFfMacScheduler::RefreshDlCqiMaps()
 {
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -2355,12 +2283,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -2372,7 +2300,7 @@
     }
 
     // refresh DL CQI A30 Map
-    std::map<uint16_t, uint32_t>::iterator itA30 = m_a30CqiTimers.begin();
+    auto itA30 = m_a30CqiTimers.begin();
     while (itA30 != m_a30CqiTimers.end())
     {
         NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
@@ -2380,12 +2308,12 @@
         if ((*itA30).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find((*itA30).first);
+            auto itMap = m_a30CqiRxed.find((*itA30).first);
             NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
                           " Does not find CQI report for user " << (*itA30).first);
             NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
             m_a30CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itA30;
+            auto temp = itA30;
             itA30++;
             m_a30CqiTimers.erase(temp);
         }
@@ -2401,7 +2329,7 @@
 PssFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -2409,13 +2337,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -2430,9 +2358,8 @@
 void
 PssFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     LteFlowId_t flow(rnti, lcid);
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
     if (it != m_rlcBufferReq.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
@@ -2487,7 +2414,7 @@
 PssFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/rr-ff-mac-scheduler.cc ns-3.40/src/lte/model/rr-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/rr-ff-mac-scheduler.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/rr-ff-mac-scheduler.cc	2023-09-27 13:30:37.826839700 -0700
@@ -160,7 +160,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, double>(params.m_rnti, params.m_transmissionMode));
@@ -215,8 +215,7 @@
     NS_LOG_FUNCTION(this);
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::list<FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).m_rnti == params.m_rnti) &&
@@ -248,8 +247,7 @@
     m_ulHarqProcessesStatus.erase(params.m_rnti);
     m_ulHarqProcessesDciBuffer.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::list<FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).m_rnti == params.m_rnti)
@@ -280,8 +278,7 @@
 {
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
-    std::list<FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
+    auto it = m_rlcBufferReq.begin();
     bool newLc = true;
     while (it != m_rlcBufferReq.end())
     {
@@ -356,13 +353,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -386,13 +382,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -420,8 +415,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -431,8 +425,7 @@
                 // reset HARQ process
 
                 NS_LOG_INFO(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -468,9 +461,9 @@
     std::set<uint16_t> rntiAllocated;
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
 
-    //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    // update UL HARQ proc id
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -479,8 +472,7 @@
     // RACH Allocation
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -544,15 +536,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -594,7 +584,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -622,8 +612,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -644,16 +633,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Max number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -740,8 +727,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -819,8 +805,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -833,15 +818,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ ACK UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -873,11 +857,10 @@
     int nflows = 0;
     int nTbs = 0;
     std::map<uint16_t, uint8_t> lcActivesPerRnti; // tracks how many active LCs per RNTI there are
-    std::map<uint16_t, uint8_t>::iterator itLcRnti;
     for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         // remove old entries of this UE-LC
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).m_rnti);
+        auto itRnti = rntiAllocated.find((*it).m_rnti);
         if ((((*it).m_rlcTransmissionQueueSize > 0) || ((*it).m_rlcRetransmissionQueueSize > 0) ||
              ((*it).m_rlcStatusPduSize > 0)) &&
             (itRnti == rntiAllocated.end())             // UE must not be allocated for HARQ retx
@@ -889,7 +872,7 @@
                               << (*it).m_rlcStatusPduSize << " retx "
                               << (*it).m_rlcRetransmissionQueueSize << " tx "
                               << (*it).m_rlcTransmissionQueueSize);
-            std::map<uint16_t, uint8_t>::iterator itCqi = m_p10CqiRxed.find((*it).m_rnti);
+            auto itCqi = m_p10CqiRxed.find((*it).m_rnti);
             uint8_t cqi = 0;
             if (itCqi != m_p10CqiRxed.end())
             {
@@ -903,7 +886,7 @@
             {
                 // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
                 nflows++;
-                itLcRnti = lcActivesPerRnti.find((*it).m_rnti);
+                auto itLcRnti = lcActivesPerRnti.find((*it).m_rnti);
                 if (itLcRnti != lcActivesPerRnti.end())
                 {
                     (*itLcRnti).second++;
@@ -966,11 +949,10 @@
         it = m_rlcBufferReq.begin();
         m_nextRntiDl = (*it).m_rnti;
     }
-    std::map<uint16_t, uint8_t>::iterator itTxMode;
     do
     {
-        itLcRnti = lcActivesPerRnti.find((*it).m_rnti);
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).m_rnti);
+        auto itLcRnti = lcActivesPerRnti.find((*it).m_rnti);
+        auto itRnti = rntiAllocated.find((*it).m_rnti);
         if ((itLcRnti == lcActivesPerRnti.end()) || (itRnti != rntiAllocated.end()))
         {
             // skip this RNTI (no active queue or yet allocated for HARQ)
@@ -990,7 +972,7 @@
             }
             continue;
         }
-        itTxMode = m_uesTxMode.find((*it).m_rnti);
+        auto itTxMode = m_uesTxMode.find((*it).m_rnti);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).m_rnti);
@@ -1006,7 +988,7 @@
         newDci.m_harqProcess = UpdateHarqProcessId((*it).m_rnti);
         newDci.m_resAlloc = 0;
         newDci.m_rbBitmap = 0;
-        std::map<uint16_t, uint8_t>::iterator itCqi = m_p10CqiRxed.find(newEl.m_rnti);
+        auto itCqi = m_p10CqiRxed.find(newEl.m_rnti);
         for (uint8_t i = 0; i < nLayer; i++)
         {
             if (itCqi == m_p10CqiRxed.end())
@@ -1042,8 +1024,7 @@
                     if (m_harqOn)
                     {
                         // store RLC PDU list for HARQ
-                        std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                            m_dlHarqProcessesRlcPduListBuffer.find((*it).m_rnti);
+                        auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*it).m_rnti);
                         if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                         {
                             NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1097,8 +1078,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1106,8 +1086,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1144,16 +1123,14 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint8_t>::iterator it;
     for (unsigned int i = 0; i < params.m_cqiList.size(); i++)
     {
         if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::P10)
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1168,8 +1145,7 @@
                 // update the CQI value
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1225,8 +1201,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1234,16 +1209,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId "
                                  << (uint16_t)harqId);
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in UL-HARQ buffer for UE (might change eNB) "
                                  << rnti);
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1296,7 +1269,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         NS_LOG_INFO(this << " UE " << (*it).first << " queue " << (*it).second);
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
@@ -1348,7 +1321,7 @@
     NS_LOG_INFO(this << " NFlows " << nflows << " RB per Flow " << rbPerFlow);
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -1431,7 +1404,7 @@
                 std::pair<uint16_t, std::vector<uint16_t>>(params.m_sfnSf, rbgAllocationMap));
             return;
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -1495,15 +1468,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -1511,8 +1482,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -1566,8 +1536,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -1587,7 +1555,7 @@
             }
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -1634,9 +1602,7 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             NS_LOG_INFO(this << " Does not find info on allocation, size : "
@@ -1647,7 +1613,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -1675,8 +1641,7 @@
                 // update the value
                 (*itCqi).second.at(i) = sinr;
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1697,8 +1662,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -1725,8 +1689,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -1747,7 +1710,7 @@
 {
     NS_LOG_FUNCTION(this << m_p10CqiTimers.size());
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -1755,12 +1718,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI exired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -1776,7 +1739,7 @@
 RrFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -1784,13 +1747,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -1806,8 +1769,7 @@
 RrFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
     NS_LOG_FUNCTION(this);
-    std::list<FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).m_rnti == rnti) && ((*it).m_logicalChannelIdentity == lcid))
         {
@@ -1861,7 +1823,7 @@
 RrFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " Update RLC BSR UE " << rnti << " size " << size << " BSR "
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/simple-ue-component-carrier-manager.cc ns-3.40/src/lte/model/simple-ue-component-carrier-manager.cc
--- ns-3.39/src/lte/model/simple-ue-component-carrier-manager.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/simple-ue-component-carrier-manager.cc	2023-09-27 13:30:37.826839700 -0700
@@ -182,8 +182,7 @@
 SimpleUeComponentCarrierManager::DoTransmitPdu(LteMacSapProvider::TransmitPduParameters params)
 {
     NS_LOG_FUNCTION(this);
-    std::map<uint8_t, LteMacSapProvider*>::iterator it =
-        m_macSapProvidersMap.find(params.componentCarrierId);
+    auto it = m_macSapProvidersMap.find(params.componentCarrierId);
     NS_ABORT_MSG_IF(it == m_macSapProvidersMap.end(),
                     "could not find Sap for ComponentCarrier "
                         << (uint16_t)params.componentCarrierId);
@@ -197,18 +196,17 @@
 {
     NS_LOG_FUNCTION(this);
     NS_LOG_DEBUG("BSR from RLC for LCID = " << (uint16_t)params.lcid);
-    std::map<uint8_t, LteMacSapProvider*>::iterator it = m_macSapProvidersMap.find(0);
+    auto it = m_macSapProvidersMap.find(0);
     NS_ABORT_MSG_IF(it == m_macSapProvidersMap.end(), "could not find Sap for ComponentCarrier");
 
     NS_LOG_DEBUG("Size of component carrier LC map " << m_componentCarrierLcMap.size());
 
-    for (std::map<uint8_t, std::map<uint8_t, LteMacSapProvider*>>::iterator ccLcMapIt =
-             m_componentCarrierLcMap.begin();
+    for (auto ccLcMapIt = m_componentCarrierLcMap.begin();
          ccLcMapIt != m_componentCarrierLcMap.end();
          ccLcMapIt++)
     {
         NS_LOG_DEBUG("BSR from RLC for CC id = " << (uint16_t)ccLcMapIt->first);
-        std::map<uint8_t, LteMacSapProvider*>::iterator it = ccLcMapIt->second.find(params.lcid);
+        auto it = ccLcMapIt->second.find(params.lcid);
         if (it != ccLcMapIt->second.end())
         {
             it->second->ReportBufferStatus(params);
@@ -227,7 +225,7 @@
     LteMacSapUser::TxOpportunityParameters txOpParams)
 {
     NS_LOG_FUNCTION(this);
-    std::map<uint8_t, LteMacSapUser*>::iterator lcidIt = m_lcAttached.find(txOpParams.lcid);
+    auto lcidIt = m_lcAttached.find(txOpParams.lcid);
     NS_ABORT_MSG_IF(lcidIt == m_lcAttached.end(),
                     "could not find LCID" << (uint16_t)txOpParams.lcid);
     NS_LOG_DEBUG(this << " lcid = " << (uint32_t)txOpParams.lcid
@@ -245,7 +243,7 @@
 SimpleUeComponentCarrierManager::DoReceivePdu(LteMacSapUser::ReceivePduParameters rxPduParams)
 {
     NS_LOG_FUNCTION(this);
-    std::map<uint8_t, LteMacSapUser*>::iterator lcidIt = m_lcAttached.find(rxPduParams.lcid);
+    auto lcidIt = m_lcAttached.find(rxPduParams.lcid);
     NS_ABORT_MSG_IF(lcidIt == m_lcAttached.end(),
                     "could not find LCID" << (uint16_t)rxPduParams.lcid);
     if (lcidIt != m_lcAttached.end())
@@ -265,11 +263,10 @@
     NS_ABORT_MSG_IF(m_lcAttached.find(lcid) == m_lcAttached.end(), "could not find LCID " << lcid);
     m_lcAttached.erase(lcid);
     // send back all the configuration to the componentCarrier where we want to remove the Lc
-    std::map<uint8_t, std::map<uint8_t, LteMacSapProvider*>>::iterator it =
-        m_componentCarrierLcMap.begin();
+    auto it = m_componentCarrierLcMap.begin();
     while (it != m_componentCarrierLcMap.end())
     {
-        std::map<uint8_t, LteMacSapProvider*>::iterator lcToRemove = it->second.find(lcid);
+        auto lcToRemove = it->second.find(lcid);
         if (lcToRemove != it->second.end())
         {
             res.insert(res.end(), it->first);
@@ -287,7 +284,7 @@
 {
     NS_LOG_FUNCTION(this);
     // same semantics as LteUeMac::DoRest
-    std::map<uint8_t, LteMacSapUser*>::iterator it = m_lcAttached.begin();
+    auto it = m_lcAttached.begin();
     while (it != m_lcAttached.end())
     {
         // don't delete CCCH
@@ -310,11 +307,10 @@
 {
     NS_LOG_FUNCTION(this);
     std::vector<LteUeCcmRrcSapProvider::LcsConfig> res;
-    std::map<uint8_t, LteMacSapUser*>::iterator it = m_lcAttached.find(lcId);
+    auto it = m_lcAttached.find(lcId);
     NS_ABORT_MSG_IF(it != m_lcAttached.end(), "Warning, LCID " << lcId << " already exist");
     m_lcAttached.insert(std::pair<uint8_t, LteMacSapUser*>(lcId, msu));
     LteUeCcmRrcSapProvider::LcsConfig elem;
-    std::map<uint8_t, std::map<uint8_t, LteMacSapProvider*>>::iterator ccLcMapIt;
     for (uint8_t ncc = 0; ncc < m_noOfComponentCarriers; ncc++)
     {
         elem.componentCarrierId = ncc;
@@ -322,7 +318,7 @@
         elem.msu = m_ccmMacSapUser;
         res.insert(res.end(), elem);
 
-        ccLcMapIt = m_componentCarrierLcMap.find(ncc);
+        auto ccLcMapIt = m_componentCarrierLcMap.find(ncc);
         if (ccLcMapIt != m_componentCarrierLcMap.end())
         {
             ccLcMapIt->second.insert(
@@ -331,9 +327,8 @@
         else
         {
             std::map<uint8_t, LteMacSapProvider*> empty;
-            std::pair<std::map<uint8_t, std::map<uint8_t, LteMacSapProvider*>>::iterator, bool>
-                ret = m_componentCarrierLcMap.insert(
-                    std::pair<uint8_t, std::map<uint8_t, LteMacSapProvider*>>(ncc, empty));
+            auto ret = m_componentCarrierLcMap.insert(
+                std::pair<uint8_t, std::map<uint8_t, LteMacSapProvider*>>(ncc, empty));
             NS_ABORT_MSG_IF(!ret.second,
                             "element already present, ComponentCarrierId already exist");
             ccLcMapIt = m_componentCarrierLcMap.find(ncc);
@@ -352,7 +347,7 @@
     LteMacSapUser* msu)
 {
     NS_LOG_FUNCTION(this);
-    std::map<uint8_t, LteMacSapUser*>::iterator it = m_lcAttached.find(lcid);
+    auto it = m_lcAttached.find(lcid);
     // if the following assert is hit, e.g., in handover scenarios, it means
     //  the DoRest function is not called by UE RRC
     NS_ABORT_MSG_IF(it != m_lcAttached.end(),
@@ -360,10 +355,9 @@
 
     m_lcAttached.insert(std::pair<uint8_t, LteMacSapUser*>(lcid, msu));
 
-    std::map<uint8_t, std::map<uint8_t, LteMacSapProvider*>>::iterator ccLcMapIt;
     for (uint8_t ncc = 0; ncc < m_noOfComponentCarriers; ncc++)
     {
-        ccLcMapIt = m_componentCarrierLcMap.find(ncc);
+        auto ccLcMapIt = m_componentCarrierLcMap.find(ncc);
         if (ccLcMapIt != m_componentCarrierLcMap.end())
         {
             ccLcMapIt->second.insert(
@@ -372,9 +366,8 @@
         else
         {
             std::map<uint8_t, LteMacSapProvider*> empty;
-            std::pair<std::map<uint8_t, std::map<uint8_t, LteMacSapProvider*>>::iterator, bool>
-                ret = m_componentCarrierLcMap.insert(
-                    std::pair<uint8_t, std::map<uint8_t, LteMacSapProvider*>>(ncc, empty));
+            auto ret = m_componentCarrierLcMap.insert(
+                std::pair<uint8_t, std::map<uint8_t, LteMacSapProvider*>>(ncc, empty));
             NS_ABORT_MSG_IF(!ret.second,
                             "element already present, ComponentCarrierId already existed");
             ccLcMapIt = m_componentCarrierLcMap.find(ncc);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/tdbet-ff-mac-scheduler.cc ns-3.40/src/lte/model/tdbet-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/tdbet-ff-mac-scheduler.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/tdbet-ff-mac-scheduler.cc	2023-09-27 13:30:37.826839700 -0700
@@ -159,7 +159,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, double>(params.m_rnti, params.m_transmissionMode));
@@ -205,10 +205,9 @@
 {
     NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
 
-    std::map<uint16_t, tdbetsFlowPerf_t>::iterator it;
     for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
     {
-        it = m_flowStatsDl.find(params.m_rnti);
+        auto it = m_flowStatsDl.find(params.m_rnti);
 
         if (it == m_flowStatsDl.end())
         {
@@ -235,15 +234,13 @@
     NS_LOG_FUNCTION(this);
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).first.m_rnti == params.m_rnti) &&
                 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
             {
-                temp = it;
+                auto temp = it;
                 it++;
                 m_rlcBufferReq.erase(temp);
             }
@@ -273,14 +270,12 @@
     m_flowStatsDl.erase(params.m_rnti);
     m_flowStatsUl.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).first.m_rnti == params.m_rnti)
         {
-            temp = it;
+            auto temp = it;
             it++;
             m_rlcBufferReq.erase(temp);
         }
@@ -302,11 +297,9 @@
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
 
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-
     LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
 
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
 
     if (it == m_rlcBufferReq.end())
     {
@@ -353,9 +346,8 @@
 unsigned int
 TdBetFfMacScheduler::LcActivePerFlow(uint16_t rnti)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     unsigned int lcActive = 0;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
                                              ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
@@ -376,13 +368,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -406,13 +397,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -441,8 +431,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -452,8 +441,7 @@
                 // reset HARQ process
 
                 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -493,9 +481,9 @@
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
     FfMacSchedSapUser::SchedDlConfigIndParameters ret;
 
-    //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    // update UL HARQ proc id
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -504,8 +492,7 @@
     // RACH Allocation
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -569,15 +556,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -619,7 +604,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -647,8 +632,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -669,16 +653,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -765,8 +747,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -843,8 +824,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -857,15 +837,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -891,16 +870,13 @@
         return;
     }
 
-    std::map<uint16_t, tdbetsFlowPerf_t>::iterator it;
-    std::map<uint16_t, tdbetsFlowPerf_t>::iterator itMax = m_flowStatsDl.end();
+    auto itMax = m_flowStatsDl.end();
     double metricMax = 0.0;
-    for (it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
+    for (auto it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
     {
         // check first what are channel conditions for this UE, if CQI!=0
-        std::map<uint16_t, uint8_t>::iterator itCqi;
-        itCqi = m_p10CqiRxed.find((*it).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*it).first);
+        auto itCqi = m_p10CqiRxed.find((*it).first);
+        auto itTxMode = m_uesTxMode.find((*it).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
@@ -925,7 +901,7 @@
             continue;
         }
 
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*it).first)))
         {
             // UE already allocated for HARQ or without HARQ process available -> drop it
@@ -967,15 +943,14 @@
     }
 
     // reset TTI stats of users
-    std::map<uint16_t, tdbetsFlowPerf_t>::iterator itStats;
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         (*itStats).second.lastTtiBytesTrasmitted = 0;
     }
 
     // generate the transmission opportunities by grouping the RBGs of the same RNTI and
     // creating the correspondent DCIs
-    std::map<uint16_t, std::vector<uint16_t>>::iterator itMap = allocationMap.begin();
+    auto itMap = allocationMap.begin();
     while (itMap != allocationMap.end())
     {
         // create new BuildDataListElement_s for this LC
@@ -994,10 +969,8 @@
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
         uint16_t RgbPerRnti = (*itMap).second.size();
-        std::map<uint16_t, uint8_t>::iterator itCqi;
-        itCqi = m_p10CqiRxed.find((*itMap).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itMap).first);
+        auto itCqi = m_p10CqiRxed.find((*itMap).first);
+        auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
@@ -1033,9 +1006,7 @@
         newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
 
         // create the rlc PDUs -> equally divide resources among actives LCs
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itBufReq;
-        for (itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
+        for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
         {
             if (((*itBufReq).first.m_rnti == (*itMap).first) &&
                 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
@@ -1057,8 +1028,7 @@
                     if (m_harqOn)
                     {
                         // store RLC PDU list for HARQ
-                        std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                            m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
+                        auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
                         if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                         {
                             NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1087,8 +1057,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1096,8 +1065,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1109,8 +1077,7 @@
 
         ret.m_buildDataList.push_back(newEl);
         // update UE stats
-        std::map<uint16_t, tdbetsFlowPerf_t>::iterator it;
-        it = m_flowStatsDl.find((*itMap).first);
+        auto it = m_flowStatsDl.find((*itMap).first);
         if (it != m_flowStatsDl.end())
         {
             (*it).second.lastTtiBytesTrasmitted = bytesTxed;
@@ -1127,7 +1094,7 @@
 
     // update UEs stats
     NS_LOG_INFO(this << " Update UEs statistics");
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
         // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
@@ -1164,9 +1131,8 @@
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1181,17 +1147,15 @@
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
         else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
         {
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_a30CqiRxed.find(rnti);
+            auto it = m_a30CqiRxed.find(rnti);
             if (it == m_a30CqiRxed.end())
             {
                 // create the new entry
@@ -1204,8 +1168,7 @@
             {
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_a30CqiTimers.find(rnti);
+                auto itTimers = m_a30CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1219,7 +1182,7 @@
 double
 TdBetFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find(rnti);
+    auto itCqi = m_ueCqi.find(rnti);
     if (itCqi == m_ueCqi.end())
     {
         // no cqi info about this UE
@@ -1286,8 +1249,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1295,16 +1257,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
                                  << " i " << i << " size " << params.m_ulInfoList.size());
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                     continue;
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1362,7 +1322,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
         {
@@ -1392,7 +1352,6 @@
     }
     int rbAllocated = 0;
 
-    std::map<uint16_t, tdbetsFlowPerf_t>::iterator itStats;
     if (m_nextRntiUl != 0)
     {
         for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
@@ -1414,7 +1373,7 @@
     }
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -1499,7 +1458,7 @@
             return;
         }
 
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -1570,15 +1529,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -1586,8 +1543,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -1603,7 +1559,7 @@
                          << (uint16_t)harqId);
 
         // update TTI  UE stats
-        itStats = m_flowStatsUl.find((*it).first);
+        auto itStats = m_flowStatsUl.find((*it).first);
         if (itStats != m_flowStatsUl.end())
         {
             (*itStats).second.lastTtiBytesTrasmitted = uldci.m_tbSize;
@@ -1629,7 +1585,7 @@
 
     // Update global UE stats
     // update UEs stats
-    for (itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
+    for (auto itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
     {
         (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
         // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
@@ -1666,8 +1622,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -1688,7 +1642,7 @@
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
             NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -1734,11 +1688,9 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
         NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
                           << " subframe no. " << (0xF & params.m_sfnSf));
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             return;
@@ -1747,7 +1699,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -1777,8 +1729,7 @@
                 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
                                   << sinr);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1799,8 +1750,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -1827,8 +1777,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -1848,7 +1797,7 @@
 TdBetFfMacScheduler::RefreshDlCqiMaps()
 {
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -1856,12 +1805,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -1873,7 +1822,7 @@
     }
 
     // refresh DL CQI A30 Map
-    std::map<uint16_t, uint32_t>::iterator itA30 = m_a30CqiTimers.begin();
+    auto itA30 = m_a30CqiTimers.begin();
     while (itA30 != m_a30CqiTimers.end())
     {
         NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
@@ -1881,12 +1830,12 @@
         if ((*itA30).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find((*itA30).first);
+            auto itMap = m_a30CqiRxed.find((*itA30).first);
             NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
                           " Does not find CQI report for user " << (*itA30).first);
             NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
             m_a30CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itA30;
+            auto temp = itA30;
             itA30++;
             m_a30CqiTimers.erase(temp);
         }
@@ -1902,7 +1851,7 @@
 TdBetFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -1910,13 +1859,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -1931,9 +1880,8 @@
 void
 TdBetFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     LteFlowId_t flow(rnti, lcid);
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
     if (it != m_rlcBufferReq.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
@@ -1988,7 +1936,7 @@
 TdBetFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/tdmt-ff-mac-scheduler.cc ns-3.40/src/lte/model/tdmt-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/tdmt-ff-mac-scheduler.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/tdmt-ff-mac-scheduler.cc	2023-09-27 13:30:37.826839700 -0700
@@ -158,7 +158,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, double>(params.m_rnti, params.m_transmissionMode));
@@ -204,10 +204,9 @@
 {
     NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
 
-    std::set<uint16_t>::iterator it;
     for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
     {
-        it = m_flowStatsDl.find(params.m_rnti);
+        auto it = m_flowStatsDl.find(params.m_rnti);
 
         if (it == m_flowStatsDl.end())
         {
@@ -224,15 +223,13 @@
     NS_LOG_FUNCTION(this);
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).first.m_rnti == params.m_rnti) &&
                 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
             {
-                temp = it;
+                auto temp = it;
                 it++;
                 m_rlcBufferReq.erase(temp);
             }
@@ -262,14 +259,12 @@
     m_flowStatsDl.erase(params.m_rnti);
     m_flowStatsUl.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).first.m_rnti == params.m_rnti)
         {
-            temp = it;
+            auto temp = it;
             it++;
             m_rlcBufferReq.erase(temp);
         }
@@ -291,11 +286,9 @@
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
 
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-
     LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
 
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
 
     if (it == m_rlcBufferReq.end())
     {
@@ -342,9 +335,8 @@
 unsigned int
 TdMtFfMacScheduler::LcActivePerFlow(uint16_t rnti)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     unsigned int lcActive = 0;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
                                              ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
@@ -365,13 +357,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -395,13 +386,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -430,8 +420,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -441,8 +430,7 @@
                 // reset HARQ process
 
                 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -482,9 +470,9 @@
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
     FfMacSchedSapUser::SchedDlConfigIndParameters ret;
 
-    //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    // update UL HARQ proc id
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -493,8 +481,7 @@
     // RACH Allocation
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -558,15 +545,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -608,7 +593,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -636,8 +621,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -658,16 +642,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -754,8 +736,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -832,8 +813,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -846,15 +826,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -880,12 +859,11 @@
         return;
     }
 
-    std::set<uint16_t>::iterator it;
-    std::set<uint16_t>::iterator itMax = m_flowStatsDl.end();
+    auto itMax = m_flowStatsDl.end();
     double metricMax = 0.0;
-    for (it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
+    for (auto it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it));
+        auto itRnti = rntiAllocated.find((*it));
         if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*it))))
         {
             // UE already allocated for HARQ or without HARQ process available -> drop it
@@ -901,14 +879,13 @@
             continue;
         }
 
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*it));
+        auto itTxMode = m_uesTxMode.find((*it));
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*it));
         }
         auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
-        std::map<uint16_t, uint8_t>::iterator itCqi = m_p10CqiRxed.find((*it));
+        auto itCqi = m_p10CqiRxed.find((*it));
         uint8_t wbCqi = 0;
         if (itCqi != m_p10CqiRxed.end())
         {
@@ -978,7 +955,7 @@
 
     // generate the transmission opportunities by grouping the RBGs of the same RNTI and
     // creating the correspondent DCIs
-    std::map<uint16_t, std::vector<uint16_t>>::iterator itMap = allocationMap.begin();
+    auto itMap = allocationMap.begin();
     while (itMap != allocationMap.end())
     {
         // create new BuildDataListElement_s for this LC
@@ -997,10 +974,8 @@
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
         uint16_t RgbPerRnti = (*itMap).second.size();
-        std::map<uint16_t, uint8_t>::iterator itCqi;
-        itCqi = m_p10CqiRxed.find((*itMap).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itMap).first);
+        auto itCqi = m_p10CqiRxed.find((*itMap).first);
+        auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
@@ -1033,9 +1008,7 @@
         newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
 
         // create the rlc PDUs -> equally divide resources among actives LCs
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itBufReq;
-        for (itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
+        for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
         {
             if (((*itBufReq).first.m_rnti == (*itMap).first) &&
                 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
@@ -1057,8 +1030,7 @@
                     if (m_harqOn)
                     {
                         // store RLC PDU list for HARQ
-                        std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                            m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
+                        auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
                         if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                         {
                             NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1087,8 +1059,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1096,8 +1067,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1137,9 +1107,8 @@
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1154,17 +1123,15 @@
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
         else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
         {
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_a30CqiRxed.find(rnti);
+            auto it = m_a30CqiRxed.find(rnti);
             if (it == m_a30CqiRxed.end())
             {
                 // create the new entry
@@ -1177,8 +1144,7 @@
             {
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_a30CqiTimers.find(rnti);
+                auto itTimers = m_a30CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1192,7 +1158,7 @@
 double
 TdMtFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find(rnti);
+    auto itCqi = m_ueCqi.find(rnti);
     if (itCqi == m_ueCqi.end())
     {
         // no cqi info about this UE
@@ -1259,8 +1225,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1268,16 +1233,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
                                  << " i " << i << " size " << params.m_ulInfoList.size());
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                     continue;
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1335,7 +1298,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
         {
@@ -1386,7 +1349,7 @@
     }
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -1471,7 +1434,7 @@
             return;
         }
 
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -1542,15 +1505,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -1558,8 +1519,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -1613,8 +1573,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -1635,7 +1593,7 @@
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
             NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -1681,11 +1639,9 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
         NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
                           << " subframe no. " << (0xF & params.m_sfnSf));
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             return;
@@ -1694,7 +1650,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -1724,8 +1680,7 @@
                 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
                                   << sinr);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1746,8 +1701,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -1774,8 +1728,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -1795,7 +1748,7 @@
 TdMtFfMacScheduler::RefreshDlCqiMaps()
 {
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -1803,12 +1756,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -1820,7 +1773,7 @@
     }
 
     // refresh DL CQI A30 Map
-    std::map<uint16_t, uint32_t>::iterator itA30 = m_a30CqiTimers.begin();
+    auto itA30 = m_a30CqiTimers.begin();
     while (itA30 != m_a30CqiTimers.end())
     {
         NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
@@ -1828,12 +1781,12 @@
         if ((*itA30).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find((*itA30).first);
+            auto itMap = m_a30CqiRxed.find((*itA30).first);
             NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
                           " Does not find CQI report for user " << (*itA30).first);
             NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
             m_a30CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itA30;
+            auto temp = itA30;
             itA30++;
             m_a30CqiTimers.erase(temp);
         }
@@ -1849,7 +1802,7 @@
 TdMtFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -1857,13 +1810,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -1878,9 +1831,8 @@
 void
 TdMtFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     LteFlowId_t flow(rnti, lcid);
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
     if (it != m_rlcBufferReq.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
@@ -1935,7 +1887,7 @@
 TdMtFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/tdtbfq-ff-mac-scheduler.cc ns-3.40/src/lte/model/tdtbfq-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/tdtbfq-ff-mac-scheduler.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/tdtbfq-ff-mac-scheduler.cc	2023-09-27 13:30:37.826839700 -0700
@@ -184,7 +184,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, double>(params.m_rnti, params.m_transmissionMode));
@@ -230,10 +230,9 @@
 {
     NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
 
-    std::map<uint16_t, tdtbfqsFlowPerf_t>::iterator it;
     for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
     {
-        it = m_flowStatsDl.find(params.m_rnti);
+        auto it = m_flowStatsDl.find(params.m_rnti);
 
         if (it == m_flowStatsDl.end())
         {
@@ -287,15 +286,13 @@
     NS_LOG_FUNCTION(this);
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).first.m_rnti == params.m_rnti) &&
                 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
             {
-                temp = it;
+                auto temp = it;
                 it++;
                 m_rlcBufferReq.erase(temp);
             }
@@ -325,14 +322,12 @@
     m_flowStatsDl.erase(params.m_rnti);
     m_flowStatsUl.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).first.m_rnti == params.m_rnti)
         {
-            temp = it;
+            auto temp = it;
             it++;
             m_rlcBufferReq.erase(temp);
         }
@@ -354,11 +349,9 @@
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
 
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-
     LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
 
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
 
     if (it == m_rlcBufferReq.end())
     {
@@ -405,9 +398,8 @@
 unsigned int
 TdTbfqFfMacScheduler::LcActivePerFlow(uint16_t rnti)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     unsigned int lcActive = 0;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
                                              ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
@@ -428,13 +420,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -458,13 +449,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -493,8 +483,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -504,8 +493,7 @@
                 // reset HARQ process
 
                 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -545,7 +533,7 @@
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
 
     rbgMap = m_ffrSapProvider->GetAvailableDlRbg();
-    for (std::vector<bool>::iterator it = rbgMap.begin(); it != rbgMap.end(); it++)
+    for (auto it = rbgMap.begin(); it != rbgMap.end(); it++)
     {
         if (*it)
         {
@@ -555,9 +543,9 @@
 
     FfMacSchedSapUser::SchedDlConfigIndParameters ret;
 
-    //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    // update UL HARQ proc id
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -573,7 +561,7 @@
     uint16_t tmpFfrRbStartOffset = 0;
     uint16_t index = 0;
 
-    for (std::vector<bool>::iterator it = ulRbMap.begin(); it != ulRbMap.end(); it++)
+    for (auto it = ulRbMap.begin(); it != ulRbMap.end(); it++)
     {
         if (*it)
         {
@@ -604,8 +592,7 @@
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
     rbStart = ffrRbStartOffset;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -669,15 +656,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -719,7 +704,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -747,8 +732,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -769,16 +753,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -865,8 +847,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -943,8 +924,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -957,15 +937,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -992,8 +971,7 @@
     }
 
     // update token pool, counter and bank size
-    std::map<uint16_t, tdtbfqsFlowPerf_t>::iterator itStats;
-    for (itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
+    for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
     {
         if ((*itStats).second.tokenGenerationRate / 1000 + (*itStats).second.tokenPoolSize >
             (*itStats).second.maxTokenPoolSize)
@@ -1012,13 +990,12 @@
     }
 
     // select UE with largest metric
-    std::map<uint16_t, tdtbfqsFlowPerf_t>::iterator it;
-    std::map<uint16_t, tdtbfqsFlowPerf_t>::iterator itMax = m_flowStatsDl.end();
+    auto itMax = m_flowStatsDl.end();
     double metricMax = 0.0;
     bool firstRnti = true;
-    for (it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
+    for (auto it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*it).first)))
         {
             // UE already allocated for HARQ or without HARQ process available -> drop it
@@ -1034,10 +1011,8 @@
         }
 
         // check first the channel conditions for this UE, if CQI!=0
-        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-        itCqi = m_a30CqiRxed.find((*it).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*it).first);
+        auto itCqi = m_a30CqiRxed.find((*it).first);
+        auto itTxMode = m_uesTxMode.find((*it).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
@@ -1124,7 +1099,7 @@
 
     // generate the transmission opportunities by grouping the RBGs of the same RNTI and
     // creating the correspondent DCIs
-    std::map<uint16_t, std::vector<uint16_t>>::iterator itMap = allocationMap.begin();
+    auto itMap = allocationMap.begin();
     while (itMap != allocationMap.end())
     {
         // create new BuildDataListElement_s for this LC
@@ -1143,10 +1118,8 @@
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
         uint16_t RgbPerRnti = (*itMap).second.size();
-        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-        itCqi = m_a30CqiRxed.find((*itMap).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itMap).first);
+        auto itCqi = m_a30CqiRxed.find((*itMap).first);
+        auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
@@ -1219,9 +1192,7 @@
         newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
 
         // create the rlc PDUs -> equally divide resources among actives LCs
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itBufReq;
-        for (itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
+        for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
         {
             if (((*itBufReq).first.m_rnti == (*itMap).first) &&
                 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
@@ -1243,8 +1214,7 @@
                     if (m_harqOn)
                     {
                         // store RLC PDU list for HARQ
-                        std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                            m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
+                        auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
                         if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                         {
                             NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1273,8 +1243,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1282,8 +1251,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1344,9 +1312,8 @@
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1361,17 +1328,15 @@
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
         else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
         {
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_a30CqiRxed.find(rnti);
+            auto it = m_a30CqiRxed.find(rnti);
             if (it == m_a30CqiRxed.end())
             {
                 // create the new entry
@@ -1384,8 +1349,7 @@
             {
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_a30CqiTimers.find(rnti);
+                auto itTimers = m_a30CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1399,7 +1363,7 @@
 double
 TdTbfqFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find(rnti);
+    auto itCqi = m_ueCqi.find(rnti);
     if (itCqi == m_ueCqi.end())
     {
         // no cqi info about this UE
@@ -1452,7 +1416,7 @@
 
     rbMap = m_ffrSapProvider->GetAvailableUlRbg();
 
-    for (std::vector<bool>::iterator it = rbMap.begin(); it != rbMap.end(); it++)
+    for (auto it = rbMap.begin(); it != rbMap.end(); it++)
     {
         if (*it)
         {
@@ -1482,8 +1446,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1491,16 +1454,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
                                  << " i " << i << " size " << params.m_ulInfoList.size());
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                     continue;
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1559,7 +1520,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
         {
@@ -1592,7 +1553,6 @@
     }
     int rbAllocated = 0;
 
-    std::map<uint16_t, tdtbfqsFlowPerf_t>::iterator itStats;
     if (m_nextRntiUl != 0)
     {
         for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
@@ -1614,7 +1574,7 @@
     }
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -1707,7 +1667,7 @@
             break;
         }
 
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -1778,15 +1738,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -1794,8 +1752,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -1849,8 +1806,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -1871,7 +1826,7 @@
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
             NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -1917,11 +1872,9 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
         NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
                           << " subframe no. " << (0xF & params.m_sfnSf));
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             return;
@@ -1930,7 +1883,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -1960,8 +1913,7 @@
                 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
                                   << sinr);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1982,8 +1934,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -2010,8 +1961,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -2031,7 +1981,7 @@
 TdTbfqFfMacScheduler::RefreshDlCqiMaps()
 {
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -2039,12 +1989,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -2056,7 +2006,7 @@
     }
 
     // refresh DL CQI A30 Map
-    std::map<uint16_t, uint32_t>::iterator itA30 = m_a30CqiTimers.begin();
+    auto itA30 = m_a30CqiTimers.begin();
     while (itA30 != m_a30CqiTimers.end())
     {
         NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
@@ -2064,12 +2014,12 @@
         if ((*itA30).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find((*itA30).first);
+            auto itMap = m_a30CqiRxed.find((*itA30).first);
             NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
                           " Does not find CQI report for user " << (*itA30).first);
             NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
             m_a30CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itA30;
+            auto temp = itA30;
             itA30++;
             m_a30CqiTimers.erase(temp);
         }
@@ -2085,7 +2035,7 @@
 TdTbfqFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -2093,13 +2043,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -2114,9 +2064,8 @@
 void
 TdTbfqFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     LteFlowId_t flow(rnti, lcid);
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
     if (it != m_rlcBufferReq.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
@@ -2171,7 +2120,7 @@
 TdTbfqFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/model/tta-ff-mac-scheduler.cc ns-3.40/src/lte/model/tta-ff-mac-scheduler.cc
--- ns-3.39/src/lte/model/tta-ff-mac-scheduler.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/model/tta-ff-mac-scheduler.cc	2023-09-27 13:30:37.826839700 -0700
@@ -158,7 +158,7 @@
 {
     NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
                          << (uint16_t)params.m_transmissionMode);
-    std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
+    auto it = m_uesTxMode.find(params.m_rnti);
     if (it == m_uesTxMode.end())
     {
         m_uesTxMode.insert(std::pair<uint16_t, double>(params.m_rnti, params.m_transmissionMode));
@@ -204,10 +204,9 @@
 {
     NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
 
-    std::set<uint16_t>::iterator it;
     for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
     {
-        it = m_flowStatsDl.find(params.m_rnti);
+        auto it = m_flowStatsDl.find(params.m_rnti);
 
         if (it == m_flowStatsDl.end())
         {
@@ -224,15 +223,13 @@
     NS_LOG_FUNCTION(this);
     for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
     {
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-            m_rlcBufferReq.begin();
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+        auto it = m_rlcBufferReq.begin();
         while (it != m_rlcBufferReq.end())
         {
             if (((*it).first.m_rnti == params.m_rnti) &&
                 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
             {
-                temp = it;
+                auto temp = it;
                 it++;
                 m_rlcBufferReq.erase(temp);
             }
@@ -262,14 +259,12 @@
     m_flowStatsDl.erase(params.m_rnti);
     m_flowStatsUl.erase(params.m_rnti);
     m_ceBsrRxed.erase(params.m_rnti);
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
-        m_rlcBufferReq.begin();
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
+    auto it = m_rlcBufferReq.begin();
     while (it != m_rlcBufferReq.end())
     {
         if ((*it).first.m_rnti == params.m_rnti)
         {
-            temp = it;
+            auto temp = it;
             it++;
             m_rlcBufferReq.erase(temp);
         }
@@ -291,11 +286,9 @@
     NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
     // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
 
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
-
     LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
 
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
 
     if (it == m_rlcBufferReq.end())
     {
@@ -342,9 +335,8 @@
 unsigned int
 TtaFfMacScheduler::LcActivePerFlow(uint16_t rnti)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     unsigned int lcActive = 0;
-    for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
+    for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
     {
         if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
                                              ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
@@ -365,13 +357,12 @@
 {
     NS_LOG_FUNCTION(this << rnti);
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -395,13 +386,12 @@
         return (0);
     }
 
-    std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
+    auto it = m_dlHarqCurrentProcessId.find(rnti);
     if (it == m_dlHarqCurrentProcessId.end())
     {
         NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
     }
-    std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-        m_dlHarqProcessesStatus.find(rnti);
+    auto itStat = m_dlHarqProcessesStatus.find(rnti);
     if (itStat == m_dlHarqProcessesStatus.end())
     {
         NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
@@ -430,8 +420,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
-    for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
+    for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
          itTimers++)
     {
         for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
@@ -441,8 +430,7 @@
                 // reset HARQ process
 
                 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
-                    m_dlHarqProcessesStatus.find((*itTimers).first);
+                auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
                 if (itStat == m_dlHarqProcessesStatus.end())
                 {
                     NS_FATAL_ERROR("No Process Id Status found for this RNTI "
@@ -482,9 +470,9 @@
     rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
     FfMacSchedSapUser::SchedDlConfigIndParameters ret;
 
-    //   update UL HARQ proc id
-    std::map<uint16_t, uint8_t>::iterator itProcId;
-    for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
+    // update UL HARQ proc id
+    for (auto itProcId = m_ulHarqCurrentProcessId.begin();
+         itProcId != m_ulHarqCurrentProcessId.end();
          itProcId++)
     {
         (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
@@ -493,8 +481,7 @@
     // RACH Allocation
     m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
     uint16_t rbStart = 0;
-    std::vector<RachListElement_s>::iterator itRach;
-    for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
+    for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
     {
         NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
                           (*itRach).m_estimatedSize,
@@ -558,15 +545,13 @@
             uldci.m_pdcchPowerOffset = 0; // not used
 
             uint8_t harqId = 0;
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -608,7 +593,7 @@
     std::vector<DlInfoListElement_s> dlInfoListUntxed;
     for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
+        auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
         if (itRnti != rntiAllocated.end())
         {
             // RNTI already allocated for retx
@@ -636,8 +621,7 @@
             uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
             uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
             NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
-                m_dlHarqProcessesDciBuffer.find(rnti);
+            auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
             if (itHarq == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
@@ -658,16 +642,14 @@
             {
                 // maximum number of retx reached -> drop process
                 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
-                std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                    m_dlHarqProcessesStatus.find(rnti);
+                auto it = m_dlHarqProcessesStatus.find(rnti);
                 if (it == m_dlHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
                                  << m_dlInfoListBuffered.at(i).m_rnti);
                 }
                 (*it).second.at(harqId) = 0;
-                std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                    m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+                auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
                 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                 {
                     NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -754,8 +736,7 @@
             }
             // retrieve RLC PDU list for retx TBsize and update DCI
             BuildDataListElement_s newEl;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                m_dlHarqProcessesRlcPduListBuffer.find(rnti);
+            auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
@@ -832,8 +813,7 @@
             newEl.m_dci = dci;
             (*itHarq).second.at(harqId).m_rv = dci.m_rv;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
@@ -846,15 +826,14 @@
         {
             // update HARQ process status
             NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
-            std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
-                m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
+            auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (it == m_dlHarqProcessesStatus.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
                                << m_dlInfoListBuffered.at(i).m_rnti);
             }
             (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
-            std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
+            auto itRlcPdu =
                 m_dlHarqProcessesRlcPduListBuffer.find(m_dlInfoListBuffered.at(i).m_rnti);
             if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
             {
@@ -885,12 +864,11 @@
         NS_LOG_INFO(this << " ALLOCATION for RBG " << i << " of " << rbgNum);
         if (!rbgMap.at(i))
         {
-            std::set<uint16_t>::iterator it;
-            std::set<uint16_t>::iterator itMax = m_flowStatsDl.end();
+            auto itMax = m_flowStatsDl.end();
             double rcqiMax = 0.0;
-            for (it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
+            for (auto it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
             {
-                std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it));
+                auto itRnti = rntiAllocated.find((*it));
                 if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*it))))
                 {
                     // UE already allocated for HARQ or without HARQ process available -> drop it
@@ -905,13 +883,10 @@
                     continue;
                 }
 
-                std::map<uint16_t, SbMeasResult_s>::iterator itSbCqi;
-                itSbCqi = m_a30CqiRxed.find((*it));
-                std::map<uint16_t, uint8_t>::iterator itWbCqi;
-                itWbCqi = m_p10CqiRxed.find((*it));
+                auto itSbCqi = m_a30CqiRxed.find((*it));
+                auto itWbCqi = m_p10CqiRxed.find((*it));
 
-                std::map<uint16_t, uint8_t>::iterator itTxMode;
-                itTxMode = m_uesTxMode.find((*it));
+                auto itTxMode = m_uesTxMode.find((*it));
                 if (itTxMode == m_uesTxMode.end())
                 {
                     NS_FATAL_ERROR("No Transmission Mode info on user " << (*it));
@@ -921,10 +896,7 @@
                 std::vector<uint8_t> sbCqi;
                 if (itSbCqi == m_a30CqiRxed.end())
                 {
-                    for (uint8_t k = 0; k < nLayer; k++)
-                    {
-                        sbCqi.push_back(1); // start with lowest value
-                    }
+                    sbCqi = std::vector<uint8_t>(nLayer, 1); // start with lowest value
                 }
                 else
                 {
@@ -995,8 +967,7 @@
             else
             {
                 rbgMap.at(i) = true;
-                std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-                itMap = allocationMap.find((*itMax));
+                auto itMap = allocationMap.find((*itMax));
                 if (itMap == allocationMap.end())
                 {
                     // insert new element
@@ -1016,7 +987,7 @@
 
     // generate the transmission opportunities by grouping the RBGs of the same RNTI and
     // creating the correspondent DCIs
-    std::map<uint16_t, std::vector<uint16_t>>::iterator itMap = allocationMap.begin();
+    auto itMap = allocationMap.begin();
     while (itMap != allocationMap.end())
     {
         // create new BuildDataListElement_s for this LC
@@ -1035,10 +1006,8 @@
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
         uint16_t RgbPerRnti = (*itMap).second.size();
-        std::map<uint16_t, SbMeasResult_s>::iterator itCqi;
-        itCqi = m_a30CqiRxed.find((*itMap).first);
-        std::map<uint16_t, uint8_t>::iterator itTxMode;
-        itTxMode = m_uesTxMode.find((*itMap).first);
+        auto itCqi = m_a30CqiRxed.find((*itMap).first);
+        auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
         {
             NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
@@ -1121,9 +1090,7 @@
         newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
 
         // create the rlc PDUs -> equally divide resources among actives LCs
-        std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
-            itBufReq;
-        for (itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
+        for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
         {
             if (((*itBufReq).first.m_rnti == (*itMap).first) &&
                 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
@@ -1145,8 +1112,7 @@
                     if (m_harqOn)
                     {
                         // store RLC PDU list for HARQ
-                        std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
-                            m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
+                        auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
                         if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
                         {
                             NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
@@ -1175,8 +1141,7 @@
         if (m_harqOn)
         {
             // store DCI for HARQ
-            std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
+            auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
             if (itDci == m_dlHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
@@ -1184,8 +1149,7 @@
             }
             (*itDci).second.at(newDci.m_harqProcess) = newDci;
             // refresh timer
-            std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
-                m_dlHarqProcessesTimer.find(newEl.m_rnti);
+            auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
             if (itHarqTimer == m_dlHarqProcessesTimer.end())
             {
                 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
@@ -1225,9 +1189,8 @@
         {
             NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
                                          << " reported");
-            std::map<uint16_t, uint8_t>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_p10CqiRxed.find(rnti);
+            auto it = m_p10CqiRxed.find(rnti);
             if (it == m_p10CqiRxed.end())
             {
                 // create the new entry
@@ -1242,17 +1205,15 @@
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
                 // update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_p10CqiTimers.find(rnti);
+                auto itTimers = m_p10CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
         else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
         {
             // subband CQI reporting high layer configured
-            std::map<uint16_t, SbMeasResult_s>::iterator it;
             uint16_t rnti = params.m_cqiList.at(i).m_rnti;
-            it = m_a30CqiRxed.find(rnti);
+            auto it = m_a30CqiRxed.find(rnti);
             if (it == m_a30CqiRxed.end())
             {
                 // create the new entry
@@ -1265,8 +1226,7 @@
             {
                 // update the CQI value and refresh correspondent timer
                 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_a30CqiTimers.find(rnti);
+                auto itTimers = m_a30CqiTimers.find(rnti);
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1280,7 +1240,7 @@
 double
 TtaFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
 {
-    std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find(rnti);
+    auto itCqi = m_ueCqi.find(rnti);
     if (itCqi == m_ueCqi.end())
     {
         // no cqi info about this UE
@@ -1347,8 +1307,7 @@
             {
                 // retx correspondent block: retrieve the UL-DCI
                 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
-                std::map<uint16_t, uint8_t>::iterator itProcId =
-                    m_ulHarqCurrentProcessId.find(rnti);
+                auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
                 if (itProcId == m_ulHarqCurrentProcessId.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1356,16 +1315,14 @@
                 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
                 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
                                  << " i " << i << " size " << params.m_ulInfoList.size());
-                std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq =
-                    m_ulHarqProcessesDciBuffer.find(rnti);
+                auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
                 if (itHarq == m_ulHarqProcessesDciBuffer.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                     continue;
                 }
                 UlDciListElement_s dci = (*itHarq).second.at(harqId);
-                std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                    m_ulHarqProcessesStatus.find(rnti);
+                auto itStat = m_ulHarqProcessesStatus.find(rnti);
                 if (itStat == m_ulHarqProcessesStatus.end())
                 {
                     NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
@@ -1423,7 +1380,7 @@
 
     for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         // select UEs with queues not empty and not yet allocated for HARQ
         if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
         {
@@ -1474,7 +1431,7 @@
     }
     do
     {
-        std::set<uint16_t>::iterator itRnti = rntiAllocated.find((*it).first);
+        auto itRnti = rntiAllocated.find((*it).first);
         if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
         {
             // UE already allocated for UL-HARQ -> skip it
@@ -1559,7 +1516,7 @@
             return;
         }
 
-        std::map<uint16_t, std::vector<double>>::iterator itCqi = m_ueCqi.find((*it).first);
+        auto itCqi = m_ueCqi.find((*it).first);
         int cqi = 0;
         if (itCqi == m_ueCqi.end())
         {
@@ -1630,15 +1587,13 @@
         uint8_t harqId = 0;
         if (m_harqOn)
         {
-            std::map<uint16_t, uint8_t>::iterator itProcId;
-            itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
+            auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
             if (itProcId == m_ulHarqCurrentProcessId.end())
             {
                 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
             }
             harqId = (*itProcId).second;
-            std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
-                m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
+            auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
             if (itDci == m_ulHarqProcessesDciBuffer.end())
             {
                 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
@@ -1646,8 +1601,7 @@
             }
             (*itDci).second.at(harqId) = uldci;
             // Update HARQ process status (RV 0)
-            std::map<uint16_t, UlHarqProcessesStatus_t>::iterator itStat =
-                m_ulHarqProcessesStatus.find(uldci.m_rnti);
+            auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
             if (itStat == m_ulHarqProcessesStatus.end())
             {
                 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
@@ -1701,8 +1655,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, uint32_t>::iterator it;
-
     for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
     {
         if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
@@ -1723,7 +1675,7 @@
 
             uint16_t rnti = params.m_macCeList.at(i).m_rnti;
             NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
-            it = m_ceBsrRxed.find(rnti);
+            auto it = m_ceBsrRxed.find(rnti);
             if (it == m_ceBsrRxed.end())
             {
                 // create the new entry
@@ -1769,11 +1721,9 @@
     switch (params.m_ulCqi.m_type)
     {
     case UlCqi_s::PUSCH: {
-        std::map<uint16_t, std::vector<uint16_t>>::iterator itMap;
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
         NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
                           << " subframe no. " << (0xF & params.m_sfnSf));
-        itMap = m_allocationMaps.find(params.m_sfnSf);
+        auto itMap = m_allocationMaps.find(params.m_sfnSf);
         if (itMap == m_allocationMaps.end())
         {
             return;
@@ -1782,7 +1732,7 @@
         {
             // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
             double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
-            itCqi = m_ueCqi.find((*itMap).second.at(i));
+            auto itCqi = m_ueCqi.find((*itMap).second.at(i));
             if (itCqi == m_ueCqi.end())
             {
                 // create a new entry
@@ -1812,8 +1762,7 @@
                 // NS_LOG_DEBUG (this << " RNTI " << (*itMap).second.at (i) << " RB " << i << " SINR
                 // " << sinr);
                 //  update correspondent timer
-                std::map<uint16_t, uint32_t>::iterator itTimers;
-                itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
+                auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
                 (*itTimers).second = m_cqiTimersThreshold;
             }
         }
@@ -1834,8 +1783,7 @@
                 rnti = vsp->GetRnti();
             }
         }
-        std::map<uint16_t, std::vector<double>>::iterator itCqi;
-        itCqi = m_ueCqi.find(rnti);
+        auto itCqi = m_ueCqi.find(rnti);
         if (itCqi == m_ueCqi.end())
         {
             // create a new entry
@@ -1862,8 +1810,7 @@
                                  << sinr);
             }
             // update correspondent timer
-            std::map<uint16_t, uint32_t>::iterator itTimers;
-            itTimers = m_ueCqiTimers.find(rnti);
+            auto itTimers = m_ueCqiTimers.find(rnti);
             (*itTimers).second = m_cqiTimersThreshold;
         }
     }
@@ -1883,7 +1830,7 @@
 TtaFfMacScheduler::RefreshDlCqiMaps()
 {
     // refresh DL CQI P01 Map
-    std::map<uint16_t, uint32_t>::iterator itP10 = m_p10CqiTimers.begin();
+    auto itP10 = m_p10CqiTimers.begin();
     while (itP10 != m_p10CqiTimers.end())
     {
         NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
@@ -1891,12 +1838,12 @@
         if ((*itP10).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, uint8_t>::iterator itMap = m_p10CqiRxed.find((*itP10).first);
+            auto itMap = m_p10CqiRxed.find((*itP10).first);
             NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
                           " Does not find CQI report for user " << (*itP10).first);
             NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
             m_p10CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itP10;
+            auto temp = itP10;
             itP10++;
             m_p10CqiTimers.erase(temp);
         }
@@ -1908,7 +1855,7 @@
     }
 
     // refresh DL CQI A30 Map
-    std::map<uint16_t, uint32_t>::iterator itA30 = m_a30CqiTimers.begin();
+    auto itA30 = m_a30CqiTimers.begin();
     while (itA30 != m_a30CqiTimers.end())
     {
         NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
@@ -1916,12 +1863,12 @@
         if ((*itA30).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find((*itA30).first);
+            auto itMap = m_a30CqiRxed.find((*itA30).first);
             NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
                           " Does not find CQI report for user " << (*itA30).first);
             NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
             m_a30CqiRxed.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itA30;
+            auto temp = itA30;
             itA30++;
             m_a30CqiTimers.erase(temp);
         }
@@ -1937,7 +1884,7 @@
 TtaFfMacScheduler::RefreshUlCqiMaps()
 {
     // refresh UL CQI  Map
-    std::map<uint16_t, uint32_t>::iterator itUl = m_ueCqiTimers.begin();
+    auto itUl = m_ueCqiTimers.begin();
     while (itUl != m_ueCqiTimers.end())
     {
         NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
@@ -1945,13 +1892,13 @@
         if ((*itUl).second == 0)
         {
             // delete correspondent entries
-            std::map<uint16_t, std::vector<double>>::iterator itMap = m_ueCqi.find((*itUl).first);
+            auto itMap = m_ueCqi.find((*itUl).first);
             NS_ASSERT_MSG(itMap != m_ueCqi.end(),
                           " Does not find CQI report for user " << (*itUl).first);
             NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
             (*itMap).second.clear();
             m_ueCqi.erase(itMap);
-            std::map<uint16_t, uint32_t>::iterator temp = itUl;
+            auto temp = itUl;
             itUl++;
             m_ueCqiTimers.erase(temp);
         }
@@ -1966,9 +1913,8 @@
 void
 TtaFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
 {
-    std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
     LteFlowId_t flow(rnti, lcid);
-    it = m_rlcBufferReq.find(flow);
+    auto it = m_rlcBufferReq.find(flow);
     if (it != m_rlcBufferReq.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
@@ -2023,7 +1969,7 @@
 TtaFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
 {
     size = size - 2; // remove the minimum RLC overhead
-    std::map<uint16_t, uint32_t>::iterator it = m_ceBsrRxed.find(rnti);
+    auto it = m_ceBsrRxed.find(rnti);
     if (it != m_ceBsrRxed.end())
     {
         NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/epc-test-gtpu.cc ns-3.40/src/lte/test/epc-test-gtpu.cc
--- ns-3.39/src/lte/test/epc-test-gtpu.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/test/epc-test-gtpu.cc	2023-09-27 13:30:37.826839700 -0700
@@ -57,7 +57,7 @@
 void
 EpsGtpuHeaderTestCase::DoRun()
 {
-    LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
+    auto logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
 
     LogComponentEnable("EpcGtpuTest", logLevel);
     GtpuHeader h1;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/epc-test-s1u-downlink.cc ns-3.40/src/lte/test/epc-test-s1u-downlink.cc
--- ns-3.39/src/lte/test/epc-test-s1u-downlink.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/test/epc-test-s1u-downlink.cc	2023-09-27 13:30:37.826839700 -0700
@@ -154,9 +154,7 @@
     uint16_t cellIdCounter = 0;
     uint64_t imsiCounter = 0;
 
-    for (std::vector<EnbDlTestData>::iterator enbit = m_enbDlTestData.begin();
-         enbit < m_enbDlTestData.end();
-         ++enbit)
+    for (auto enbit = m_enbDlTestData.begin(); enbit < m_enbDlTestData.end(); ++enbit)
     {
         Ptr<Node> enb = CreateObject<Node>();
         enbs.Add(enb);
@@ -245,12 +243,9 @@
 
     Simulator::Run();
 
-    for (std::vector<EnbDlTestData>::iterator enbit = m_enbDlTestData.begin();
-         enbit < m_enbDlTestData.end();
-         ++enbit)
+    for (auto enbit = m_enbDlTestData.begin(); enbit < m_enbDlTestData.end(); ++enbit)
     {
-        for (std::vector<UeDlTestData>::iterator ueit = enbit->ues.begin(); ueit < enbit->ues.end();
-             ++ueit)
+        for (auto ueit = enbit->ues.begin(); ueit < enbit->ues.end(); ++ueit)
         {
             NS_TEST_ASSERT_MSG_EQ(ueit->serverApp->GetTotalRx(),
                                   (ueit->numPkts) * (ueit->pktSize),
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/epc-test-s1u-uplink.cc ns-3.40/src/lte/test/epc-test-s1u-uplink.cc
--- ns-3.39/src/lte/test/epc-test-s1u-uplink.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/test/epc-test-s1u-uplink.cc	2023-09-27 13:30:37.826839700 -0700
@@ -366,9 +366,7 @@
     uint16_t cellIdCounter = 0;
     uint64_t imsiCounter = 0;
 
-    for (std::vector<EnbUlTestData>::iterator enbit = m_enbUlTestData.begin();
-         enbit < m_enbUlTestData.end();
-         ++enbit)
+    for (auto enbit = m_enbUlTestData.begin(); enbit < m_enbUlTestData.end(); ++enbit)
     {
         Ptr<Node> enb = CreateObject<Node>();
         enbs.Add(enb);
@@ -486,12 +484,9 @@
 
     Simulator::Run();
 
-    for (std::vector<EnbUlTestData>::iterator enbit = m_enbUlTestData.begin();
-         enbit < m_enbUlTestData.end();
-         ++enbit)
+    for (auto enbit = m_enbUlTestData.begin(); enbit < m_enbUlTestData.end(); ++enbit)
     {
-        for (std::vector<UeUlTestData>::iterator ueit = enbit->ues.begin(); ueit < enbit->ues.end();
-             ++ueit)
+        for (auto ueit = enbit->ues.begin(); ueit < enbit->ues.end(); ++ueit)
         {
             NS_TEST_ASSERT_MSG_EQ(ueit->serverApp->GetTotalRx(),
                                   (ueit->numPkts) * (ueit->pktSize),
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-ffr-simple.cc ns-3.40/src/lte/test/lte-ffr-simple.cc
--- ns-3.39/src/lte/test/lte-ffr-simple.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/test/lte-ffr-simple.cc	2023-09-27 13:30:37.826839700 -0700
@@ -279,9 +279,7 @@
 {
     NS_LOG_FUNCTION(this << rnti << (uint16_t)measResults.measId);
 
-    std::map<uint16_t, LteRrcSap::PdschConfigDedicated>::iterator it;
-
-    it = m_ues.find(rnti);
+    auto it = m_ues.find(rnti);
 
     if (it == m_ues.end())
     {
@@ -302,8 +300,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::map<uint16_t, LteRrcSap::PdschConfigDedicated>::iterator it;
-    for (it = m_ues.begin(); it != m_ues.end(); it++)
+    for (auto it = m_ues.begin(); it != m_ues.end(); it++)
     {
         if (it->second.pa != m_pdschConfigDedicated.pa)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-simple-helper.cc ns-3.40/src/lte/test/lte-simple-helper.cc
--- ns-3.39/src/lte/test/lte-simple-helper.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/test/lte-simple-helper.cc	2023-09-27 13:30:37.826839700 -0700
@@ -91,7 +91,7 @@
     NS_LOG_FUNCTION(this);
     Initialize(); // will run DoInitialize () if necessary
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<NetDevice> device = InstallSingleEnbDevice(node);
@@ -105,7 +105,7 @@
 {
     NS_LOG_FUNCTION(this);
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<NetDevice> device = InstallSingleUeDevice(node);
@@ -209,8 +209,7 @@
 void
 LteSimpleHelper::EnableLogComponents()
 {
-    LogLevel level =
-        (LogLevel)(LOG_LEVEL_ALL | LOG_PREFIX_TIME | LOG_PREFIX_NODE | LOG_PREFIX_FUNC);
+    auto level = (LogLevel)(LOG_LEVEL_ALL | LOG_PREFIX_TIME | LOG_PREFIX_NODE | LOG_PREFIX_FUNC);
 
     LogComponentEnable("Config", level);
     LogComponentEnable("LteSimpleHelper", level);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-carrier-aggregation.cc ns-3.40/src/lte/test/lte-test-carrier-aggregation.cc
--- ns-3.39/src/lte/test/lte-test-carrier-aggregation.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/test/lte-test-carrier-aggregation.cc	2023-09-27 13:30:37.826839700 -0700
@@ -425,8 +425,7 @@
 
     bool testDownlinkShare = true;
 
-    for (std::map<uint8_t, uint32_t>::iterator itDownlink = m_ccDownlinkTraffic.begin();
-         itDownlink != m_ccDownlinkTraffic.end();
+    for (auto itDownlink = m_ccDownlinkTraffic.begin(); itDownlink != m_ccDownlinkTraffic.end();
          itDownlink++)
     {
         if (itDownlink == m_ccDownlinkTraffic.begin())
@@ -445,9 +444,7 @@
 
     bool testUplinkShare = true;
 
-    for (std::map<uint8_t, uint32_t>::iterator itUplink = m_ccUplinkTraffic.begin();
-         itUplink != m_ccUplinkTraffic.end();
-         itUplink++)
+    for (auto itUplink = m_ccUplinkTraffic.begin(); itUplink != m_ccUplinkTraffic.end(); itUplink++)
     {
         if (itUplink == m_ccUplinkTraffic.begin())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-cell-selection.cc ns-3.40/src/lte/test/lte-test-cell-selection.cc
--- ns-3.39/src/lte/test/lte-test-cell-selection.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/test/lte-test-cell-selection.cc	2023-09-27 13:30:37.826839700 -0700
@@ -185,7 +185,7 @@
     NodeContainer enbNodes;
     enbNodes.Create(4);
     NodeContainer ueNodes;
-    uint16_t nUe = static_cast<uint16_t>(m_ueSetupList.size());
+    auto nUe = static_cast<uint16_t>(m_ueSetupList.size());
     ueNodes.Create(nUe);
 
     // Assign nodes to position
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-cqa-ff-mac-scheduler.cc ns-3.40/src/lte/test/lte-test-cqa-ff-mac-scheduler.cc
--- ns-3.39/src/lte/test/lte-test-cqa-ff-mac-scheduler.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/test/lte-test-cqa-ff-mac-scheduler.cc	2023-09-27 13:30:37.826839700 -0700
@@ -23,15 +23,16 @@
 
 #include "lte-test-cqa-ff-mac-scheduler.h"
 
-#include "ns3/applications-module.h"
 #include "ns3/double.h"
 #include "ns3/internet-module.h"
 #include "ns3/ipv4-global-routing-helper.h"
 #include "ns3/network-module.h"
+#include "ns3/packet-sink-helper.h"
 #include "ns3/point-to-point-epc-helper.h"
 #include "ns3/point-to-point-helper.h"
 #include "ns3/radio-bearer-stats-calculator.h"
 #include "ns3/string.h"
+#include "ns3/udp-client-server-helper.h"
 #include <ns3/boolean.h>
 #include <ns3/constant-position-mobility-model.h>
 #include <ns3/enum.h>
@@ -541,7 +542,7 @@
 {
     std::ostringstream oss;
     oss << "distances (m) = [ ";
-    for (std::vector<double>::iterator it = dist.begin(); it != dist.end(); ++it)
+    for (auto it = dist.begin(); it != dist.end(); ++it)
     {
         oss << *it << " ";
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-deactivate-bearer.cc ns-3.40/src/lte/test/lte-test-deactivate-bearer.cc
--- ns-3.39/src/lte/test/lte-test-deactivate-bearer.cc	2023-07-05 14:23:48.017428200 -0700
+++ ns-3.40/src/lte/test/lte-test-deactivate-bearer.cc	2023-09-27 13:30:37.826839700 -0700
@@ -19,15 +19,16 @@
 
 #include "lte-test-deactivate-bearer.h"
 
-#include "ns3/applications-module.h"
 #include "ns3/double.h"
 #include "ns3/internet-module.h"
 #include "ns3/ipv4-global-routing-helper.h"
 #include "ns3/network-module.h"
+#include "ns3/packet-sink-helper.h"
 #include "ns3/point-to-point-epc-helper.h"
 #include "ns3/point-to-point-helper.h"
 #include "ns3/radio-bearer-stats-calculator.h"
 #include "ns3/string.h"
+#include "ns3/udp-client-server-helper.h"
 #include <ns3/boolean.h>
 #include <ns3/constant-position-mobility-model.h>
 #include <ns3/enum.h>
@@ -108,7 +109,7 @@
 {
     std::ostringstream oss;
     oss << "distances (m) = [ ";
-    for (std::vector<uint16_t>::iterator it = dist.begin(); it != dist.end(); ++it)
+    for (auto it = dist.begin(); it != dist.end(); ++it)
     {
         oss << *it << " ";
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-entities.cc ns-3.40/src/lte/test/lte-test-entities.cc
--- ns-3.39/src/lte/test/lte-test-entities.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-entities.cc	2023-09-27 13:30:37.826839700 -0700
@@ -162,7 +162,7 @@
     //   NS_LOG_LOGIC ("PDU received = " << (*p));
 
     uint32_t dataLen = p->GetSize();
-    uint8_t* buf = new uint8_t[dataLen];
+    auto buf = new uint8_t[dataLen];
 
     // Stats
     m_rxPdus++;
@@ -312,7 +312,7 @@
     NS_LOG_LOGIC("Data = " << (*p));
 
     uint32_t dataLen = p->GetSize();
-    uint8_t* buf = new uint8_t[dataLen];
+    auto buf = new uint8_t[dataLen];
     p->CopyData(buf, dataLen);
     m_receivedData = std::string((char*)buf, dataLen);
 
@@ -606,7 +606,7 @@
 
         // Copy data to a string
         uint32_t dataLen = params.pdu->GetSize();
-        uint8_t* buf = new uint8_t[dataLen];
+        auto buf = new uint8_t[dataLen];
         params.pdu->CopyData(buf, dataLen);
         m_receivedData = std::string((char*)buf, dataLen);
 
@@ -623,8 +623,7 @@
     if (m_txOpportunityMode == AUTOMATIC_MODE)
     {
         // cancel all previously scheduled TxOpps
-        for (std::list<EventId>::iterator it = m_nextTxOppList.begin(); it != m_nextTxOppList.end();
-             ++it)
+        for (auto it = m_nextTxOppList.begin(); it != m_nextTxOppList.end(); ++it)
         {
             it->Cancel();
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-fdbet-ff-mac-scheduler.cc ns-3.40/src/lte/test/lte-test-fdbet-ff-mac-scheduler.cc
--- ns-3.39/src/lte/test/lte-test-fdbet-ff-mac-scheduler.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-fdbet-ff-mac-scheduler.cc	2023-09-27 13:30:37.826839700 -0700
@@ -383,7 +383,7 @@
 {
     std::ostringstream oss;
     oss << "distances (m) = [ ";
-    for (std::vector<double>::iterator it = dist.begin(); it != dist.end(); ++it)
+    for (auto it = dist.begin(); it != dist.end(); ++it)
     {
         oss << *it << " ";
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-fdtbfq-ff-mac-scheduler.cc ns-3.40/src/lte/test/lte-test-fdtbfq-ff-mac-scheduler.cc
--- ns-3.39/src/lte/test/lte-test-fdtbfq-ff-mac-scheduler.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-fdtbfq-ff-mac-scheduler.cc	2023-09-27 13:30:37.826839700 -0700
@@ -21,15 +21,16 @@
 
 #include "lte-test-fdtbfq-ff-mac-scheduler.h"
 
-#include "ns3/applications-module.h"
 #include "ns3/double.h"
 #include "ns3/internet-module.h"
 #include "ns3/ipv4-global-routing-helper.h"
 #include "ns3/network-module.h"
+#include "ns3/packet-sink-helper.h"
 #include "ns3/point-to-point-epc-helper.h"
 #include "ns3/point-to-point-helper.h"
 #include "ns3/radio-bearer-stats-calculator.h"
 #include "ns3/string.h"
+#include "ns3/udp-client-server-helper.h"
 #include <ns3/boolean.h>
 #include <ns3/constant-position-mobility-model.h>
 #include <ns3/enum.h>
@@ -547,7 +548,7 @@
 {
     std::ostringstream oss;
     oss << "distances (m) = [ ";
-    for (std::vector<double>::iterator it = dist.begin(); it != dist.end(); ++it)
+    for (auto it = dist.begin(); it != dist.end(); ++it)
     {
         oss << *it << " ";
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-frequency-reuse.cc ns-3.40/src/lte/test/lte-test-frequency-reuse.cc
--- ns-3.39/src/lte/test/lte-test-frequency-reuse.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-frequency-reuse.cc	2023-09-27 13:30:37.826839700 -0700
@@ -23,12 +23,13 @@
 #include "lte-ffr-simple.h"
 #include "lte-simple-spectrum-phy.h"
 
-#include "ns3/applications-module.h"
 #include "ns3/internet-module.h"
 #include "ns3/lte-helper.h"
 #include "ns3/mobility-helper.h"
+#include "ns3/packet-sink-helper.h"
 #include "ns3/point-to-point-epc-helper.h"
 #include "ns3/point-to-point-module.h"
+#include "ns3/udp-client-server-helper.h"
 #include <ns3/boolean.h>
 #include <ns3/callback.h>
 #include <ns3/config.h>
@@ -479,9 +480,8 @@
 LteFrTestCase::DlDataRxStart(Ptr<const SpectrumValue> spectrumValue)
 {
     NS_LOG_DEBUG("DL DATA Power allocation :");
-    Values::const_iterator it;
     uint32_t i = 0;
-    for (it = spectrumValue->ConstValuesBegin(); it != spectrumValue->ConstValuesEnd(); it++)
+    for (auto it = spectrumValue->ConstValuesBegin(); it != spectrumValue->ConstValuesEnd(); it++)
     {
         double power = (*it) * (m_dlBandwidth * 180000);
         NS_LOG_DEBUG("RB " << i << " POWER: "
@@ -499,9 +499,8 @@
 LteFrTestCase::UlDataRxStart(Ptr<const SpectrumValue> spectrumValue)
 {
     NS_LOG_DEBUG("UL DATA Power allocation :");
-    Values::const_iterator it;
     uint32_t i = 0;
-    for (it = spectrumValue->ConstValuesBegin(); it != spectrumValue->ConstValuesEnd(); it++)
+    for (auto it = spectrumValue->ConstValuesBegin(); it != spectrumValue->ConstValuesEnd(); it++)
     {
         double power = (*it) * (m_ulBandwidth * 180000);
         NS_LOG_DEBUG("RB " << i << " POWER: "
@@ -821,9 +820,8 @@
     }
 
     NS_LOG_DEBUG("DL DATA Power allocation :");
-    Values::const_iterator it;
     uint32_t i = 0;
-    for (it = spectrumValue->ConstValuesBegin(); it != spectrumValue->ConstValuesEnd(); it++)
+    for (auto it = spectrumValue->ConstValuesBegin(); it != spectrumValue->ConstValuesEnd(); it++)
     {
         double power = (*it) * (m_dlBandwidth * 180000);
         NS_LOG_DEBUG("RB " << i << " POWER: "
@@ -857,7 +855,6 @@
     }
 
     NS_LOG_DEBUG("UL DATA Power allocation :");
-    Values::const_iterator it;
     uint32_t i = 0;
     uint32_t numActiveRbs = 0;
 
@@ -865,7 +862,7 @@
     // of active RBs. This method is independent of the bandwidth
     // configuration done in a test scenario, thus, it requires
     // minimum change to the script.
-    for (it = spectrumValue->ConstValuesBegin(); it != spectrumValue->ConstValuesEnd(); it++)
+    for (auto it = spectrumValue->ConstValuesBegin(); it != spectrumValue->ConstValuesEnd(); it++)
     {
         // Count the RB as active if it is part of
         // the expected UL RBs and has Power Spectral Density (PSD) > 0
@@ -878,7 +875,7 @@
 
     // The uplink power control and the uplink PSD
     // calculation only consider active resource blocks.
-    for (it = spectrumValue->ConstValuesBegin(); it != spectrumValue->ConstValuesEnd(); it++)
+    for (auto it = spectrumValue->ConstValuesBegin(); it != spectrumValue->ConstValuesEnd(); it++)
     {
         double power = (*it) * (numActiveRbs * 180000);
         NS_LOG_DEBUG("RB " << i << " POWER: " << power
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-ipv6-routing.cc ns-3.40/src/lte/test/lte-test-ipv6-routing.cc
--- ns-3.39/src/lte/test/lte-test-ipv6-routing.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-ipv6-routing.cc	2023-09-27 13:30:37.830839600 -0700
@@ -17,7 +17,6 @@
  * Author: Manoj Kumar Rana <manoj24.rana@gmail.com>
  */
 
-#include "ns3/applications-module.h"
 #include "ns3/config-store.h"
 #include "ns3/core-module.h"
 #include "ns3/epc-helper.h"
@@ -29,6 +28,7 @@
 #include "ns3/mobility-module.h"
 #include "ns3/network-module.h"
 #include "ns3/point-to-point-helper.h"
+#include "ns3/udp-echo-helper.h"
 
 #include <algorithm>
 
@@ -164,8 +164,7 @@
     bool b = false;
     bool check = true;
     // Extract each received reply packet of the client
-    for (std::list<Ptr<Packet>>::iterator it1 = m_clientRxPkts.begin(); it1 != m_clientRxPkts.end();
-         it1++)
+    for (auto it1 = m_clientRxPkts.begin(); it1 != m_clientRxPkts.end(); it1++)
     {
         Ipv6Header ipv6header1;
         UdpHeader udpHeader1;
@@ -174,9 +173,7 @@
         uint64_t uid = p1->GetUid();
         p1->RemoveHeader(udpHeader1);
         // Search each packet in list of sent request packet of the client
-        for (std::list<Ptr<Packet>>::iterator it2 = m_clientTxPkts.begin();
-             it2 != m_clientTxPkts.end();
-             it2++)
+        for (auto it2 = m_clientTxPkts.begin(); it2 != m_clientTxPkts.end(); it2++)
         {
             Ptr<Packet> p2 = (*it2)->Copy();
             Ipv6Header ipv6header2;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-pf-ff-mac-scheduler.cc ns-3.40/src/lte/test/lte-test-pf-ff-mac-scheduler.cc
--- ns-3.39/src/lte/test/lte-test-pf-ff-mac-scheduler.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-pf-ff-mac-scheduler.cc	2023-09-27 13:30:37.830839600 -0700
@@ -399,7 +399,7 @@
 {
     std::ostringstream oss;
     oss << "distances (m) = [ ";
-    for (std::vector<double>::iterator it = dist.begin(); it != dist.end(); ++it)
+    for (auto it = dist.begin(); it != dist.end(); ++it)
     {
         oss << *it << " ";
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-phy-error-model.cc ns-3.40/src/lte/test/lte-test-phy-error-model.cc
--- ns-3.39/src/lte/test/lte-test-phy-error-model.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-phy-error-model.cc	2023-09-27 13:30:37.830839600 -0700
@@ -260,7 +260,7 @@
 
         // sanity check for whether the tx packets reported by the stats are correct
         // we expect one packet per TTI
-        double expectedDlTxPackets = static_cast<double>(statsDuration.GetMilliSeconds());
+        auto expectedDlTxPackets = static_cast<double>(statsDuration.GetMilliSeconds());
         NS_TEST_ASSERT_MSG_EQ_TOL(dlTxPackets,
                                   expectedDlTxPackets,
                                   expectedDlTxPackets * 0.005,
@@ -422,7 +422,7 @@
 
         // sanity check for whether the tx packets reported by the stats are correct
         // we expect one packet per TTI
-        double expectedDlTxPackets = static_cast<double>(statsDuration.GetMilliSeconds());
+        auto expectedDlTxPackets = static_cast<double>(statsDuration.GetMilliSeconds());
         NS_TEST_ASSERT_MSG_EQ_TOL(dlTxPackets,
                                   expectedDlTxPackets,
                                   expectedDlTxPackets * 0.005,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-pss-ff-mac-scheduler.cc ns-3.40/src/lte/test/lte-test-pss-ff-mac-scheduler.cc
--- ns-3.39/src/lte/test/lte-test-pss-ff-mac-scheduler.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-pss-ff-mac-scheduler.cc	2023-09-27 13:30:37.830839600 -0700
@@ -21,15 +21,16 @@
 
 #include "lte-test-pss-ff-mac-scheduler.h"
 
-#include "ns3/applications-module.h"
 #include "ns3/double.h"
 #include "ns3/internet-module.h"
 #include "ns3/ipv4-global-routing-helper.h"
 #include "ns3/network-module.h"
+#include "ns3/packet-sink-helper.h"
 #include "ns3/point-to-point-epc-helper.h"
 #include "ns3/point-to-point-helper.h"
 #include "ns3/radio-bearer-stats-calculator.h"
 #include "ns3/string.h"
+#include "ns3/udp-client-server-helper.h"
 #include <ns3/boolean.h>
 #include <ns3/constant-position-mobility-model.h>
 #include <ns3/enum.h>
@@ -543,7 +544,7 @@
 {
     std::ostringstream oss;
     oss << "distances (m) = [ ";
-    for (std::vector<double>::iterator it = dist.begin(); it != dist.end(); ++it)
+    for (auto it = dist.begin(); it != dist.end(); ++it)
     {
         oss << *it << " ";
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-radio-link-failure.cc ns-3.40/src/lte/test/lte-test-radio-link-failure.cc
--- ns-3.39/src/lte/test/lte-test-radio-link-failure.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-radio-link-failure.cc	2023-09-27 13:30:37.830839600 -0700
@@ -24,7 +24,6 @@
 
 #include "lte-test-radio-link-failure.h"
 
-#include "ns3/applications-module.h"
 #include "ns3/config-store-module.h"
 #include "ns3/config-store.h"
 #include "ns3/core-module.h"
@@ -32,7 +31,9 @@
 #include "ns3/lte-module.h"
 #include "ns3/mobility-module.h"
 #include "ns3/network-module.h"
+#include "ns3/packet-sink-helper.h"
 #include "ns3/point-to-point-module.h"
+#include "ns3/udp-client-server-helper.h"
 
 #include <iomanip>
 #include <iostream>
@@ -281,9 +282,7 @@
     // Mobility
     Ptr<ListPositionAllocator> positionAllocEnb = CreateObject<ListPositionAllocator>();
 
-    for (std::vector<Vector>::iterator enbPosIt = m_enbPositionList.begin();
-         enbPosIt != m_enbPositionList.end();
-         ++enbPosIt)
+    for (auto enbPosIt = m_enbPositionList.begin(); enbPosIt != m_enbPositionList.end(); ++enbPosIt)
     {
         positionAllocEnb->Add(*enbPosIt);
     }
@@ -294,9 +293,7 @@
 
     Ptr<ListPositionAllocator> positionAllocUe = CreateObject<ListPositionAllocator>();
 
-    for (std::vector<Vector>::iterator uePosIt = m_uePositionList.begin();
-         uePosIt != m_uePositionList.end();
-         ++uePosIt)
+    for (auto uePosIt = m_uePositionList.begin(); uePosIt != m_uePositionList.end(); ++uePosIt)
     {
         positionAllocUe->Add(*uePosIt);
     }
@@ -463,9 +460,7 @@
 
     Ptr<LteEnbNetDevice> enbLteDevice;
 
-    for (std::vector<Ptr<NetDevice>>::const_iterator enbDevIt = enbDevices.Begin();
-         enbDevIt != enbDevices.End();
-         ++enbDevIt)
+    for (auto enbDevIt = enbDevices.Begin(); enbDevIt != enbDevices.End(); ++enbDevIt)
     {
         if (((*enbDevIt)->GetObject<LteEnbNetDevice>())->HasCellId(cellId))
         {
@@ -511,8 +506,8 @@
     ueRrc->GetAttribute("DataRadioBearerMap", ueDataRadioBearerMapValue);
     NS_TEST_ASSERT_MSG_EQ(ueDataRadioBearerMapValue.GetN(), 1 + 1, "wrong num bearers at UE");
 
-    ObjectMapValue::Iterator enbBearerIt = enbDataRadioBearerMapValue.Begin();
-    ObjectMapValue::Iterator ueBearerIt = ueDataRadioBearerMapValue.Begin();
+    auto enbBearerIt = enbDataRadioBearerMapValue.Begin();
+    auto ueBearerIt = ueDataRadioBearerMapValue.Begin();
     while (enbBearerIt != enbDataRadioBearerMapValue.End() &&
            ueBearerIt != ueDataRadioBearerMapValue.End())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-tdbet-ff-mac-scheduler.cc ns-3.40/src/lte/test/lte-test-tdbet-ff-mac-scheduler.cc
--- ns-3.39/src/lte/test/lte-test-tdbet-ff-mac-scheduler.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-tdbet-ff-mac-scheduler.cc	2023-09-27 13:30:37.830839600 -0700
@@ -388,7 +388,7 @@
 {
     std::ostringstream oss;
     oss << "distances (m) = [ ";
-    for (std::vector<double>::iterator it = dist.begin(); it != dist.end(); ++it)
+    for (auto it = dist.begin(); it != dist.end(); ++it)
     {
         oss << *it << " ";
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-tdtbfq-ff-mac-scheduler.cc ns-3.40/src/lte/test/lte-test-tdtbfq-ff-mac-scheduler.cc
--- ns-3.39/src/lte/test/lte-test-tdtbfq-ff-mac-scheduler.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-tdtbfq-ff-mac-scheduler.cc	2023-09-27 13:30:37.830839600 -0700
@@ -21,15 +21,16 @@
 
 #include "lte-test-tdtbfq-ff-mac-scheduler.h"
 
-#include "ns3/applications-module.h"
 #include "ns3/double.h"
 #include "ns3/internet-module.h"
 #include "ns3/ipv4-global-routing-helper.h"
 #include "ns3/network-module.h"
+#include "ns3/packet-sink-helper.h"
 #include "ns3/point-to-point-epc-helper.h"
 #include "ns3/point-to-point-helper.h"
 #include "ns3/radio-bearer-stats-calculator.h"
 #include "ns3/string.h"
+#include "ns3/udp-client-server-helper.h"
 #include <ns3/boolean.h>
 #include <ns3/constant-position-mobility-model.h>
 #include <ns3/enum.h>
@@ -546,7 +547,7 @@
 {
     std::ostringstream oss;
     oss << "distances (m) = [ ";
-    for (std::vector<double>::iterator it = dist.begin(); it != dist.end(); ++it)
+    for (auto it = dist.begin(); it != dist.end(); ++it)
     {
         oss << *it << " ";
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/lte-test-ue-measurements.cc ns-3.40/src/lte/test/lte-test-ue-measurements.cc
--- ns-3.39/src/lte/test/lte-test-ue-measurements.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/lte-test-ue-measurements.cc	2023-09-27 13:30:37.830839600 -0700
@@ -1607,8 +1607,7 @@
             NS_TEST_ASSERT_MSG_EQ(measResults.haveMeasResultNeighCells,
                                   true,
                                   "Unexpected report content");
-            std::list<LteRrcSap::MeasResultEutra>::iterator it =
-                measResults.measResultListEutra.begin();
+            auto it = measResults.measResultListEutra.begin();
             NS_ASSERT(it != measResults.measResultListEutra.end());
             NS_ASSERT(it->physCellId == 2);
             NS_TEST_ASSERT_MSG_EQ(it->haveCgiInfo,
@@ -1900,8 +1899,7 @@
             NS_TEST_ASSERT_MSG_EQ(measResults.haveMeasResultNeighCells,
                                   true,
                                   "Unexpected report content");
-            std::list<LteRrcSap::MeasResultEutra>::iterator it =
-                measResults.measResultListEutra.begin();
+            auto it = measResults.measResultListEutra.begin();
             NS_ASSERT(it != measResults.measResultListEutra.end());
             for (const auto& it : measResults.measResultListEutra)
             {
@@ -2402,18 +2400,19 @@
 
     // Setup UE measurement configuration in eNodeBs
     uint8_t measId;
-    std::list<LteRrcSap::ReportConfigEutra>::const_iterator itReportConfig;
     Ptr<LteEnbRrc> enbRrc1 = enbDevs.Get(0)->GetObject<LteEnbNetDevice>()->GetRrc();
     Ptr<LteEnbRrc> enbRrc2 = enbDevs.Get(1)->GetObject<LteEnbNetDevice>()->GetRrc();
 
-    for (itReportConfig = m_sourceConfigList.begin(); itReportConfig != m_sourceConfigList.end();
+    for (auto itReportConfig = m_sourceConfigList.begin();
+         itReportConfig != m_sourceConfigList.end();
          itReportConfig++)
     {
         measId = enbRrc1->AddUeMeasReportConfig(*itReportConfig).at(0);
         m_expectedSourceCellMeasId.insert(measId);
     }
 
-    for (itReportConfig = m_targetConfigList.begin(); itReportConfig != m_targetConfigList.end();
+    for (auto itReportConfig = m_targetConfigList.begin();
+         itReportConfig != m_targetConfigList.end();
          itReportConfig++)
     {
         measId = enbRrc2->AddUeMeasReportConfig(*itReportConfig).at(0);
@@ -2490,12 +2489,12 @@
     bool isCorrectMeasId;
     if (cellId == 1)
     {
-        std::set<uint8_t>::iterator itMeasId = m_expectedSourceCellMeasId.find(measId);
+        auto itMeasId = m_expectedSourceCellMeasId.find(measId);
         isCorrectMeasId = (itMeasId != m_expectedSourceCellMeasId.end());
     }
     else if (cellId == 2)
     {
-        std::set<uint8_t>::iterator itMeasId = m_expectedTargetCellMeasId.find(measId);
+        auto itMeasId = m_expectedTargetCellMeasId.find(measId);
         isCorrectMeasId = (itMeasId != m_expectedTargetCellMeasId.end());
     }
     else
@@ -2528,8 +2527,7 @@
             NS_TEST_ASSERT_MSG_EQ(measResults.haveMeasResultNeighCells,
                                   true,
                                   "Unexpected report content");
-            std::list<LteRrcSap::MeasResultEutra>::iterator it =
-                measResults.measResultListEutra.begin();
+            auto it = measResults.measResultListEutra.begin();
             NS_ASSERT(it != measResults.measResultListEutra.end());
             NS_ASSERT(it->physCellId != cellId);
             NS_ASSERT(it->physCellId <= 2);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/test-asn1-encoding.cc ns-3.40/src/lte/test/test-asn1-encoding.cc
--- ns-3.39/src/lte/test/test-asn1-encoding.cc	2023-07-05 14:23:48.021428000 -0700
+++ ns-3.40/src/lte/test/test-asn1-encoding.cc	2023-09-27 13:30:37.830839600 -0700
@@ -207,9 +207,9 @@
                           "SrbToAddModList different sizes");
 
     std::list<LteRrcSap::SrbToAddMod> srcSrbToAddModList = rrcd1.srbToAddModList;
-    std::list<LteRrcSap::SrbToAddMod>::iterator it1 = srcSrbToAddModList.begin();
+    auto it1 = srcSrbToAddModList.begin();
     std::list<LteRrcSap::SrbToAddMod> dstSrbToAddModList = rrcd2.srbToAddModList;
-    std::list<LteRrcSap::SrbToAddMod>::iterator it2 = dstSrbToAddModList.begin();
+    auto it2 = dstSrbToAddModList.begin();
 
     for (; it1 != srcSrbToAddModList.end(); it1++, it2++)
     {
@@ -233,9 +233,9 @@
                           "DrbToAddModList different sizes");
 
     std::list<LteRrcSap::DrbToAddMod> srcDrbToAddModList = rrcd1.drbToAddModList;
-    std::list<LteRrcSap::DrbToAddMod>::iterator it3 = srcDrbToAddModList.begin();
+    auto it3 = srcDrbToAddModList.begin();
     std::list<LteRrcSap::DrbToAddMod> dstDrbToAddModList = rrcd2.drbToAddModList;
-    std::list<LteRrcSap::DrbToAddMod>::iterator it4 = dstDrbToAddModList.begin();
+    auto it4 = dstDrbToAddModList.begin();
 
     for (; it3 != srcDrbToAddModList.end(); it3++, it4++)
     {
@@ -267,8 +267,8 @@
 
     std::list<uint8_t> srcDrbToReleaseList = rrcd1.drbToReleaseList;
     std::list<uint8_t> dstDrbToReleaseList = rrcd2.drbToReleaseList;
-    std::list<uint8_t>::iterator it5 = srcDrbToReleaseList.begin();
-    std::list<uint8_t>::iterator it6 = dstDrbToReleaseList.begin();
+    auto it5 = srcDrbToReleaseList.begin();
+    auto it6 = dstDrbToReleaseList.begin();
 
     for (; it5 != srcDrbToReleaseList.end(); it5++, it6++)
     {
@@ -1186,8 +1186,8 @@
 
     if (srcMeas.haveMeasResultNeighCells)
     {
-        std::list<LteRrcSap::MeasResultEutra>::iterator itsrc = srcMeas.measResultListEutra.begin();
-        std::list<LteRrcSap::MeasResultEutra>::iterator itdst = dstMeas.measResultListEutra.begin();
+        auto itsrc = srcMeas.measResultListEutra.begin();
+        auto itdst = dstMeas.measResultListEutra.begin();
         for (; itsrc != srcMeas.measResultListEutra.end(); itsrc++, itdst++)
         {
             NS_TEST_ASSERT_MSG_EQ(itsrc->physCellId, itdst->physCellId, "Different physCellId!");
@@ -1210,8 +1210,8 @@
 
                 if (!itsrc->cgiInfo.plmnIdentityList.empty())
                 {
-                    std::list<uint32_t>::iterator itsrc2 = itsrc->cgiInfo.plmnIdentityList.begin();
-                    std::list<uint32_t>::iterator itdst2 = itdst->cgiInfo.plmnIdentityList.begin();
+                    auto itsrc2 = itsrc->cgiInfo.plmnIdentityList.begin();
+                    auto itdst2 = itdst->cgiInfo.plmnIdentityList.begin();
                     for (; itsrc2 != itsrc->cgiInfo.plmnIdentityList.begin(); itsrc2++, itdst2++)
                     {
                         NS_TEST_ASSERT_MSG_EQ(*itsrc2, *itdst2, "Different plmnId elements!");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/test-lte-epc-e2e-data.cc ns-3.40/src/lte/test/test-lte-epc-e2e-data.cc
--- ns-3.39/src/lte/test/test-lte-epc-e2e-data.cc	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/lte/test/test-lte-epc-e2e-data.cc	2023-09-27 13:30:37.830839600 -0700
@@ -195,13 +195,11 @@
                                      StringValue("RowFirst"));
     enbMobility.Install(enbs);
     NetDeviceContainer enbLteDevs = lteHelper->InstallEnbDevice(enbs);
-    NetDeviceContainer::Iterator enbLteDevIt = enbLteDevs.Begin();
+    auto enbLteDevIt = enbLteDevs.Begin();
 
     uint16_t ulPort = 1000;
 
-    for (std::vector<EnbTestData>::iterator enbit = m_enbTestData.begin();
-         enbit < m_enbTestData.end();
-         ++enbit, ++enbLteDevIt)
+    for (auto enbit = m_enbTestData.begin(); enbit < m_enbTestData.end(); ++enbit, ++enbLteDevIt)
     {
         NS_ABORT_IF(enbLteDevIt == enbLteDevs.End());
 
@@ -317,12 +315,9 @@
 
     uint64_t imsiCounter = 0;
 
-    for (std::vector<EnbTestData>::iterator enbit = m_enbTestData.begin();
-         enbit < m_enbTestData.end();
-         ++enbit)
+    for (auto enbit = m_enbTestData.begin(); enbit < m_enbTestData.end(); ++enbit)
     {
-        for (std::vector<UeTestData>::iterator ueit = enbit->ues.begin(); ueit < enbit->ues.end();
-             ++ueit)
+        for (auto ueit = enbit->ues.begin(); ueit < enbit->ues.end(); ++ueit)
         {
             uint64_t imsi = ++imsiCounter;
             for (uint32_t b = 0; b < ueit->bearers.size(); ++b)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/test-lte-rlc-header.cc ns-3.40/src/lte/test/test-lte-rlc-header.cc
--- ns-3.39/src/lte/test/test-lte-rlc-header.cc	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/lte/test/test-lte-rlc-header.cc	2023-09-27 13:30:37.830839600 -0700
@@ -151,8 +151,7 @@
     LteRlcAmHeader h;
     h.SetControlPdu(LteRlcAmHeader::STATUS_PDU);
     h.SetAckSn(m_ackSn);
-    for (std::list<SequenceNumber10>::iterator it = m_nackSnList.begin(); it != m_nackSnList.end();
-         ++it)
+    for (auto it = m_nackSnList.begin(); it != m_nackSnList.end(); ++it)
     {
         h.PushNack(it->GetValue());
     }
@@ -170,8 +169,7 @@
     SequenceNumber10 ackSn = h2.GetAckSn();
     NS_TEST_ASSERT_MSG_EQ(ackSn, m_ackSn, "deserialized ACK SN differs from test vector");
 
-    for (std::list<SequenceNumber10>::iterator it = m_nackSnList.begin(); it != m_nackSnList.end();
-         ++it)
+    for (auto it = m_nackSnList.begin(); it != m_nackSnList.end(); ++it)
     {
         int nackSn = h2.PopNack();
         NS_TEST_ASSERT_MSG_GT(nackSn, -1, "not enough elements in deserialized NACK list");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/test-lte-rrc.cc ns-3.40/src/lte/test/test-lte-rrc.cc
--- ns-3.39/src/lte/test/test-lte-rrc.cc	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/lte/test/test-lte-rrc.cc	2023-09-27 13:30:37.830839600 -0700
@@ -321,7 +321,7 @@
     // instead of lteHelper->Attach () and lteHelper->ActivateXxx
 
     // Set AdmitConnectionRequest attribute
-    for (NetDeviceContainer::Iterator it = enbDevs.Begin(); it != enbDevs.End(); ++it)
+    for (auto it = enbDevs.Begin(); it != enbDevs.End(); ++it)
     {
         Ptr<LteEnbRrc> enbRrc = (*it)->GetObject<LteEnbNetDevice>()->GetRrc();
         enbRrc->SetAttribute("AdmitRrcConnectionRequest",
@@ -330,7 +330,7 @@
 
     uint32_t i = 0;
     uint32_t tmax = 0;
-    for (NetDeviceContainer::Iterator it = ueDevs.Begin(); it != ueDevs.End(); ++it)
+    for (auto it = ueDevs.Begin(); it != ueDevs.End(); ++it)
     {
         Ptr<NetDevice> ueDevice = *it;
         Ptr<NetDevice> enbDevice = enbDevs.Get(0);
@@ -494,8 +494,8 @@
                                   m_nBearers,
                                   "wrong num bearers at UE");
 
-            ObjectMapValue::Iterator enbBearerIt = enbDataRadioBearerMapValue.Begin();
-            ObjectMapValue::Iterator ueBearerIt = ueDataRadioBearerMapValue.Begin();
+            auto enbBearerIt = enbDataRadioBearerMapValue.Begin();
+            auto ueBearerIt = ueDataRadioBearerMapValue.Begin();
             while (enbBearerIt != enbDataRadioBearerMapValue.End() &&
                    ueBearerIt != ueDataRadioBearerMapValue.End())
             {
@@ -679,7 +679,7 @@
     // instead of lteHelper->Attach () and lteHelper->ActivateXxx
 
     // Set AdmitConnectionRequest attribute
-    for (NetDeviceContainer::Iterator it = enbDevs.Begin(); it != enbDevs.End(); ++it)
+    for (auto it = enbDevs.Begin(); it != enbDevs.End(); ++it)
     {
         Ptr<LteEnbRrc> enbRrc = (*it)->GetObject<LteEnbNetDevice>()->GetRrc();
         enbRrc->SetAttribute("AdmitRrcConnectionRequest",
@@ -688,7 +688,7 @@
 
     uint32_t i = 0;
     uint32_t tmax = 0;
-    for (NetDeviceContainer::Iterator it = ueDevs.Begin(); it != ueDevs.End(); ++it)
+    for (auto it = ueDevs.Begin(); it != ueDevs.End(); ++it)
     {
         Ptr<NetDevice> ueDevice = *it;
         Ptr<NetDevice> enbDevice = enbDevs.Get(0);
@@ -782,7 +782,7 @@
 
     NS_LOG_FUNCTION(this);
 
-    for (uint32_t useIdealRrc = 0; useIdealRrc <= 1; ++useIdealRrc)
+    for (auto useIdealRrc : {false, true})
     {
         // <----- all times in ms ----------------->
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/test-lte-x2-handover.cc ns-3.40/src/lte/test/test-lte-x2-handover.cc
--- ns-3.39/src/lte/test/test-lte-x2-handover.cc	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/lte/test/test-lte-x2-handover.cc	2023-09-27 13:30:37.830839600 -0700
@@ -17,13 +17,15 @@
  * Author: Nicola Baldo <nbaldo@cttc.es>
  */
 
-#include <ns3/applications-module.h>
 #include <ns3/core-module.h>
 #include <ns3/internet-module.h>
 #include <ns3/lte-module.h>
 #include <ns3/mobility-module.h>
 #include <ns3/network-module.h>
+#include <ns3/packet-sink-helper.h>
+#include <ns3/packet-sink.h>
 #include <ns3/point-to-point-module.h>
+#include <ns3/udp-client-server-helper.h>
 
 using namespace ns3;
 
@@ -274,7 +276,7 @@
     NetDeviceContainer enbDevices;
     enbDevices = m_lteHelper->InstallEnbDevice(enbNodes);
     stream += m_lteHelper->AssignStreams(enbDevices, stream);
-    for (NetDeviceContainer::Iterator it = enbDevices.Begin(); it != enbDevices.End(); ++it)
+    for (auto it = enbDevices.Begin(); it != enbDevices.End(); ++it)
     {
         Ptr<LteEnbRrc> enbRrc = (*it)->GetObject<LteEnbNetDevice>()->GetRrc();
         enbRrc->SetAttribute("AdmitHandoverRequest", BooleanValue(m_admitHo));
@@ -438,7 +440,7 @@
 
     // check initial RRC connection
     const Time maxRrcConnectionEstablishmentDuration = Seconds(0.080);
-    for (NetDeviceContainer::Iterator it = ueDevices.Begin(); it != ueDevices.End(); ++it)
+    for (auto it = ueDevices.Begin(); it != ueDevices.End(); ++it)
     {
         Simulator::Schedule(maxRrcConnectionEstablishmentDuration,
                             &LteX2HandoverTestCase::CheckConnected,
@@ -450,8 +452,7 @@
     // schedule handover events and corresponding checks
 
     Time stopTime = Seconds(0);
-    for (std::list<HandoverEvent>::iterator hoEventIt = m_handoverEventList.begin();
-         hoEventIt != m_handoverEventList.end();
+    for (auto hoEventIt = m_handoverEventList.begin(); hoEventIt != m_handoverEventList.end();
          ++hoEventIt)
     {
         // Teleport the UE between both eNBs just before the handover starts
@@ -567,8 +568,8 @@
                           m_nDedicatedBearers + 1,
                           "wrong num bearers at UE");
 
-    ObjectMapValue::Iterator enbBearerIt = enbDataRadioBearerMapValue.Begin();
-    ObjectMapValue::Iterator ueBearerIt = ueDataRadioBearerMapValue.Begin();
+    auto enbBearerIt = enbDataRadioBearerMapValue.Begin();
+    auto ueBearerIt = ueDataRadioBearerMapValue.Begin();
     while (enbBearerIt != enbDataRadioBearerMapValue.End() &&
            ueBearerIt != ueDataRadioBearerMapValue.End())
     {
@@ -619,7 +620,7 @@
 void
 LteX2HandoverTestCase::SaveStatsAfterHandover(uint32_t ueIndex)
 {
-    for (std::list<BearerData>::iterator it = m_ueDataVector.at(ueIndex).bearerDataList.begin();
+    for (auto it = m_ueDataVector.at(ueIndex).bearerDataList.begin();
          it != m_ueDataVector.at(ueIndex).bearerDataList.end();
          ++it)
     {
@@ -632,7 +633,7 @@
 LteX2HandoverTestCase::CheckStatsAWhileAfterHandover(uint32_t ueIndex)
 {
     uint32_t b = 1;
-    for (std::list<BearerData>::iterator it = m_ueDataVector.at(ueIndex).bearerDataList.begin();
+    for (auto it = m_ueDataVector.at(ueIndex).bearerDataList.begin();
          it != m_ueDataVector.at(ueIndex).bearerDataList.end();
          ++it)
     {
@@ -759,11 +760,9 @@
         "ns3::PfFfMacScheduler",
     };
 
-    for (std::vector<std::string>::iterator schedIt = schedulers.begin();
-         schedIt != schedulers.end();
-         ++schedIt)
+    for (auto schedIt = schedulers.begin(); schedIt != schedulers.end(); ++schedIt)
     {
-        for (int32_t useIdealRrc = 1; useIdealRrc >= 0; --useIdealRrc)
+        for (auto useIdealRrc : {true, false})
         {
             // nUes, nDBearers, helist, name, sched, admitHo, idealRrc
             AddTestCase(new LteX2HandoverTestCase(1,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/lte/test/test-lte-x2-handover-measures.cc ns-3.40/src/lte/test/test-lte-x2-handover-measures.cc
--- ns-3.39/src/lte/test/test-lte-x2-handover-measures.cc	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/lte/test/test-lte-x2-handover-measures.cc	2023-09-27 13:30:37.830839600 -0700
@@ -18,13 +18,16 @@
  *          Manuel Requena <manuel.requena@cttc.es>
  */
 
-#include <ns3/applications-module.h>
+#include <ns3/bulk-send-helper.h>
 #include <ns3/core-module.h>
 #include <ns3/internet-module.h>
 #include <ns3/lte-module.h>
 #include <ns3/mobility-module.h>
 #include <ns3/network-module.h>
+#include <ns3/packet-sink-helper.h>
+#include <ns3/packet-sink.h>
 #include <ns3/point-to-point-module.h>
+#include <ns3/udp-client-server-helper.h>
 
 using namespace ns3;
 
@@ -342,7 +345,7 @@
     NetDeviceContainer enbDevices;
     enbDevices = m_lteHelper->InstallEnbDevice(enbNodes);
     stream += m_lteHelper->AssignStreams(enbDevices, stream);
-    for (NetDeviceContainer::Iterator it = enbDevices.Begin(); it != enbDevices.End(); ++it)
+    for (auto it = enbDevices.Begin(); it != enbDevices.End(); ++it)
     {
         Ptr<LteEnbRrc> enbRrc = (*it)->GetObject<LteEnbNetDevice>()->GetRrc();
         enbRrc->SetAttribute("AdmitHandoverRequest", BooleanValue(m_admitHo));
@@ -538,7 +541,7 @@
 
     // check initial RRC connection
     const Time maxRrcConnectionEstablishmentDuration = Seconds(0.080);
-    for (NetDeviceContainer::Iterator it = ueDevices.Begin(); it != ueDevices.End(); ++it)
+    for (auto it = ueDevices.Begin(); it != ueDevices.End(); ++it)
     {
         NS_LOG_FUNCTION(maxRrcConnectionEstablishmentDuration);
         Simulator::Schedule(maxRrcConnectionEstablishmentDuration,
@@ -551,7 +554,7 @@
     // schedule the checkpoint events
 
     Time stopTime = Seconds(0);
-    for (std::list<CheckPointEvent>::iterator checkPointEventIt = m_checkPointEventList.begin();
+    for (auto checkPointEventIt = m_checkPointEventList.begin();
          checkPointEventIt != m_checkPointEventList.end();
          ++checkPointEventIt)
     {
@@ -639,8 +642,8 @@
                           m_nDedicatedBearers + 1,
                           "wrong num bearers at UE");
 
-    ObjectMapValue::Iterator enbBearerIt = enbDataRadioBearerMapValue.Begin();
-    ObjectMapValue::Iterator ueBearerIt = ueDataRadioBearerMapValue.Begin();
+    auto enbBearerIt = enbDataRadioBearerMapValue.Begin();
+    auto ueBearerIt = ueDataRadioBearerMapValue.Begin();
     while (enbBearerIt != enbDataRadioBearerMapValue.End() &&
            ueBearerIt != ueDataRadioBearerMapValue.End())
     {
@@ -675,7 +678,7 @@
 LteX2HandoverMeasuresTestCase::SaveStats(uint32_t ueIndex)
 {
     NS_LOG_FUNCTION(ueIndex);
-    for (std::list<BearerData>::iterator it = m_ueDataVector.at(ueIndex).bearerDataList.begin();
+    for (auto it = m_ueDataVector.at(ueIndex).bearerDataList.begin();
          it != m_ueDataVector.at(ueIndex).bearerDataList.end();
          ++it)
     {
@@ -695,7 +698,7 @@
 {
     NS_LOG_FUNCTION(ueIndex);
     uint32_t b = 1;
-    for (std::list<BearerData>::iterator it = m_ueDataVector.at(ueIndex).bearerDataList.begin();
+    for (auto it = m_ueDataVector.at(ueIndex).bearerDataList.begin();
          it != m_ueDataVector.at(ueIndex).bearerDataList.end();
          ++it)
     {
@@ -770,10 +773,9 @@
         CheckPointEvent(Seconds(25), Seconds(37), checkInterval, 0, 3),
     };
 
-    int32_t useIdealRrc;
     std::string sched = "ns3::PfFfMacScheduler";
     std::string ho = "ns3::A2A4RsrqHandoverAlgorithm";
-    for (useIdealRrc = 1; useIdealRrc >= 0; --useIdealRrc)
+    for (auto useIdealRrc : {true, false})
     {
         // nEnbs, nUes, nDBearers, celist, name, useUdp, sched, ho, admitHo, idealRrc
         AddTestCase(new LteX2HandoverMeasuresTestCase(2,
@@ -878,7 +880,7 @@
     }
 
     sched = "ns3::RrFfMacScheduler";
-    for (useIdealRrc = 1; useIdealRrc >= 0; --useIdealRrc)
+    for (auto useIdealRrc : {true, false})
     {
         // nEnbs, nUes, nDBearers, celist, name, useUdp, sched, admitHo, idealRrc
         AddTestCase(new LteX2HandoverMeasuresTestCase(2,
@@ -918,7 +920,7 @@
 
     ho = "ns3::A3RsrpHandoverAlgorithm";
     sched = "ns3::PfFfMacScheduler";
-    for (useIdealRrc = 1; useIdealRrc >= 0; --useIdealRrc)
+    for (auto useIdealRrc : {true, false})
     {
         // nEnbs, nUes, nDBearers, celist, name, useUdp, sched, admitHo, idealRrc
         AddTestCase(new LteX2HandoverMeasuresTestCase(2,
@@ -957,7 +959,7 @@
     }
 
     sched = "ns3::RrFfMacScheduler";
-    for (useIdealRrc = 1; useIdealRrc >= 0; --useIdealRrc)
+    for (auto useIdealRrc : {true, false})
     {
         // nEnbs, nUes, nDBearers, celist, name, useUdp, sched, admitHo, idealRrc
         AddTestCase(new LteX2HandoverMeasuresTestCase(2,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/CMakeLists.txt ns-3.40/src/mesh/CMakeLists.txt
--- ns-3.39/src/mesh/CMakeLists.txt	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/mesh/CMakeLists.txt	2023-09-27 13:30:37.830839600 -0700
@@ -68,7 +68,6 @@
   LIBRARIES_TO_LINK
     ${libinternet}
     ${libwifi}
-    ${libapplications}
   TEST_SOURCES
     test/dot11s/dot11s-test-suite.cc
     test/dot11s/hwmp-proactive-regression.cc
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/examples/mesh.cc ns-3.40/src/mesh/examples/mesh.cc
--- ns-3.39/src/mesh/examples/mesh.cc	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/mesh/examples/mesh.cc	2023-09-27 13:30:37.834839600 -0700
@@ -336,7 +336,7 @@
 MeshTest::Report()
 {
     unsigned n(0);
-    for (NetDeviceContainer::Iterator i = meshDevices.Begin(); i != meshDevices.End(); ++i, ++n)
+    for (auto i = meshDevices.Begin(); i != meshDevices.End(); ++i, ++n)
     {
         std::ostringstream os;
         os << "mp-report-" << n << ".xml";
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/helper/dot11s/dot11s-installer.cc ns-3.40/src/mesh/helper/dot11s/dot11s-installer.cc
--- ns-3.39/src/mesh/helper/dot11s/dot11s-installer.cc	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/mesh/helper/dot11s/dot11s-installer.cc	2023-09-27 13:30:37.834839600 -0700
@@ -16,7 +16,7 @@
  *
  * Authors: Kirill Andreev <andreev@iitp.ru>
  */
-#include "ns3/dot11s-installer.h"
+#include "dot11s-installer.h"
 
 #include "ns3/hwmp-protocol.h"
 #include "ns3/mesh-wifi-interface-mac.h"
@@ -92,7 +92,7 @@
     mp->Report(os);
 
     std::vector<Ptr<NetDevice>> ifaces = mp->GetInterfaces();
-    for (std::vector<Ptr<NetDevice>>::const_iterator i = ifaces.begin(); i != ifaces.end(); ++i)
+    for (auto i = ifaces.begin(); i != ifaces.end(); ++i)
     {
         Ptr<WifiNetDevice> device = (*i)->GetObject<WifiNetDevice>();
         NS_ASSERT(device);
@@ -115,7 +115,7 @@
     mp->ResetStats();
 
     std::vector<Ptr<NetDevice>> ifaces = mp->GetInterfaces();
-    for (std::vector<Ptr<NetDevice>>::const_iterator i = ifaces.begin(); i != ifaces.end(); ++i)
+    for (auto i = ifaces.begin(); i != ifaces.end(); ++i)
     {
         Ptr<WifiNetDevice> device = (*i)->GetObject<WifiNetDevice>();
         NS_ASSERT(device);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/helper/flame/flame-installer.cc ns-3.40/src/mesh/helper/flame/flame-installer.cc
--- ns-3.39/src/mesh/helper/flame/flame-installer.cc	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/mesh/helper/flame/flame-installer.cc	2023-09-27 13:30:37.834839600 -0700
@@ -17,7 +17,7 @@
  * Authors: Kirill Andreev <andreev@iitp.ru>
  */
 
-#include "ns3/flame-installer.h"
+#include "flame-installer.h"
 
 #include "ns3/flame-protocol.h"
 #include "ns3/mesh-wifi-interface-mac.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/helper/mesh-helper.cc ns-3.40/src/mesh/helper/mesh-helper.cc
--- ns-3.39/src/mesh/helper/mesh-helper.cc	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/mesh/helper/mesh-helper.cc	2023-09-27 13:30:37.834839600 -0700
@@ -64,7 +64,7 @@
 {
     NetDeviceContainer devices;
     NS_ASSERT(m_stack);
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
         // Create a mesh point device
@@ -179,7 +179,7 @@
 {
     int64_t currentStream = stream;
     Ptr<NetDevice> netDevice;
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         netDevice = (*i);
         Ptr<MeshPointDevice> mpd = DynamicCast<MeshPointDevice>(netDevice);
@@ -190,7 +190,7 @@
             currentStream += mpd->AssignStreams(currentStream);
             // To access, we need the underlying WifiNetDevices
             std::vector<Ptr<NetDevice>> ifaces = mpd->GetInterfaces();
-            for (std::vector<Ptr<NetDevice>>::iterator i = ifaces.begin(); i != ifaces.end(); i++)
+            for (auto i = ifaces.begin(); i != ifaces.end(); i++)
             {
                 wifi = DynamicCast<WifiNetDevice>(*i);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/helper/mesh-helper.h ns-3.40/src/mesh/helper/mesh-helper.h
--- ns-3.39/src/mesh/helper/mesh-helper.h	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/mesh/helper/mesh-helper.h	2023-09-27 13:30:37.834839600 -0700
@@ -21,7 +21,8 @@
 #ifndef MESH_HELPER_H
 #define MESH_HELPER_H
 
-#include "ns3/mesh-stack-installer.h"
+#include "mesh-stack-installer.h"
+
 #include "ns3/object-factory.h"
 #include "ns3/qos-utils.h"
 #include "ns3/wifi-standards.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/helper/mesh-stack-installer.cc ns-3.40/src/mesh/helper/mesh-stack-installer.cc
--- ns-3.39/src/mesh/helper/mesh-stack-installer.cc	2023-07-05 14:23:48.029428000 -0700
+++ ns-3.40/src/mesh/helper/mesh-stack-installer.cc	2023-09-27 13:30:37.834839600 -0700
@@ -17,7 +17,7 @@
  * Author: Peter D. Barnes, Jr. <pdbarnes@llnl.gov>
  */
 
-#include "ns3/mesh-stack-installer.h"
+#include "mesh-stack-installer.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/hwmp-protocol.cc ns-3.40/src/mesh/model/dot11s/hwmp-protocol.cc
--- ns-3.39/src/mesh/model/dot11s/hwmp-protocol.cc	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/hwmp-protocol.cc	2023-09-27 13:30:37.834839600 -0700
@@ -201,9 +201,7 @@
 HwmpProtocol::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (std::map<Mac48Address, PreqEvent>::iterator i = m_preqTimeouts.begin();
-         i != m_preqTimeouts.end();
-         i++)
+    for (auto i = m_preqTimeouts.begin(); i != m_preqTimeouts.end(); i++)
     {
         i->second.preqTimeout.Cancel();
     }
@@ -263,14 +261,10 @@
         m_stats.txBytes += packet->GetSize();
         // channel IDs where we have already sent broadcast:
         std::vector<uint16_t> channels;
-        for (HwmpProtocolMacMap::const_iterator plugin = m_interfaces.begin();
-             plugin != m_interfaces.end();
-             plugin++)
+        for (auto plugin = m_interfaces.begin(); plugin != m_interfaces.end(); plugin++)
         {
             bool shouldSend = true;
-            for (std::vector<uint16_t>::const_iterator chan = channels.begin();
-                 chan != channels.end();
-                 chan++)
+            for (auto chan = channels.begin(); chan != channels.end(); chan++)
             {
                 if ((*chan) == plugin->second->GetChannelId())
                 {
@@ -283,9 +277,7 @@
             }
             channels.push_back(plugin->second->GetChannelId());
             std::vector<Mac48Address> receivers = GetBroadcastReceivers(plugin->first);
-            for (std::vector<Mac48Address>::const_iterator i = receivers.begin();
-                 i != receivers.end();
-                 i++)
+            for (auto i = receivers.begin(); i != receivers.end(); i++)
             {
                 Ptr<Packet> packetCopy = packet->Copy();
                 //
@@ -396,8 +388,7 @@
             dst_seqno = result.seqnum;
         }
         m_stats.initiatedPreq++;
-        for (HwmpProtocolMacMap::const_iterator i = m_interfaces.begin(); i != m_interfaces.end();
-             i++)
+        for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++)
         {
             i->second->RequestDestination(destination, originator_seqno, dst_seqno);
         }
@@ -433,8 +424,7 @@
     NS_LOG_FUNCTION(this << from << interface << fromMp << metric);
     preq.IncrementMetric(metric);
     // acceptance cretirea:
-    std::map<Mac48Address, std::pair<uint32_t, uint32_t>>::const_iterator i =
-        m_hwmpSeqnoMetricDatabase.find(preq.GetOriginatorAddress());
+    auto i = m_hwmpSeqnoMetricDatabase.find(preq.GetOriginatorAddress());
     bool freshInfo(true);
     if (i != m_hwmpSeqnoMetricDatabase.end())
     {
@@ -501,9 +491,7 @@
         m_routeChangeTraceSource(rChange);
         ReactivePathResolved(fromMp);
     }
-    for (std::vector<Ptr<DestinationAddressUnit>>::const_iterator i = destinations.begin();
-         i != destinations.end();
-         i++)
+    for (auto i = destinations.begin(); i != destinations.end(); i++)
     {
         if ((*i)->GetDestinationAddress() == Mac48Address::GetBroadcast())
         {
@@ -603,7 +591,7 @@
     }
     // Forward PREQ to all interfaces:
     NS_LOG_DEBUG("I am " << GetAddress() << "retransmitting PREQ:" << preq);
-    for (HwmpProtocolMacMap::const_iterator i = m_interfaces.begin(); i != m_interfaces.end(); i++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++)
     {
         Time forwardingDelay = GetMeshPoint()->GetForwardingDelay();
         NS_LOG_DEBUG("Forwarding PREQ from " << from << " with delay "
@@ -622,8 +610,7 @@
     NS_LOG_FUNCTION(this << from << interface << fromMp << metric);
     prep.IncrementMetric(metric);
     // acceptance cretirea:
-    std::map<Mac48Address, std::pair<uint32_t, uint32_t>>::const_iterator i =
-        m_hwmpSeqnoMetricDatabase.find(prep.GetOriginatorAddress());
+    auto i = m_hwmpSeqnoMetricDatabase.find(prep.GetOriginatorAddress());
     bool freshInfo(true);
     uint32_t sequence = prep.GetDestinationSeqNumber();
     if (i != m_hwmpSeqnoMetricDatabase.end())
@@ -711,7 +698,7 @@
         return;
     }
     // Forward PREP
-    HwmpProtocolMacMap::const_iterator prep_sender = m_interfaces.find(result.ifIndex);
+    auto prep_sender = m_interfaces.find(result.ifIndex);
     NS_ASSERT(prep_sender != m_interfaces.end());
     Time forwardingDelay = GetMeshPoint()->GetForwardingDelay();
     NS_LOG_DEBUG("Forwarding PREP from " << from << " with delay " << forwardingDelay.As(Time::US));
@@ -768,7 +755,7 @@
     prep.SetMetric(initMetric);
     prep.SetOriginatorAddress(src);
     prep.SetOriginatorSeqNumber(originatorDsn);
-    HwmpProtocolMacMap::const_iterator prep_sender = m_interfaces.find(interface);
+    auto prep_sender = m_interfaces.find(interface);
     NS_ASSERT(prep_sender != m_interfaces.end());
     prep_sender->second->SendPrep(prep, retransmitter);
     m_stats.initiatedPrep++;
@@ -780,8 +767,7 @@
     NS_LOG_FUNCTION(this << mp);
     m_mp = mp;
     std::vector<Ptr<NetDevice>> interfaces = mp->GetInterfaces();
-    for (std::vector<Ptr<NetDevice>>::const_iterator i = interfaces.begin(); i != interfaces.end();
-         i++)
+    for (auto i = interfaces.begin(); i != interfaces.end(); i++)
     {
         // Checking for compatible net device
         Ptr<WifiNetDevice> wifiNetDev = (*i)->GetObject<WifiNetDevice>();
@@ -841,8 +827,7 @@
         NS_LOG_DEBUG("Dropping seqno " << seqno << "; from self");
         return true;
     }
-    std::map<Mac48Address, uint32_t, std::less<Mac48Address>>::const_iterator i =
-        m_lastDataSeqno.find(source);
+    const auto i = m_lastDataSeqno.find(source);
     if (i == m_lastDataSeqno.end())
     {
         m_lastDataSeqno[source] = seqno;
@@ -889,7 +874,7 @@
 HwmpProtocol::InitiatePathError(PathError perr)
 {
     NS_LOG_FUNCTION(this);
-    for (HwmpProtocolMacMap::const_iterator i = m_interfaces.begin(); i != m_interfaces.end(); i++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++)
     {
         std::vector<Mac48Address> receivers_for_interface;
         for (unsigned int j = 0; j < perr.receivers.size(); j++)
@@ -907,7 +892,7 @@
 HwmpProtocol::ForwardPathError(PathError perr)
 {
     NS_LOG_FUNCTION(this);
-    for (HwmpProtocolMacMap::const_iterator i = m_interfaces.begin(); i != m_interfaces.end(); i++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++)
     {
         std::vector<Mac48Address> receivers_for_interface;
         for (unsigned int j = 0; j < perr.receivers.size(); j++)
@@ -1021,7 +1006,7 @@
     NS_LOG_FUNCTION(this << dst);
     QueuedPacket retval;
     retval.pkt = nullptr;
-    for (std::vector<QueuedPacket>::iterator i = m_rqueue.begin(); i != m_rqueue.end(); i++)
+    for (auto i = m_rqueue.begin(); i != m_rqueue.end(); i++)
     {
         if ((*i).dst == dst)
         {
@@ -1051,7 +1036,7 @@
 HwmpProtocol::ReactivePathResolved(Mac48Address dst)
 {
     NS_LOG_FUNCTION(this << dst);
-    std::map<Mac48Address, PreqEvent>::iterator i = m_preqTimeouts.find(dst);
+    auto i = m_preqTimeouts.find(dst);
     if (i != m_preqTimeouts.end())
     {
         m_routeDiscoveryTimeCallback(Simulator::Now() - i->second.whenScheduled);
@@ -1106,7 +1091,7 @@
 HwmpProtocol::ShouldSendPreq(Mac48Address dst)
 {
     NS_LOG_FUNCTION(this << dst);
-    std::map<Mac48Address, PreqEvent>::const_iterator i = m_preqTimeouts.find(dst);
+    auto i = m_preqTimeouts.find(dst);
     if (i == m_preqTimeouts.end())
     {
         m_preqTimeouts[dst].preqTimeout =
@@ -1132,7 +1117,7 @@
     }
     if (result.retransmitter != Mac48Address::GetBroadcast())
     {
-        std::map<Mac48Address, PreqEvent>::iterator i = m_preqTimeouts.find(dst);
+        auto i = m_preqTimeouts.find(dst);
         NS_ASSERT(i != m_preqTimeouts.end());
         m_preqTimeouts.erase(i);
         return;
@@ -1152,7 +1137,7 @@
                          HwmpRtable::MAX_METRIC);
             packet = DequeueFirstPacketByDst(dst);
         }
-        std::map<Mac48Address, PreqEvent>::iterator i = m_preqTimeouts.find(dst);
+        auto i = m_preqTimeouts.find(dst);
         NS_ASSERT(i != m_preqTimeouts.end());
         m_routeDiscoveryTimeCallback(Simulator::Now() - i->second.whenScheduled);
         m_preqTimeouts.erase(i);
@@ -1161,7 +1146,7 @@
     numOfRetry++;
     uint32_t originator_seqno = GetNextHwmpSeqno();
     uint32_t dst_seqno = m_rtable->LookupReactiveExpired(dst).seqnum;
-    for (HwmpProtocolMacMap::const_iterator i = m_interfaces.begin(); i != m_interfaces.end(); i++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++)
     {
         i->second->RequestDestination(dst, originator_seqno, dst_seqno);
     }
@@ -1204,7 +1189,7 @@
     preq.SetOriginatorAddress(GetAddress());
     preq.SetPreqID(GetNextPreqId());
     preq.SetOriginatorSeqNumber(GetNextHwmpSeqno());
-    for (HwmpProtocolMacMap::const_iterator i = m_interfaces.begin(); i != m_interfaces.end(); i++)
+    for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++)
     {
         i->second->SendPreq(preq);
     }
@@ -1352,9 +1337,7 @@
        << "doFlag=\"" << m_doFlag << "\"" << std::endl
        << "rfFlag=\"" << m_rfFlag << "\">" << std::endl;
     m_stats.Print(os);
-    for (HwmpProtocolMacMap::const_iterator plugin = m_interfaces.begin();
-         plugin != m_interfaces.end();
-         plugin++)
+    for (auto plugin = m_interfaces.begin(); plugin != m_interfaces.end(); plugin++)
     {
         plugin->second->Report(os);
     }
@@ -1366,9 +1349,7 @@
 {
     NS_LOG_FUNCTION(this);
     m_stats = Statistics();
-    for (HwmpProtocolMacMap::const_iterator plugin = m_interfaces.begin();
-         plugin != m_interfaces.end();
-         plugin++)
+    for (auto plugin = m_interfaces.begin(); plugin != m_interfaces.end(); plugin++)
     {
         plugin->second->ResetStats();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/hwmp-protocol-mac.cc ns-3.40/src/mesh/model/dot11s/hwmp-protocol-mac.cc
--- ns-3.39/src/mesh/model/dot11s/hwmp-protocol-mac.cc	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/hwmp-protocol-mac.cc	2023-09-27 13:30:37.834839600 -0700
@@ -120,7 +120,7 @@
     // this is the last header to remove.
     packet->RemoveHeader(elements, packet->GetSize());
     std::vector<HwmpProtocol::FailedDestination> failedDestinations;
-    for (MeshInformationElementVector::Iterator i = elements.Begin(); i != elements.End(); i++)
+    for (auto i = elements.Begin(); i != elements.End(); i++)
     {
         if ((*i)->ElementId() == IE_RANN)
         {
@@ -169,10 +169,7 @@
             m_stats.rxPerr++;
             std::vector<HwmpProtocol::FailedDestination> destinations =
                 perr->GetAddressUnitVector();
-            for (std::vector<HwmpProtocol::FailedDestination>::const_iterator i =
-                     destinations.begin();
-                 i != destinations.end();
-                 i++)
+            for (auto i = destinations.begin(); i != destinations.end(); i++)
             {
                 failedDestinations.push_back(*i);
             }
@@ -263,7 +260,7 @@
     NS_LOG_FUNCTION(this);
     Ptr<Packet> packet = Create<Packet>();
     MeshInformationElementVector elements;
-    for (std::vector<IePreq>::iterator i = preq.begin(); i != preq.end(); i++)
+    for (auto i = preq.begin(); i != preq.end(); i++)
     {
         elements.AddInformationElement(Ptr<IePreq>(&(*i)));
     }
@@ -278,7 +275,7 @@
     hdr.SetAddr3(m_protocol->GetAddress());
     // Send Management frame
     std::vector<Mac48Address> receivers = m_protocol->GetPreqReceivers(m_ifIndex);
-    for (std::vector<Mac48Address>::const_iterator i = receivers.begin(); i != receivers.end(); i++)
+    for (auto i = receivers.begin(); i != receivers.end(); i++)
     {
         hdr.SetAddr1(*i);
         m_stats.txPreq++;
@@ -292,7 +289,7 @@
 HwmpProtocolMac::RequestDestination(Mac48Address dst, uint32_t originator_seqno, uint32_t dst_seqno)
 {
     NS_LOG_FUNCTION(this << dst << originator_seqno << dst_seqno);
-    for (std::vector<IePreq>::iterator i = m_myPreq.begin(); i != m_myPreq.end(); i++)
+    for (auto i = m_myPreq.begin(); i != m_myPreq.end(); i++)
     {
         if (i->IsFull())
         {
@@ -372,10 +369,7 @@
     Ptr<Packet> packet = Create<Packet>();
     Ptr<IePerr> perr = Create<IePerr>();
     MeshInformationElementVector elements;
-    for (std::vector<HwmpProtocol::FailedDestination>::const_iterator i =
-             failedDestinations.begin();
-         i != failedDestinations.end();
-         i++)
+    for (auto i = failedDestinations.begin(); i != failedDestinations.end(); i++)
     {
         if (!perr->IsFull())
         {
@@ -406,7 +400,7 @@
         receivers.push_back(Mac48Address::GetBroadcast());
     }
     // Send Management frame
-    for (std::vector<Mac48Address>::const_iterator i = receivers.begin(); i != receivers.end(); i++)
+    for (auto i = receivers.begin(); i != receivers.end(); i++)
     {
         //
         // 64-bit Intel valgrind complains about hdr.SetAddr1 (*i).  It likes this
@@ -429,13 +423,10 @@
     // All duplicates in PERR are checked here, and there is no reason to
     // check it at any other place
     {
-        std::vector<Mac48Address>::const_iterator end = receivers.end();
-        for (std::vector<Mac48Address>::const_iterator i = receivers.begin(); i != end; i++)
+        for (auto i = receivers.begin(); i != receivers.end(); i++)
         {
             bool should_add = true;
-            for (std::vector<Mac48Address>::const_iterator j = m_myPerr.receivers.begin();
-                 j != m_myPerr.receivers.end();
-                 j++)
+            for (auto j = m_myPerr.receivers.begin(); j != m_myPerr.receivers.end(); j++)
             {
                 if ((*i) == (*j))
                 {
@@ -450,17 +441,10 @@
         }
     }
     {
-        std::vector<HwmpProtocol::FailedDestination>::const_iterator end = failedDestinations.end();
-        for (std::vector<HwmpProtocol::FailedDestination>::const_iterator i =
-                 failedDestinations.begin();
-             i != end;
-             i++)
+        for (auto i = failedDestinations.begin(); i != failedDestinations.end(); i++)
         {
             bool should_add = true;
-            for (std::vector<HwmpProtocol::FailedDestination>::const_iterator j =
-                     m_myPerr.destinations.begin();
-                 j != m_myPerr.destinations.end();
-                 j++)
+            for (auto j = m_myPerr.destinations.begin(); j != m_myPerr.destinations.end(); j++)
             {
                 if (((*i).destination == (*j).destination) && ((*j).seqnum > (*i).seqnum))
                 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/hwmp-protocol-mac.h ns-3.40/src/mesh/model/dot11s/hwmp-protocol-mac.h
--- ns-3.39/src/mesh/model/dot11s/hwmp-protocol-mac.h	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/hwmp-protocol-mac.h	2023-09-27 13:30:37.834839600 -0700
@@ -20,7 +20,8 @@
 #ifndef HWMP_STATE_H
 #define HWMP_STATE_H
 
-#include "ns3/hwmp-protocol.h"
+#include "hwmp-protocol.h"
+
 #include "ns3/mesh-wifi-interface-mac-plugin.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/hwmp-rtable.cc ns-3.40/src/mesh/model/dot11s/hwmp-rtable.cc
--- ns-3.39/src/mesh/model/dot11s/hwmp-rtable.cc	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/hwmp-rtable.cc	2023-09-27 13:30:37.834839600 -0700
@@ -70,7 +70,7 @@
 {
     NS_LOG_FUNCTION(this << destination << retransmitter << interface << metric
                          << lifetime.GetSeconds() << seqnum);
-    std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find(destination);
+    auto i = m_routes.find(destination);
     if (i == m_routes.end())
     {
         ReactiveRoute newroute;
@@ -113,7 +113,7 @@
     precursor.interface = precursorInterface;
     precursor.address = precursorAddress;
     precursor.whenExpire = Simulator::Now() + lifetime;
-    std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find(destination);
+    auto i = m_routes.find(destination);
     if (i != m_routes.end())
     {
         bool should_add = true;
@@ -161,7 +161,7 @@
 HwmpRtable::DeleteReactivePath(Mac48Address destination)
 {
     NS_LOG_FUNCTION(this << destination);
-    std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find(destination);
+    auto i = m_routes.find(destination);
     if (i != m_routes.end())
     {
         m_routes.erase(i);
@@ -172,7 +172,7 @@
 HwmpRtable::LookupReactive(Mac48Address destination)
 {
     NS_LOG_FUNCTION(this << destination);
-    std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find(destination);
+    auto i = m_routes.find(destination);
     if (i == m_routes.end())
     {
         return LookupResult();
@@ -189,7 +189,7 @@
 HwmpRtable::LookupReactiveExpired(Mac48Address destination)
 {
     NS_LOG_FUNCTION(this << destination);
-    std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find(destination);
+    auto i = m_routes.find(destination);
     if (i == m_routes.end())
     {
         return LookupResult();
@@ -232,8 +232,7 @@
     NS_LOG_FUNCTION(this << peerAddress);
     HwmpProtocol::FailedDestination dst;
     std::vector<HwmpProtocol::FailedDestination> retval;
-    for (std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.begin(); i != m_routes.end();
-         i++)
+    for (auto i = m_routes.begin(); i != m_routes.end(); i++)
     {
         if (i->second.retransmitter == peerAddress)
         {
@@ -259,12 +258,10 @@
     NS_LOG_FUNCTION(this << destination);
     // We suppose that no duplicates here can be
     PrecursorList retval;
-    std::map<Mac48Address, ReactiveRoute>::iterator route = m_routes.find(destination);
+    auto route = m_routes.find(destination);
     if (route != m_routes.end())
     {
-        for (std::vector<Precursor>::const_iterator i = route->second.precursors.begin();
-             i != route->second.precursors.end();
-             i++)
+        for (auto i = route->second.precursors.begin(); i != route->second.precursors.end(); i++)
         {
             if (i->whenExpire > Simulator::Now())
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/hwmp-rtable.h ns-3.40/src/mesh/model/dot11s/hwmp-rtable.h
--- ns-3.39/src/mesh/model/dot11s/hwmp-rtable.h	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/hwmp-rtable.h	2023-09-27 13:30:37.834839600 -0700
@@ -20,7 +20,8 @@
 #ifndef HWMP_RTABLE_H
 #define HWMP_RTABLE_H
 
-#include "ns3/hwmp-protocol.h"
+#include "hwmp-protocol.h"
+
 #include "ns3/mac48-address.h"
 #include "ns3/nstime.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/ie-dot11s-beacon-timing.cc ns-3.40/src/mesh/model/dot11s/ie-dot11s-beacon-timing.cc
--- ns-3.39/src/mesh/model/dot11s/ie-dot11s-beacon-timing.cc	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/ie-dot11s-beacon-timing.cc	2023-09-27 13:30:37.834839600 -0700
@@ -99,9 +99,7 @@
         return;
     }
     // First we lookup if this element already exists
-    for (NeighboursTimingUnitsList::const_iterator i = m_neighbours.begin();
-         i != m_neighbours.end();
-         i++)
+    for (auto i = m_neighbours.begin(); i != m_neighbours.end(); i++)
     {
         if (((*i)->GetAid() == AidToU8(aid)) &&
             ((*i)->GetLastBeacon() == TimestampToU16(last_beacon)) &&
@@ -121,7 +119,7 @@
 void
 IeBeaconTiming::DelNeighboursTimingElementUnit(uint16_t aid, Time last_beacon, Time beacon_interval)
 {
-    for (NeighboursTimingUnitsList::iterator i = m_neighbours.begin(); i != m_neighbours.end(); i++)
+    for (auto i = m_neighbours.begin(); i != m_neighbours.end(); i++)
     {
         if (((*i)->GetAid() == AidToU8(aid)) &&
             ((*i)->GetLastBeacon() == TimestampToU16(last_beacon)) &&
@@ -137,7 +135,7 @@
 void
 IeBeaconTiming::ClearTimingElement()
 {
-    for (NeighboursTimingUnitsList::iterator j = m_neighbours.begin(); j != m_neighbours.end(); j++)
+    for (auto j = m_neighbours.begin(); j != m_neighbours.end(); j++)
     {
         (*j) = nullptr;
     }
@@ -154,9 +152,7 @@
 IeBeaconTiming::Print(std::ostream& os) const
 {
     os << "BeaconTiming=(Number of units=" << (uint16_t)m_numOfUnits;
-    for (NeighboursTimingUnitsList::const_iterator j = m_neighbours.begin();
-         j != m_neighbours.end();
-         j++)
+    for (auto j = m_neighbours.begin(); j != m_neighbours.end(); j++)
     {
         os << "(AID=" << (uint16_t)(*j)->GetAid() << ", Last beacon at=" << (*j)->GetLastBeacon()
            << ", with beacon interval=" << (*j)->GetBeaconInterval() << ")";
@@ -167,9 +163,7 @@
 void
 IeBeaconTiming::SerializeInformationField(Buffer::Iterator i) const
 {
-    for (NeighboursTimingUnitsList::const_iterator j = m_neighbours.begin();
-         j != m_neighbours.end();
-         j++)
+    for (auto j = m_neighbours.begin(); j != m_neighbours.end(); j++)
     {
         i.WriteU8((*j)->GetAid());
         i.WriteHtolsbU16((*j)->GetLastBeacon());
@@ -223,7 +217,7 @@
 {
     try
     {
-        const IeBeaconTiming& aa = dynamic_cast<const IeBeaconTiming&>(a);
+        const auto& aa = dynamic_cast<const IeBeaconTiming&>(a);
 
         if (m_numOfUnits != aa.m_numOfUnits)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/ie-dot11s-perr.cc ns-3.40/src/mesh/model/dot11s/ie-dot11s-perr.cc
--- ns-3.39/src/mesh/model/dot11s/ie-dot11s-perr.cc	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/ie-dot11s-perr.cc	2023-09-27 13:30:37.834839600 -0700
@@ -140,9 +140,7 @@
 void
 IePerr::DeleteAddressUnit(Mac48Address address)
 {
-    for (std::vector<HwmpProtocol::FailedDestination>::iterator i = m_addressUnits.begin();
-         i != m_addressUnits.end();
-         i++)
+    for (auto i = m_addressUnits.begin(); i != m_addressUnits.end(); i++)
     {
         if (i->destination == address)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/ie-dot11s-perr.h ns-3.40/src/mesh/model/dot11s/ie-dot11s-perr.h
--- ns-3.39/src/mesh/model/dot11s/ie-dot11s-perr.h	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/ie-dot11s-perr.h	2023-09-27 13:30:37.834839600 -0700
@@ -20,7 +20,8 @@
 #ifndef PERR_INFORMATION_ELEMENT_H
 #define PERR_INFORMATION_ELEMENT_H
 
-#include "ns3/hwmp-protocol.h"
+#include "hwmp-protocol.h"
+
 #include "ns3/mac48-address.h"
 #include "ns3/mesh-information-element-vector.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/ie-dot11s-preq.cc ns-3.40/src/mesh/model/dot11s/ie-dot11s-preq.cc
--- ns-3.39/src/mesh/model/dot11s/ie-dot11s-preq.cc	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/ie-dot11s-preq.cc	2023-09-27 13:30:37.834839600 -0700
@@ -266,9 +266,7 @@
     i.WriteHtolsbU32(m_metric);
     i.WriteU8(m_destCount);
     int written = 0;
-    for (std::vector<Ptr<DestinationAddressUnit>>::const_iterator j = m_destinations.begin();
-         j != m_destinations.end();
-         j++)
+    for (auto j = m_destinations.begin(); j != m_destinations.end(); j++)
     {
         uint8_t flags = 0;
         if ((*j)->IsDo())
@@ -386,9 +384,7 @@
                                      Mac48Address dest_address,
                                      uint32_t dest_seq_number)
 {
-    for (std::vector<Ptr<DestinationAddressUnit>>::const_iterator i = m_destinations.begin();
-         i != m_destinations.end();
-         i++)
+    for (auto i = m_destinations.begin(); i != m_destinations.end(); i++)
     {
         if ((*i)->GetDestinationAddress() == dest_address)
         {
@@ -407,9 +403,7 @@
 void
 IePreq::DelDestinationAddressElement(Mac48Address dest_address)
 {
-    for (std::vector<Ptr<DestinationAddressUnit>>::iterator i = m_destinations.begin();
-         i != m_destinations.end();
-         i++)
+    for (auto i = m_destinations.begin(); i != m_destinations.end(); i++)
     {
         if ((*i)->GetDestinationAddress() == dest_address)
         {
@@ -423,9 +417,7 @@
 void
 IePreq::ClearDestinationAddressElements()
 {
-    for (std::vector<Ptr<DestinationAddressUnit>>::iterator j = m_destinations.begin();
-         j != m_destinations.end();
-         j++)
+    for (auto j = m_destinations.begin(); j != m_destinations.end(); j++)
     {
         (*j) = nullptr;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/peer-link.cc ns-3.40/src/mesh/model/dot11s/peer-link.cc
--- ns-3.39/src/mesh/model/dot11s/peer-link.cc	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/peer-link.cc	2023-09-27 13:30:37.834839600 -0700
@@ -19,7 +19,7 @@
  *          Pavel Boyko <boyko@iitp.ru>
  */
 
-#include "ns3/peer-link.h"
+#include "peer-link.h"
 
 #include "peer-management-protocol-mac.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/peer-link.h ns-3.40/src/mesh/model/dot11s/peer-link.h
--- ns-3.39/src/mesh/model/dot11s/peer-link.h	2023-07-05 14:23:48.033428200 -0700
+++ ns-3.40/src/mesh/model/dot11s/peer-link.h	2023-09-27 13:30:37.834839600 -0700
@@ -21,11 +21,12 @@
 #ifndef PEER_LINK_H
 #define PEER_LINK_H
 
+#include "ie-dot11s-beacon-timing.h"
+#include "ie-dot11s-configuration.h"
+#include "ie-dot11s-peer-management.h"
+
 #include "ns3/callback.h"
 #include "ns3/event-id.h"
-#include "ns3/ie-dot11s-beacon-timing.h"
-#include "ns3/ie-dot11s-configuration.h"
-#include "ns3/ie-dot11s-peer-management.h"
 #include "ns3/mac48-address.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/dot11s/peer-management-protocol.cc ns-3.40/src/mesh/model/dot11s/peer-management-protocol.cc
--- ns-3.39/src/mesh/model/dot11s/peer-management-protocol.cc	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/dot11s/peer-management-protocol.cc	2023-09-27 13:30:37.834839600 -0700
@@ -18,7 +18,7 @@
  *          Aleksey Kovalenko <kovalenko@iitp.ru>
  */
 
-#include "ns3/peer-management-protocol.h"
+#include "peer-management-protocol.h"
 
 #include "ie-dot11s-configuration.h"
 #include "ie-dot11s-id.h"
@@ -105,9 +105,9 @@
 {
     // cancel cleanup event and go through the map of peer links,
     // deleting each
-    for (PeerLinksMap::iterator j = m_peerLinks.begin(); j != m_peerLinks.end(); j++)
+    for (auto j = m_peerLinks.begin(); j != m_peerLinks.end(); j++)
     {
-        for (PeerLinksOnInterface::iterator i = j->second.begin(); i != j->second.end(); i++)
+        for (auto i = j->second.begin(); i != j->second.end(); i++)
         {
             (*i) = nullptr;
         }
@@ -121,7 +121,7 @@
 PeerManagementProtocol::Install(Ptr<MeshPointDevice> mp)
 {
     std::vector<Ptr<NetDevice>> interfaces = mp->GetInterfaces();
-    for (std::vector<Ptr<NetDevice>>::iterator i = interfaces.begin(); i != interfaces.end(); i++)
+    for (auto i = interfaces.begin(); i != interfaces.end(); i++)
     {
         Ptr<WifiNetDevice> wifiNetDev = (*i)->GetObject<WifiNetDevice>();
         if (!wifiNetDev)
@@ -154,9 +154,9 @@
         return nullptr;
     }
     Ptr<IeBeaconTiming> retval = Create<IeBeaconTiming>();
-    PeerLinksMap::iterator iface = m_peerLinks.find(interface);
+    auto iface = m_peerLinks.find(interface);
     NS_ASSERT(iface != m_peerLinks.end());
-    for (PeerLinksOnInterface::iterator i = iface->second.begin(); i != iface->second.end(); i++)
+    for (auto i = iface->second.begin(); i != iface->second.end(); i++)
     {
         // If we do not know peer Assoc Id, we shall not add any info
         // to a beacon timing element
@@ -180,8 +180,7 @@
 {
     // PM STATE Machine
     // Check that a given beacon is not from our interface
-    for (PeerManagementProtocolMacMap::const_iterator i = m_plugins.begin(); i != m_plugins.end();
-         i++)
+    for (auto i = m_plugins.begin(); i != m_plugins.end(); i++)
     {
         if (i->second->GetAddress() == peerAddress)
         {
@@ -304,9 +303,9 @@
         NS_FATAL_ERROR("Peer link must not exist.");
     }
     // Plugin must exist
-    PeerManagementProtocolMacMap::iterator plugin = m_plugins.find(interface);
+    auto plugin = m_plugins.find(interface);
     NS_ASSERT(plugin != m_plugins.end());
-    PeerLinksMap::iterator iface = m_peerLinks.find(interface);
+    auto iface = m_peerLinks.find(interface);
     NS_ASSERT(iface != m_peerLinks.end());
     new_link->SetLocalAid(m_lastAssocId++);
     new_link->SetInterface(interface);
@@ -323,9 +322,9 @@
 Ptr<PeerLink>
 PeerManagementProtocol::FindPeerLink(uint32_t interface, Mac48Address peerAddress)
 {
-    PeerLinksMap::iterator iface = m_peerLinks.find(interface);
+    auto iface = m_peerLinks.find(interface);
     NS_ASSERT(iface != m_peerLinks.end());
-    for (PeerLinksOnInterface::iterator i = iface->second.begin(); i != iface->second.end(); i++)
+    for (auto i = iface->second.begin(); i != iface->second.end(); i++)
     {
         if ((*i)->GetPeerAddress() == peerAddress)
         {
@@ -355,10 +354,9 @@
 PeerManagementProtocol::GetPeers(uint32_t interface) const
 {
     std::vector<Mac48Address> retval;
-    PeerLinksMap::const_iterator iface = m_peerLinks.find(interface);
+    auto iface = m_peerLinks.find(interface);
     NS_ASSERT(iface != m_peerLinks.end());
-    for (PeerLinksOnInterface::const_iterator i = iface->second.begin(); i != iface->second.end();
-         i++)
+    for (auto i = iface->second.begin(); i != iface->second.end(); i++)
     {
         if ((*i)->LinkIsEstab())
         {
@@ -373,12 +371,9 @@
 {
     std::vector<Ptr<PeerLink>> links;
 
-    for (PeerLinksMap::const_iterator iface = m_peerLinks.begin(); iface != m_peerLinks.end();
-         ++iface)
+    for (auto iface = m_peerLinks.begin(); iface != m_peerLinks.end(); ++iface)
     {
-        for (PeerLinksOnInterface::const_iterator i = iface->second.begin();
-             i != iface->second.end();
-             i++)
+        for (auto i = iface->second.begin(); i != iface->second.end(); i++)
         {
             if ((*i)->LinkIsEstab())
             {
@@ -426,19 +421,18 @@
     {
         return;
     }
-    PeerLinksMap::iterator iface = m_peerLinks.find(interface);
+    auto iface = m_peerLinks.find(interface);
     NS_ASSERT(iface != m_peerLinks.end());
     NS_ASSERT(m_plugins.find(interface) != m_plugins.end());
 
-    std::map<uint32_t, Time>::const_iterator lastBeacon = m_lastBeacon.find(interface);
-    std::map<uint32_t, Time>::const_iterator beaconInterval = m_beaconInterval.find(interface);
+    auto lastBeacon = m_lastBeacon.find(interface);
+    auto beaconInterval = m_beaconInterval.find(interface);
     if ((lastBeacon == m_lastBeacon.end()) || (beaconInterval == m_beaconInterval.end()))
     {
         return;
     }
     // my last beacon in 256 us units
-    uint16_t lastBeaconInTimeElement =
-        (uint16_t)((lastBeacon->second.GetMicroSeconds() >> 8) & 0xffff);
+    auto lastBeaconInTimeElement = (uint16_t)((lastBeacon->second.GetMicroSeconds() >> 8) & 0xffff);
 
     NS_ASSERT_MSG(TuToTime(m_maxBeaconShift) <= m_beaconInterval[interface],
                   "Wrong beacon shift parameters");
@@ -451,14 +445,12 @@
     }
     // check whether all my peers receive my beacon and I'am not in collision with other beacons
 
-    for (PeerLinksOnInterface::iterator i = iface->second.begin(); i != iface->second.end(); i++)
+    for (auto i = iface->second.begin(); i != iface->second.end(); i++)
     {
         bool myBeaconExists = false;
         IeBeaconTiming::NeighboursTimingUnitsList neighbors =
             (*i)->GetBeaconTimingElement().GetNeighboursTimingElementsList();
-        for (IeBeaconTiming::NeighboursTimingUnitsList::const_iterator j = neighbors.begin();
-             j != neighbors.end();
-             j++)
+        for (auto j = neighbors.begin(); j != neighbors.end(); j++)
         {
             if ((*i)->GetPeerAid() == (*j)->GetAid())
             {
@@ -494,7 +486,7 @@
         shift = (int)m_beaconShift->GetValue();
     } while (shift == 0);
     // Apply beacon shift parameters:
-    PeerManagementProtocolMacMap::iterator plugin = m_plugins.find(interface);
+    auto plugin = m_plugins.find(interface);
     NS_ASSERT(plugin != m_plugins.end());
     plugin->second->SetBeaconShift(TuToTime(shift));
 }
@@ -550,7 +542,7 @@
                                        PeerLink::PeerState ostate,
                                        PeerLink::PeerState nstate)
 {
-    PeerManagementProtocolMacMap::iterator plugin = m_plugins.find(interface);
+    auto plugin = m_plugins.find(interface);
     NS_ASSERT(plugin != m_plugins.end());
     NS_LOG_DEBUG("Link between me:" << m_address << " my interface:" << plugin->second->GetAddress()
                                     << " and peer mesh point:" << peerMeshPointAddress
@@ -635,18 +627,14 @@
 {
     os << "<PeerManagementProtocol>" << std::endl;
     m_stats.Print(os);
-    for (PeerManagementProtocolMacMap::const_iterator plugins = m_plugins.begin();
-         plugins != m_plugins.end();
-         plugins++)
+    for (auto plugins = m_plugins.begin(); plugins != m_plugins.end(); plugins++)
     {
         // Take statistics from plugin:
         plugins->second->Report(os);
         // Print all active peer links:
-        PeerLinksMap::const_iterator iface = m_peerLinks.find(plugins->second->m_ifIndex);
+        auto iface = m_peerLinks.find(plugins->second->m_ifIndex);
         NS_ASSERT(iface != m_peerLinks.end());
-        for (PeerLinksOnInterface::const_iterator i = iface->second.begin();
-             i != iface->second.end();
-             i++)
+        for (auto i = iface->second.begin(); i != iface->second.end(); i++)
         {
             (*i)->Report(os);
         }
@@ -658,9 +646,7 @@
 PeerManagementProtocol::ResetStats()
 {
     m_stats = Statistics(m_stats.linksTotal); // don't reset number of links
-    for (PeerManagementProtocolMacMap::const_iterator plugins = m_plugins.begin();
-         plugins != m_plugins.end();
-         plugins++)
+    for (auto plugins = m_plugins.begin(); plugins != m_plugins.end(); plugins++)
     {
         plugins->second->ResetStats();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/flame/flame-protocol.cc ns-3.40/src/mesh/model/flame/flame-protocol.cc
--- ns-3.39/src/mesh/model/flame/flame-protocol.cc	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/flame/flame-protocol.cc	2023-09-27 13:30:37.834839600 -0700
@@ -324,8 +324,7 @@
 {
     m_mp = mp;
     std::vector<Ptr<NetDevice>> interfaces = mp->GetInterfaces();
-    for (std::vector<Ptr<NetDevice>>::const_iterator i = interfaces.begin(); i != interfaces.end();
-         i++)
+    for (auto i = interfaces.begin(); i != interfaces.end(); i++)
     {
         // Checking for compatible net device
         Ptr<WifiNetDevice> wifiNetDev = (*i)->GetObject<WifiNetDevice>();
@@ -423,8 +422,7 @@
        << "broadcastInterval=\"" << m_broadcastInterval.GetSeconds() << "\"" << std::endl
        << "maxCost=\"" << (uint16_t)m_maxCost << "\">" << std::endl;
     m_stats.Print(os);
-    for (FlamePluginMap::const_iterator plugin = m_interfaces.begin(); plugin != m_interfaces.end();
-         plugin++)
+    for (auto plugin = m_interfaces.begin(); plugin != m_interfaces.end(); plugin++)
     {
         plugin->second->Report(os);
     }
@@ -435,8 +433,7 @@
 FlameProtocol::ResetStats()
 {
     m_stats = Statistics();
-    for (FlamePluginMap::const_iterator plugin = m_interfaces.begin(); plugin != m_interfaces.end();
-         plugin++)
+    for (auto plugin = m_interfaces.begin(); plugin != m_interfaces.end(); plugin++)
     {
         plugin->second->ResetStats();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/flame/flame-rtable.cc ns-3.40/src/mesh/model/flame/flame-rtable.cc
--- ns-3.39/src/mesh/model/flame/flame-rtable.cc	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/flame/flame-rtable.cc	2023-09-27 13:30:37.834839600 -0700
@@ -70,7 +70,7 @@
                      const uint8_t cost,
                      const uint16_t seqnum)
 {
-    std::map<Mac48Address, Route>::iterator i = m_routes.find(destination);
+    auto i = m_routes.find(destination);
     if (i == m_routes.end())
     {
         Route newroute;
@@ -93,7 +93,7 @@
 FlameRtable::LookupResult
 FlameRtable::Lookup(Mac48Address destination)
 {
-    std::map<Mac48Address, Route>::iterator i = m_routes.find(destination);
+    auto i = m_routes.find(destination);
     if (i == m_routes.end())
     {
         return LookupResult();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/mesh-information-element-vector.cc ns-3.40/src/mesh/model/mesh-information-element-vector.cc
--- ns-3.39/src/mesh/model/mesh-information-element-vector.cc	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/mesh-information-element-vector.cc	2023-09-27 13:30:37.834839600 -0700
@@ -47,7 +47,7 @@
 
 MeshInformationElementVector::~MeshInformationElementVector()
 {
-    for (IE_VECTOR::iterator i = m_elements.begin(); i != m_elements.end(); i++)
+    for (auto i = m_elements.begin(); i != m_elements.end(); i++)
     {
         *i = nullptr;
     }
@@ -79,7 +79,7 @@
 void
 MeshInformationElementVector::Serialize(Buffer::Iterator start) const
 {
-    for (IE_VECTOR::const_iterator i = m_elements.begin(); i != m_elements.end(); i++)
+    for (auto i = m_elements.begin(); i != m_elements.end(); i++)
     {
         start = (*i)->Serialize(start);
     }
@@ -164,7 +164,7 @@
 void
 MeshInformationElementVector::Print(std::ostream& os) const
 {
-    for (IE_VECTOR::const_iterator i = m_elements.begin(); i != m_elements.end(); i++)
+    for (auto i = m_elements.begin(); i != m_elements.end(); i++)
     {
         os << "(";
         (*i)->Print(os);
@@ -198,7 +198,7 @@
 Ptr<WifiInformationElement>
 MeshInformationElementVector::FindFirst(WifiInformationElementId id) const
 {
-    for (IE_VECTOR::const_iterator i = m_elements.begin(); i != m_elements.end(); i++)
+    for (auto i = m_elements.begin(); i != m_elements.end(); i++)
     {
         if ((*i)->ElementId() == id)
         {
@@ -212,7 +212,7 @@
 MeshInformationElementVector::GetSize() const
 {
     uint32_t size = 0;
-    for (IE_VECTOR::const_iterator i = m_elements.begin(); i != m_elements.end(); i++)
+    for (auto i = m_elements.begin(); i != m_elements.end(); i++)
     {
         size += (*i)->GetSerializedSize();
     }
@@ -234,10 +234,8 @@
     // I'm leaving it like this, however, so that there is the option of
     // having individual Information Elements implement slightly more
     // flexible equality operators.
-    MeshInformationElementVector::IE_VECTOR::const_iterator j = a.m_elements.begin();
-    for (MeshInformationElementVector::IE_VECTOR::const_iterator i = m_elements.begin();
-         i != m_elements.end();
-         i++, j++)
+    auto j = a.m_elements.begin();
+    for (auto i = m_elements.begin(); i != m_elements.end(); i++, j++)
     {
         if (!(*(*i) == *(*j)))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/mesh-l2-routing-protocol.cc ns-3.40/src/mesh/model/mesh-l2-routing-protocol.cc
--- ns-3.39/src/mesh/model/mesh-l2-routing-protocol.cc	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/mesh-l2-routing-protocol.cc	2023-09-27 13:30:37.834839600 -0700
@@ -18,10 +18,11 @@
  *          Pavel Boyko <boyko@iitp.ru>
  */
 
-#include "ns3/mesh-l2-routing-protocol.h"
+#include "mesh-l2-routing-protocol.h"
+
+#include "mesh-point-device.h"
 
 #include "ns3/log.h"
-#include "ns3/mesh-point-device.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/mesh-point-device.cc ns-3.40/src/mesh/model/mesh-point-device.cc
--- ns-3.39/src/mesh/model/mesh-point-device.cc	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/mesh-point-device.cc	2023-09-27 13:30:37.834839600 -0700
@@ -18,10 +18,11 @@
  *         Pavel Boyko <boyko@iitp.ru>
  */
 
-#include "ns3/mesh-point-device.h"
+#include "mesh-point-device.h"
+
+#include "mesh-wifi-interface-mac.h"
 
 #include "ns3/log.h"
-#include "ns3/mesh-wifi-interface-mac.h"
 #include "ns3/packet.h"
 #include "ns3/pointer.h"
 #include "ns3/simulator.h"
@@ -82,8 +83,7 @@
 MeshPointDevice::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (std::vector<Ptr<NetDevice>>::iterator iter = m_ifaces.begin(); iter != m_ifaces.end();
-         iter++)
+    for (auto iter = m_ifaces.begin(); iter != m_ifaces.end(); iter++)
     {
         *iter = nullptr;
     }
@@ -398,7 +398,7 @@
 MeshPointDevice::GetInterface(uint32_t n) const
 {
     NS_LOG_FUNCTION(this << n);
-    for (std::vector<Ptr<NetDevice>>::const_iterator i = m_ifaces.begin(); i != m_ifaces.end(); i++)
+    for (auto i = m_ifaces.begin(); i != m_ifaces.end(); i++)
     {
         if ((*i)->GetIfIndex() == n)
         {
@@ -515,7 +515,7 @@
     }
     else
     {
-        for (std::vector<Ptr<NetDevice>>::iterator i = m_ifaces.begin(); i != m_ifaces.end(); i++)
+        for (auto i = m_ifaces.begin(); i != m_ifaces.end(); i++)
         {
             (*i)->SendFrom(packet->Copy(), src, dst, protocol);
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/mesh-point-device.h ns-3.40/src/mesh/model/mesh-point-device.h
--- ns-3.39/src/mesh/model/mesh-point-device.h	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/mesh-point-device.h	2023-09-27 13:30:37.834839600 -0700
@@ -21,9 +21,10 @@
 #ifndef L2ROUTING_NET_DEVICE_H
 #define L2ROUTING_NET_DEVICE_H
 
+#include "mesh-l2-routing-protocol.h"
+
 #include "ns3/bridge-channel.h"
 #include "ns3/mac48-address.h"
-#include "ns3/mesh-l2-routing-protocol.h"
 #include "ns3/net-device.h"
 #include "ns3/node.h"
 #include "ns3/random-variable-stream.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/mesh-wifi-beacon.cc ns-3.40/src/mesh/model/mesh-wifi-beacon.cc
--- ns-3.39/src/mesh/model/mesh-wifi-beacon.cc	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/mesh-wifi-beacon.cc	2023-09-27 13:30:37.834839600 -0700
@@ -17,7 +17,7 @@
  * Author: Pavel Boyko <boyko@iitp.ru>
  */
 
-#include "ns3/mesh-wifi-beacon.h"
+#include "mesh-wifi-beacon.h"
 
 #include "ns3/nstime.h"
 #include "ns3/wifi-mac-header.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/mesh-wifi-beacon.h ns-3.40/src/mesh/model/mesh-wifi-beacon.h
--- ns-3.39/src/mesh/model/mesh-wifi-beacon.h	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/mesh-wifi-beacon.h	2023-09-27 13:30:37.834839600 -0700
@@ -20,7 +20,8 @@
 #ifndef MESH_WIFI_BEACON_H
 #define MESH_WIFI_BEACON_H
 
-#include "ns3/mesh-information-element-vector.h"
+#include "mesh-information-element-vector.h"
+
 #include "ns3/mgt-headers.h"
 #include "ns3/object.h"
 #include "ns3/packet.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/mesh-wifi-interface-mac.cc ns-3.40/src/mesh/model/mesh-wifi-interface-mac.cc
--- ns-3.39/src/mesh/model/mesh-wifi-interface-mac.cc	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/mesh-wifi-interface-mac.cc	2023-09-27 13:30:37.834839600 -0700
@@ -18,14 +18,15 @@
  *          Pavel Boyko <boyko@iitp.ru>
  */
 
-#include "ns3/mesh-wifi-interface-mac.h"
+#include "mesh-wifi-interface-mac.h"
+
+#include "mesh-wifi-beacon.h"
 
 #include "ns3/boolean.h"
 #include "ns3/channel-access-manager.h"
 #include "ns3/double.h"
 #include "ns3/log.h"
 #include "ns3/mac-tx-middle.h"
-#include "ns3/mesh-wifi-beacon.h"
 #include "ns3/pointer.h"
 #include "ns3/qos-txop.h"
 #include "ns3/random-variable-stream.h"
@@ -166,7 +167,7 @@
     NS_LOG_FUNCTION(this << stream);
     int64_t currentStream = stream;
     m_coefficient->SetStream(currentStream++);
-    for (PluginList::const_iterator i = m_plugins.begin(); i < m_plugins.end(); i++)
+    for (auto i = m_plugins.begin(); i < m_plugins.end(); i++)
     {
         currentStream += (*i)->AssignStreams(currentStream);
     }
@@ -239,7 +240,7 @@
     // Address 1 is unknown here. Routing plugin is responsible to correctly set it.
     hdr.SetAddr1(Mac48Address());
     // Filter packet through all installed plugins
-    for (PluginList::const_iterator i = m_plugins.end() - 1; i != m_plugins.begin() - 1; i--)
+    for (auto i = m_plugins.end() - 1; i != m_plugins.begin() - 1; i--)
     {
         bool drop = !((*i)->UpdateOutcomingFrame(packet, hdr, from, to));
         if (drop)
@@ -285,7 +286,7 @@
 {
     // Filter management frames:
     WifiMacHeader header = hdr;
-    for (PluginList::const_iterator i = m_plugins.end() - 1; i != m_plugins.begin() - 1; i--)
+    for (auto i = m_plugins.end() - 1; i != m_plugins.begin() - 1; i--)
     {
         bool drop = !((*i)->UpdateOutcomingFrame(packet, header, Mac48Address(), Mac48Address()));
         if (drop)
@@ -428,7 +429,7 @@
     MeshWifiBeacon beacon(GetSsid(), GetSupportedRates(), m_beaconInterval.GetMicroSeconds());
 
     // Ask all plugins to add their specific information elements to beacon
-    for (PluginList::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i)
+    for (auto i = m_plugins.begin(); i != m_plugins.end(); ++i)
     {
         (*i)->UpdateBeacon(beacon);
     }
@@ -486,7 +487,7 @@
         m_stats.recvFrames++;
     }
     // Filter frame through all installed plugins
-    for (PluginList::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i)
+    for (auto i = m_plugins.begin(); i != m_plugins.end(); ++i)
     {
         bool drop = !((*i)->Receive(packet, *hdr));
         if (drop)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/mesh-wifi-interface-mac.h ns-3.40/src/mesh/model/mesh-wifi-interface-mac.h
--- ns-3.39/src/mesh/model/mesh-wifi-interface-mac.h	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/mesh-wifi-interface-mac.h	2023-09-27 13:30:37.834839600 -0700
@@ -21,10 +21,11 @@
 #ifndef MESH_WIFI_INTERFACE_MAC_H
 #define MESH_WIFI_INTERFACE_MAC_H
 
+#include "mesh-wifi-interface-mac-plugin.h"
+
 #include "ns3/callback.h"
 #include "ns3/event-id.h"
 #include "ns3/mac48-address.h"
-#include "ns3/mesh-wifi-interface-mac-plugin.h"
 #include "ns3/mgt-headers.h"
 #include "ns3/nstime.h"
 #include "ns3/packet.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/model/mesh-wifi-interface-mac-plugin.h ns-3.40/src/mesh/model/mesh-wifi-interface-mac-plugin.h
--- ns-3.39/src/mesh/model/mesh-wifi-interface-mac-plugin.h	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/model/mesh-wifi-interface-mac-plugin.h	2023-09-27 13:30:37.834839600 -0700
@@ -20,8 +20,9 @@
 #ifndef MESH_WIFI_INTERFACE_MAC_PLUGIN_H
 #define MESH_WIFI_INTERFACE_MAC_PLUGIN_H
 
+#include "mesh-wifi-beacon.h"
+
 #include "ns3/mac48-address.h"
-#include "ns3/mesh-wifi-beacon.h"
 #include "ns3/packet.h"
 #include "ns3/simple-ref-count.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mesh/test/dot11s/dot11s-test-suite.cc ns-3.40/src/mesh/test/dot11s/dot11s-test-suite.cc
--- ns-3.39/src/mesh/test/dot11s/dot11s-test-suite.cc	2023-07-05 14:23:48.037428100 -0700
+++ ns-3.40/src/mesh/test/dot11s/dot11s-test-suite.cc	2023-09-27 13:30:37.834839600 -0700
@@ -186,8 +186,7 @@
 void
 HwmpRtableTest::TestPrecursorAdd()
 {
-    for (std::vector<Mac48Address>::const_iterator i = precursors.begin(); i != precursors.end();
-         i++)
+    for (auto i = precursors.begin(); i != precursors.end(); i++)
     {
         table->AddPrecursor(dst, iface, *i, Seconds(100));
         // Check that duplicates are filtered
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/CMakeLists.txt ns-3.40/src/mobility/CMakeLists.txt
--- ns-3.39/src/mobility/CMakeLists.txt	2023-07-05 14:23:48.041428000 -0700
+++ ns-3.40/src/mobility/CMakeLists.txt	2023-09-27 13:30:37.838839500 -0700
@@ -50,6 +50,7 @@
     test/mobility-trace-test-suite.cc
     test/ns2-mobility-helper-test-suite.cc
     test/rand-cart-around-geo-test.cc
+    test/rectangle-closest-border-test.cc
     test/steady-state-random-waypoint-mobility-model-test.cc
     test/waypoint-mobility-model-test.cc
 )
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/examples/main-grid-topology.cc ns-3.40/src/mobility/examples/main-grid-topology.cc
--- ns-3.39/src/mobility/examples/main-grid-topology.cc	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/examples/main-grid-topology.cc	2023-09-27 13:30:37.838839500 -0700
@@ -61,7 +61,7 @@
     mobility.Install(nodes);
 
     // iterate our nodes and print their position.
-    for (NodeContainer::Iterator j = nodes.Begin(); j != nodes.End(); ++j)
+    for (auto j = nodes.Begin(); j != nodes.End(); ++j)
     {
         Ptr<Node> object = *j;
         Ptr<MobilityModel> position = object->GetObject<MobilityModel>();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/helper/group-mobility-helper.cc ns-3.40/src/mobility/helper/group-mobility-helper.cc
--- ns-3.39/src/mobility/helper/group-mobility-helper.cc	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/helper/group-mobility-helper.cc	2023-09-27 13:30:37.838839500 -0700
@@ -19,7 +19,7 @@
  * Adapted from 'mobility-helper.cc' for group mobility by Tom Henderson
  */
 
-#include "ns3/group-mobility-helper.h"
+#include "group-mobility-helper.h"
 
 #include "ns3/config.h"
 #include "ns3/hierarchical-mobility-model.h"
@@ -101,7 +101,7 @@
 void
 GroupMobilityHelper::Install(NodeContainer c)
 {
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Install(*i);
     }
@@ -114,7 +114,7 @@
     Ptr<Node> node;
     bool firstNode = true;
     Ptr<HierarchicalMobilityModel> mobility;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         node = (*i);
         mobility = node->GetObject<HierarchicalMobilityModel>();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/helper/mobility-helper.cc ns-3.40/src/mobility/helper/mobility-helper.cc
--- ns-3.39/src/mobility/helper/mobility-helper.cc	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/helper/mobility-helper.cc	2023-09-27 13:30:37.838839500 -0700
@@ -16,7 +16,7 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
-#include "ns3/mobility-helper.h"
+#include "mobility-helper.h"
 
 #include "ns3/config.h"
 #include "ns3/hierarchical-mobility-model.h"
@@ -126,7 +126,7 @@
 void
 MobilityHelper::Install(NodeContainer c) const
 {
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Install(*i);
     }
@@ -201,7 +201,7 @@
 void
 MobilityHelper::EnableAscii(Ptr<OutputStreamWrapper> stream, NodeContainer n)
 {
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         EnableAscii(stream, (*i)->GetId());
     }
@@ -219,7 +219,7 @@
     int64_t currentStream = stream;
     Ptr<Node> node;
     Ptr<MobilityModel> mobility;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         node = (*i);
         mobility = node->GetObject<MobilityModel>();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/helper/ns2-mobility-helper.cc ns-3.40/src/mobility/helper/ns2-mobility-helper.cc
--- ns-3.39/src/mobility/helper/ns2-mobility-helper.cc	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/helper/ns2-mobility-helper.cc	2023-09-27 13:30:37.838839500 -0700
@@ -523,7 +523,7 @@
     {
         std::string x;
         s >> x;
-        if (x.length() == 0)
+        if (x.empty())
         {
             continue;
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/model/constant-velocity-helper.cc ns-3.40/src/mobility/model/constant-velocity-helper.cc
--- ns-3.39/src/mobility/model/constant-velocity-helper.cc	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/model/constant-velocity-helper.cc	2023-09-27 13:30:37.838839500 -0700
@@ -18,9 +18,10 @@
  */
 #include "constant-velocity-helper.h"
 
-#include "ns3/box.h"
+#include "box.h"
+#include "rectangle.h"
+
 #include "ns3/log.h"
-#include "ns3/rectangle.h"
 #include "ns3/simulator.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/model/constant-velocity-helper.h ns-3.40/src/mobility/model/constant-velocity-helper.h
--- ns-3.39/src/mobility/model/constant-velocity-helper.h	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/model/constant-velocity-helper.h	2023-09-27 13:30:37.838839500 -0700
@@ -19,7 +19,8 @@
 #ifndef CONSTANT_VELOCITY_HELPER_H
 #define CONSTANT_VELOCITY_HELPER_H
 
-#include "ns3/box.h"
+#include "box.h"
+
 #include "ns3/nstime.h"
 #include "ns3/vector.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/model/gauss-markov-mobility-model.h ns-3.40/src/mobility/model/gauss-markov-mobility-model.h
--- ns-3.39/src/mobility/model/gauss-markov-mobility-model.h	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/model/gauss-markov-mobility-model.h	2023-09-27 13:30:37.838839500 -0700
@@ -21,11 +21,11 @@
 #ifndef GAUSS_MARKOV_MOBILITY_MODEL_H
 #define GAUSS_MARKOV_MOBILITY_MODEL_H
 
+#include "box.h"
 #include "constant-velocity-helper.h"
 #include "mobility-model.h"
 #include "position-allocator.h"
 
-#include "ns3/box.h"
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/model/random-direction-2d-mobility-model.cc ns-3.40/src/mobility/model/random-direction-2d-mobility-model.cc
--- ns-3.39/src/mobility/model/random-direction-2d-mobility-model.cc	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/model/random-direction-2d-mobility-model.cc	2023-09-27 13:30:37.842839700 -0700
@@ -117,23 +117,36 @@
 void
 RandomDirection2dMobilityModel::ResetDirectionAndSpeed()
 {
-    double direction = m_direction->GetValue(0, M_PI);
+    double direction = 0;
 
     m_helper.UpdateWithBounds(m_bounds);
     Vector position = m_helper.GetCurrentPosition();
-    switch (m_bounds.GetClosestSide(position))
+    switch (m_bounds.GetClosestSideOrCorner(position))
     {
-    case Rectangle::RIGHT:
-        direction += M_PI / 2;
+    case Rectangle::RIGHTSIDE:
+        direction = m_direction->GetValue(M_PI_2, M_PI + M_PI_2);
+        break;
+    case Rectangle::LEFTSIDE:
+        direction = m_direction->GetValue(-M_PI_2, M_PI - M_PI_2);
+        break;
+    case Rectangle::TOPSIDE:
+        direction = m_direction->GetValue(M_PI, 2 * M_PI);
         break;
-    case Rectangle::LEFT:
-        direction += -M_PI / 2;
+    case Rectangle::BOTTOMSIDE:
+        direction = m_direction->GetValue(0, M_PI);
         break;
-    case Rectangle::TOP:
-        direction += M_PI;
+    case Rectangle::TOPRIGHTCORNER:
+        direction = m_direction->GetValue(M_PI, M_PI + M_PI_2);
+        break;
+    case Rectangle::TOPLEFTCORNER:
+        direction = m_direction->GetValue(M_PI + M_PI_2, 2 * M_PI);
+        break;
+    case Rectangle::BOTTOMRIGHTCORNER:
+        direction = m_direction->GetValue(0, M_PI_2);
+        direction += M_PI / 2;
         break;
-    case Rectangle::BOTTOM:
-        direction += 0.0;
+    case Rectangle::BOTTOMLEFTCORNER:
+        direction = m_direction->GetValue(M_PI_2, M_PI);
         break;
     }
     SetDirectionAndSpeed(direction);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/model/random-direction-2d-mobility-model.h ns-3.40/src/mobility/model/random-direction-2d-mobility-model.h
--- ns-3.39/src/mobility/model/random-direction-2d-mobility-model.h	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/model/random-direction-2d-mobility-model.h	2023-09-27 13:30:37.842839700 -0700
@@ -21,13 +21,13 @@
 
 #include "constant-velocity-helper.h"
 #include "mobility-model.h"
+#include "rectangle.h"
 
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
 #include "ns3/ptr.h"
 #include "ns3/random-variable-stream.h"
-#include "ns3/rectangle.h"
 
 namespace ns3
 {
@@ -40,7 +40,7 @@
  * pauses for a specific delay, chooses a random direction and speed and
  * then travels in the specific direction until it reaches one of
  * the boundaries of the model. When it reaches the boundary, it pauses,
- * selects a new direction and speed, aso.
+ * and selects a new direction and speed.
  */
 class RandomDirection2dMobilityModel : public MobilityModel
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/model/random-walk-2d-mobility-model.cc ns-3.40/src/mobility/model/random-walk-2d-mobility-model.cc
--- ns-3.39/src/mobility/model/random-walk-2d-mobility-model.cc	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/model/random-walk-2d-mobility-model.cc	2023-09-27 13:30:37.842839700 -0700
@@ -90,8 +90,46 @@
 RandomWalk2dMobilityModel::DoInitializePrivate()
 {
     m_helper.Update();
+    Vector position = m_helper.GetCurrentPosition();
+
     double speed = m_speed->GetValue();
-    double direction = m_direction->GetValue();
+    double direction = 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);
+            break;
+        case Rectangle::LEFTSIDE:
+            direction = directionOverride->GetValue(-M_PI_2, M_PI - M_PI_2);
+            break;
+        case Rectangle::TOPSIDE:
+            direction = directionOverride->GetValue(M_PI, 2 * M_PI);
+            break;
+        case Rectangle::BOTTOMSIDE:
+            direction = directionOverride->GetValue(0, M_PI);
+            break;
+        case Rectangle::TOPRIGHTCORNER:
+            direction = directionOverride->GetValue(M_PI, M_PI + M_PI_2);
+            break;
+        case Rectangle::TOPLEFTCORNER:
+            direction = directionOverride->GetValue(M_PI + M_PI_2, 2 * M_PI);
+            break;
+        case Rectangle::BOTTOMRIGHTCORNER:
+            direction = directionOverride->GetValue(0, M_PI_2);
+            direction += M_PI / 2;
+            break;
+        case Rectangle::BOTTOMLEFTCORNER:
+            direction = directionOverride->GetValue(M_PI_2, M_PI);
+            break;
+        }
+    }
     Vector vector(std::cos(direction) * speed, std::sin(direction) * speed, 0.0);
     m_helper.SetVelocity(vector);
     m_helper.Unpause();
@@ -125,7 +163,23 @@
     else
     {
         nextPosition = m_bounds.CalculateIntersection(position, speed);
-        Time delay = Seconds((nextPosition.x - position.x) / speed.x);
+        double delaySeconds = std::numeric_limits<double>::max();
+        if (speed.x != 0)
+        {
+            delaySeconds =
+                std::min(delaySeconds, std::abs((nextPosition.x - position.x) / speed.x));
+        }
+        else if (speed.y != 0)
+        {
+            delaySeconds =
+                std::min(delaySeconds, std::abs((nextPosition.y - position.y) / speed.y));
+        }
+        else
+        {
+            NS_ABORT_MSG("RandomWalk2dMobilityModel::DoWalk: unable to calculate the rebound time "
+                         "(the node is stationary).");
+        }
+        Time delay = Seconds(delaySeconds);
         m_event = Simulator::Schedule(delay,
                                       &RandomWalk2dMobilityModel::Rebound,
                                       this,
@@ -140,16 +194,24 @@
     m_helper.UpdateWithBounds(m_bounds);
     Vector position = m_helper.GetCurrentPosition();
     Vector speed = m_helper.GetVelocity();
-    switch (m_bounds.GetClosestSide(position))
+    switch (m_bounds.GetClosestSideOrCorner(position))
     {
-    case Rectangle::RIGHT:
-    case Rectangle::LEFT:
+    case Rectangle::RIGHTSIDE:
+    case Rectangle::LEFTSIDE:
         speed.x = -speed.x;
         break;
-    case Rectangle::TOP:
-    case Rectangle::BOTTOM:
+    case Rectangle::TOPSIDE:
+    case Rectangle::BOTTOMSIDE:
         speed.y = -speed.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;
+        break;
     }
     m_helper.SetVelocity(speed);
     m_helper.Unpause();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/model/random-walk-2d-mobility-model.h ns-3.40/src/mobility/model/random-walk-2d-mobility-model.h
--- ns-3.39/src/mobility/model/random-walk-2d-mobility-model.h	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/model/random-walk-2d-mobility-model.h	2023-09-27 13:30:37.842839700 -0700
@@ -21,12 +21,12 @@
 
 #include "constant-velocity-helper.h"
 #include "mobility-model.h"
+#include "rectangle.h"
 
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
 #include "ns3/random-variable-stream.h"
-#include "ns3/rectangle.h"
 
 namespace ns3
 {
@@ -42,6 +42,11 @@
  * of the model, we rebound on the boundary with a reflexive angle
  * and speed. This model is often identified as a brownian motion
  * model.
+ *
+ * The Direction random variable is used for any point strictly
+ * inside the boundaries. The points on the boundary have their
+ * direction chosen randomly, without considering the Direction
+ * Attribute.
  */
 class RandomWalk2dMobilityModel : public MobilityModel
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/model/rectangle.cc ns-3.40/src/mobility/model/rectangle.cc
--- ns-3.39/src/mobility/model/rectangle.cc	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/model/rectangle.cc	2023-09-27 13:30:37.842839700 -0700
@@ -23,6 +23,7 @@
 #include "ns3/vector.h"
 
 #include <algorithm>
+#include <array>
 #include <cmath>
 #include <sstream>
 
@@ -52,126 +53,99 @@
            position.y >= this->yMin;
 }
 
+bool
+Rectangle::IsOnTheBorder(const Vector& position) const
+{
+    return position.x == this->xMax || position.x == this->xMin || position.y == this->yMax ||
+           position.y == this->yMin;
+}
+
 Rectangle::Side
-Rectangle::GetClosestSide(const Vector& position) const
+Rectangle::GetClosestSideOrCorner(const Vector& position) const
 {
-    if (IsInside(position))
+    std::array<double, 4> distanceFromBorders{
+        std::abs(position.x - this->xMin), // left border
+        std::abs(this->xMax - position.x), // right border
+        std::abs(position.y - this->yMin), // bottom border
+        std::abs(this->yMax - position.y), // top border
+    };
+    uint8_t flags = 0;
+    double minDist = std::numeric_limits<double>::max();
+    for (int i = 0; i < 4; i++)
     {
-        double xMinDist = std::abs(position.x - this->xMin);
-        double xMaxDist = std::abs(this->xMax - position.x);
-        double yMinDist = std::abs(position.y - this->yMin);
-        double yMaxDist = std::abs(this->yMax - position.y);
-        double minX = std::min(xMinDist, xMaxDist);
-        double minY = std::min(yMinDist, yMaxDist);
-        if (minX < minY)
+        if (distanceFromBorders[i] > minDist)
         {
-            if (xMinDist < xMaxDist)
-            {
-                return LEFT;
-            }
-            else
-            {
-                return RIGHT;
-            }
+            continue;
         }
-        else
+        // In case we find a border closer to the position,
+        // we replace it and mark the flag
+        if (distanceFromBorders[i] < minDist)
         {
-            if (yMinDist < yMaxDist)
-            {
-                return BOTTOM;
-            }
-            else
-            {
-                return TOP;
-            }
+            minDist = distanceFromBorders[i];
+            flags = 0;
         }
+        flags |= (0b1000 >> i);
     }
-    else
-    {
-        if (position.x < this->xMin)
+    NS_ASSERT(minDist != std::numeric_limits<double>::max());
+    Rectangle::Side side;
+    switch (flags)
+    {
+    //     LRBT
+    case 0b1111:
+        // Every side is equally distant, so choose any
+        side = TOPSIDE;
+        break;
+    case 0b0011:
+        // Opposing sides are equally distant, so we need to check the other two
+        // We also need to check if we're inside or outside.
+        side = TOPSIDE;
+        if (!IsInside(position))
         {
-            if (position.y < this->yMin)
-            {
-                double yDiff = this->yMin - position.y;
-                double xDiff = this->xMin - position.x;
-                if (yDiff > xDiff)
-                {
-                    return BOTTOM;
-                }
-                else
-                {
-                    return LEFT;
-                }
-            }
-            else if (position.y < this->yMax)
-            {
-                return LEFT;
-            }
-            else
-            {
-                double yDiff = position.y - this->yMax;
-                double xDiff = this->xMin - position.x;
-                if (yDiff > xDiff)
-                {
-                    return TOP;
-                }
-                else
-                {
-                    return LEFT;
-                }
-            }
+            side = (distanceFromBorders[0] > distanceFromBorders[1]) ? RIGHTSIDE : LEFTSIDE;
         }
-        else if (position.x < this->xMax)
+        break;
+    case 0b1100:
+        // Opposing sides are equally distant, so we need to check the other two
+        // We also need to check if we're inside or outside.
+        side = RIGHTSIDE;
+        if (!IsInside(position))
         {
-            if (position.y < this->yMin)
-            {
-                return BOTTOM;
-            }
-            else if (position.y < this->yMax)
-            {
-                NS_FATAL_ERROR(
-                    "This region should have been reached if the IsInside check was true");
-                return TOP; // silence compiler warning
-            }
-            else
-            {
-                return TOP;
-            }
-        }
-        else
-        {
-            if (position.y < this->yMin)
-            {
-                double yDiff = this->yMin - position.y;
-                double xDiff = position.x - this->xMin;
-                if (yDiff > xDiff)
-                {
-                    return BOTTOM;
-                }
-                else
-                {
-                    return RIGHT;
-                }
-            }
-            else if (position.y < this->yMax)
-            {
-                return RIGHT;
-            }
-            else
-            {
-                double yDiff = position.y - this->yMax;
-                double xDiff = position.x - this->xMin;
-                if (yDiff > xDiff)
-                {
-                    return TOP;
-                }
-                else
-                {
-                    return RIGHT;
-                }
-            }
+            side = (distanceFromBorders[2] > distanceFromBorders[3]) ? TOPSIDE : BOTTOMSIDE;
         }
+        break;
+    case 0b0001:
+    case 0b1101:
+        side = TOPSIDE;
+        break;
+    case 0b0010:
+    case 0b1110:
+        side = BOTTOMSIDE;
+        break;
+    case 0b0100:
+    case 0b0111:
+        side = RIGHTSIDE;
+        break;
+    case 0b0101:
+        side = TOPRIGHTCORNER;
+        break;
+    case 0b0110:
+        side = BOTTOMRIGHTCORNER;
+        break;
+    case 0b1000:
+    case 0b1011:
+        side = LEFTSIDE;
+        break;
+    case 0b1001:
+        side = TOPLEFTCORNER;
+        break;
+    case 0b1010:
+        side = BOTTOMLEFTCORNER;
+        break;
+    default:
+        NS_FATAL_ERROR("Impossible case");
+        break;
     }
+    return side;
 }
 
 Vector
@@ -247,4 +221,44 @@
     return is;
 }
 
+/**
+ * \brief Stream insertion operator.
+ *
+ * \param os the stream
+ * \param side the rectangle side
+ * \returns a reference to the stream
+ */
+std::ostream&
+operator<<(std::ostream& os, const Rectangle::Side& side)
+{
+    switch (side)
+    {
+    case Rectangle::RIGHTSIDE:
+        os << "RIGHTSIDE";
+        break;
+    case Rectangle::LEFTSIDE:
+        os << "LEFTSIDE";
+        break;
+    case Rectangle::TOPSIDE:
+        os << "TOPSIDE";
+        break;
+    case Rectangle::BOTTOMSIDE:
+        os << "BOTTOMSIDE";
+        break;
+    case Rectangle::TOPRIGHTCORNER:
+        os << "TOPRIGHTCORNER";
+        break;
+    case Rectangle::TOPLEFTCORNER:
+        os << "TOPLEFTCORNER";
+        break;
+    case Rectangle::BOTTOMRIGHTCORNER:
+        os << "BOTTOMRIGHTCORNER";
+        break;
+    case Rectangle::BOTTOMLEFTCORNER:
+        os << "BOTTOMLEFTCORNER";
+        break;
+    }
+    return os;
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/model/rectangle.h ns-3.40/src/mobility/model/rectangle.h
--- ns-3.39/src/mobility/model/rectangle.h	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/model/rectangle.h	2023-09-27 13:30:37.842839700 -0700
@@ -39,10 +39,14 @@
      */
     enum Side
     {
-        RIGHT,
-        LEFT,
-        TOP,
-        BOTTOM
+        RIGHTSIDE = 0,
+        LEFTSIDE,
+        TOPSIDE,
+        BOTTOMSIDE,
+        TOPRIGHTCORNER,
+        TOPLEFTCORNER,
+        BOTTOMRIGHTCORNER,
+        BOTTOMLEFTCORNER
     };
 
     /**
@@ -68,12 +72,34 @@
     bool IsInside(const Vector& position) const;
     /**
      * \param position the position to test.
+     * \return true if the input position is located on the rectable border, false otherwise.
+     *
+     * This method compares only the x and y coordinates of the input position.
+     * It ignores the z coordinate.
+     */
+    bool IsOnTheBorder(const Vector& position) const;
+    /**
+     * \param position the position to test.
      * \return the side of the rectangle the input position is closest to.
      *
      * This method compares only the x and y coordinates of the input position.
      * It ignores the z coordinate.
+     *
+     * This method assumes assumes a right-handed Cartesian orientation, so that
+     * (xMin, yMin) is the BOTTOMLEFTCORNER,  the TOP and BOTTOM sides are parallel to
+     * the x-axis, the LEFT and RIGHT sides are parallel to the y-axis, and the
+     * (xMax, yMax) point is the TOPRIGHTCORNER.
+     *
+     * Beware: the method has an ambiguity in the "center" of the rectangle. Assume
+     * a rectangle between the points (0, 0) and (4, 2), i.e., wider than taller.
+     * All the points on the line between (1, 1) and (3, 1) are equally closer to the
+     * TOP and BOTTOM than to the other sides of the Rectangle.
+     * These points are classified as TOPSIDE by convention.
+     *
+     * Similarly, for a Rectangle taller than wider, the "center" points will be
+     * classified as RIGHTSIDE, and for a square box, the center will return RIGHTSIDE.
      */
-    Side GetClosestSide(const Vector& position) const;
+    Side GetClosestSideOrCorner(const Vector& position) const;
     /**
      * \param current the current position
      * \param speed the current speed
@@ -94,6 +120,7 @@
 
 std::ostream& operator<<(std::ostream& os, const Rectangle& rectangle);
 std::istream& operator>>(std::istream& is, Rectangle& rectangle);
+std::ostream& operator<<(std::ostream& os, const Rectangle::Side& side);
 
 ATTRIBUTE_HELPER_HEADER(Rectangle);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/test/rectangle-closest-border-test.cc ns-3.40/src/mobility/test/rectangle-closest-border-test.cc
--- ns-3.39/src/mobility/test/rectangle-closest-border-test.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/src/mobility/test/rectangle-closest-border-test.cc	2023-09-27 13:30:37.842839700 -0700
@@ -0,0 +1,207 @@
+/*
+ * 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: Gabriel Ferreira <gabrielcarvfer@gmail.com>
+ */
+
+#include <ns3/rectangle.h>
+#include <ns3/simulator.h>
+#include <ns3/test.h>
+
+using namespace ns3;
+
+/**
+ * \ingroup mobility-test
+ *
+ * \brief Rectangle detection of closest border to a point, inside or outside.
+ */
+class RectangleClosestBorderTestSuite : public TestSuite
+{
+  public:
+    /**
+     * Constructor
+     */
+    RectangleClosestBorderTestSuite();
+};
+
+/**
+ * \ingroup mobility-test
+ *
+ * \brief TestCase to check the rectangle line intersection
+ */
+class RectangleClosestBorderTestCase : public TestCase
+{
+  public:
+    /**
+     * \brief Create RectangleClosestBorderTestCase
+     * \param x Index of the first position to generate
+     * \param y Index of the second position to generate
+     * \param rectangle The 2D rectangle
+     * \param side The expected result of the test
+     */
+    RectangleClosestBorderTestCase(double x, double y, Rectangle rectangle, Rectangle::Side side);
+    /**
+     * \brief Builds the test name string based on provided parameter values
+     * \param x Index of the first position to generate
+     * \param y Index of the second position to generate
+     * \param rectangle The 2D rectangle
+     * \param side The expected result of the test
+     *
+     * \return The name string
+     */
+    std::string BuildNameString(double x, double y, Rectangle rectangle, Rectangle::Side side);
+    /**
+     * Destructor
+     */
+    ~RectangleClosestBorderTestCase() override;
+
+  private:
+    /**
+     * \brief Setup the simulation according to the configuration set by the
+     *        class constructor, run it, and verify the result.
+     */
+    void DoRun() override;
+
+    double m_x{0.0};       //!< X coordinate of the point to be tested
+    double m_y{0.0};       //!< Y coordinate of the point to be tested
+    Rectangle m_rectangle; //!< The rectangle to check the intersection with
+
+    /**
+     * Flag to indicate the intersection.
+     * True, for intersection, false otherwise.
+     */
+    Rectangle::Side m_side{ns3::Rectangle::TOPSIDE};
+};
+
+/**
+ * This TestSuite tests the intersection of a line segment
+ * between two 2D positions with a 2D rectangle. It generates two
+ * positions from a set of predefined positions (see GeneratePosition method),
+ * and then tests the intersection of a line segments between them with a rectangle
+ * of predefined dimensions.
+ */
+
+RectangleClosestBorderTestSuite::RectangleClosestBorderTestSuite()
+    : TestSuite("rectangle-closest-border", UNIT)
+{
+    // Rectangle in the positive x-plane to check the intersection with.
+    Rectangle rectangle = Rectangle(0.0, 10.0, 0.0, 10.0);
+
+    /*            2                3                4
+     *              +----------------------------+ (10,10)
+     *              |  11         16          12 |
+     *              |                            |
+     *              |                            |
+     *      1       |  15          18         17 |              5
+     *              |                            |
+     *              |                            |
+     *              |  10          14         13 |
+     *              +----------------------------+
+     *           9                                  7
+     *           (0,0)
+     *
+     *
+     *
+     *                             8
+     */
+    // Left side (1 and 15)
+    AddTestCase(new RectangleClosestBorderTestCase(-5, 5, rectangle, Rectangle::LEFTSIDE),
+                TestCase::QUICK);
+    AddTestCase(new RectangleClosestBorderTestCase(2, 5, rectangle, Rectangle::LEFTSIDE),
+                TestCase::QUICK);
+    // Right side (5 and 17)
+    AddTestCase(new RectangleClosestBorderTestCase(17, 5, rectangle, Rectangle::RIGHTSIDE),
+                TestCase::QUICK);
+    AddTestCase(new RectangleClosestBorderTestCase(7, 5, rectangle, Rectangle::RIGHTSIDE),
+                TestCase::QUICK);
+    // Bottom side (8 and 14)
+    AddTestCase(new RectangleClosestBorderTestCase(5, -7, rectangle, Rectangle::BOTTOMSIDE),
+                TestCase::QUICK);
+    AddTestCase(new RectangleClosestBorderTestCase(5, 1, rectangle, Rectangle::BOTTOMSIDE),
+                TestCase::QUICK);
+    // Top side (3 and 16)
+    AddTestCase(new RectangleClosestBorderTestCase(5, 15, rectangle, Rectangle::TOPSIDE),
+                TestCase::QUICK);
+    AddTestCase(new RectangleClosestBorderTestCase(5, 7, rectangle, Rectangle::TOPSIDE),
+                TestCase::QUICK);
+    // Left-Bottom corner (9 and 10)
+    AddTestCase(new RectangleClosestBorderTestCase(-1, -1, rectangle, Rectangle::BOTTOMLEFTCORNER),
+                TestCase::QUICK);
+    AddTestCase(new RectangleClosestBorderTestCase(0, 0, rectangle, Rectangle::BOTTOMLEFTCORNER),
+                TestCase::QUICK);
+    // Right-Bottom corner (7 and 13)
+    AddTestCase(new RectangleClosestBorderTestCase(11, -1, rectangle, Rectangle::BOTTOMRIGHTCORNER),
+                TestCase::QUICK);
+    AddTestCase(new RectangleClosestBorderTestCase(9, 1, rectangle, Rectangle::BOTTOMRIGHTCORNER),
+                TestCase::QUICK);
+    // Left-Top corner (2 and 11)
+    AddTestCase(new RectangleClosestBorderTestCase(-1, 11, rectangle, Rectangle::TOPLEFTCORNER),
+                TestCase::QUICK);
+    AddTestCase(new RectangleClosestBorderTestCase(1, 9, rectangle, Rectangle::TOPLEFTCORNER),
+                TestCase::QUICK);
+    // Right-Top corner (4 and 12)
+    AddTestCase(new RectangleClosestBorderTestCase(11, 11, rectangle, Rectangle::TOPRIGHTCORNER),
+                TestCase::QUICK);
+    AddTestCase(new RectangleClosestBorderTestCase(9, 9, rectangle, Rectangle::TOPRIGHTCORNER),
+                TestCase::QUICK);
+    // Central position (18)
+    AddTestCase(new RectangleClosestBorderTestCase(5, 5, rectangle, Rectangle::TOPSIDE),
+                TestCase::QUICK);
+}
+
+/**
+ * \ingroup mobility-test
+ * Static variable for test initialization
+ */
+static RectangleClosestBorderTestSuite rectangleClosestBorderTestSuite;
+
+RectangleClosestBorderTestCase::RectangleClosestBorderTestCase(double x,
+                                                               double y,
+                                                               Rectangle rectangle,
+                                                               Rectangle::Side side)
+    : TestCase(BuildNameString(x, y, rectangle, side)),
+      m_x(x),
+      m_y(y),
+      m_rectangle(rectangle),
+      m_side(side)
+{
+}
+
+RectangleClosestBorderTestCase::~RectangleClosestBorderTestCase()
+{
+}
+
+std::string
+RectangleClosestBorderTestCase::BuildNameString(double x,
+                                                double y,
+                                                Rectangle rectangle,
+                                                Rectangle::Side side)
+{
+    std::ostringstream oss;
+    oss << "Rectangle closest border test : checking"
+        << " (x,y) = (" << x << "," << y << ") closest border to the rectangle [(" << rectangle.xMin
+        << ", " << rectangle.yMin << "), (" << rectangle.xMax << ", " << rectangle.yMax
+        << ")]. The expected side = " << side;
+    return oss.str();
+}
+
+void
+RectangleClosestBorderTestCase::DoRun()
+{
+    Vector position(m_x, m_y, 0.0);
+    Rectangle::Side side = m_rectangle.GetClosestSideOrCorner(position);
+
+    NS_TEST_ASSERT_MSG_EQ(side, m_side, "Unexpected result of rectangle side!");
+    Simulator::Destroy();
+}
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/test/steady-state-random-waypoint-mobility-model-test.cc ns-3.40/src/mobility/test/steady-state-random-waypoint-mobility-model-test.cc
--- ns-3.39/src/mobility/test/steady-state-random-waypoint-mobility-model-test.cc	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/test/steady-state-random-waypoint-mobility-model-test.cc	2023-09-27 13:30:37.842839700 -0700
@@ -106,11 +106,9 @@
     double sum_x = 0;
     double sum_y = 0;
     double sum_v = 0;
-    std::vector<Ptr<MobilityModel>>::iterator i;
-    Ptr<MobilityModel> model;
-    for (i = mobilityStack.begin(); i != mobilityStack.end(); ++i)
+    for (auto i = mobilityStack.begin(); i != mobilityStack.end(); ++i)
     {
-        model = (*i);
+        auto model = (*i);
         velocity =
             std::sqrt(std::pow(model->GetVelocity().x, 2) + std::pow(model->GetVelocity().y, 2));
         sum_x += model->GetPosition().x;
@@ -129,9 +127,9 @@
     sum_y = 0;
     sum_v = 0;
     double tmp;
-    for (i = mobilityStack.begin(); i != mobilityStack.end(); ++i)
+    for (auto i = mobilityStack.begin(); i != mobilityStack.end(); ++i)
     {
-        model = (*i);
+        auto model = (*i);
         velocity =
             std::sqrt(std::pow(model->GetVelocity().x, 2) + std::pow(model->GetVelocity().y, 2));
         tmp = model->GetPosition().x - mean_x;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mobility/test/waypoint-mobility-model-test.cc ns-3.40/src/mobility/test/waypoint-mobility-model-test.cc
--- ns-3.39/src/mobility/test/waypoint-mobility-model-test.cc	2023-07-05 14:23:48.045428000 -0700
+++ ns-3.40/src/mobility/test/waypoint-mobility-model-test.cc	2023-09-27 13:30:37.842839700 -0700
@@ -105,15 +105,14 @@
     }
 
     // Add the same waypoints to each node
-    std::vector<Ptr<MobilityModel>>::iterator i;
-    for (i = mobilityStack.begin(); i != mobilityStack.end(); ++i)
+    for (auto i = mobilityStack.begin(); i != mobilityStack.end(); ++i)
     {
         Ptr<WaypointMobilityModel> mob = (*i)->GetObject<WaypointMobilityModel>();
         mob->TraceConnectWithoutContext(
             "CourseChange",
             MakeCallback(&WaypointMobilityModelNotifyTest::CourseChangeCallback, this));
 
-        for (std::deque<Waypoint>::iterator w = waypoints.begin(); w != waypoints.end(); ++w)
+        for (auto w = waypoints.begin(); w != waypoints.end(); ++w)
         {
             mob->AddWaypoint(*w);
         }
@@ -135,8 +134,7 @@
 void
 WaypointMobilityModelNotifyTest::ForceUpdates()
 {
-    std::vector<Ptr<MobilityModel>>::iterator i;
-    for (i = mobilityStack.begin(); i != mobilityStack.end(); ++i)
+    for (auto i = mobilityStack.begin(); i != mobilityStack.end(); ++i)
     {
         Ptr<WaypointMobilityModel> mob = (*i)->GetObject<WaypointMobilityModel>();
         mob->Update();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mpi/examples/nms-p2p-nix-distributed.cc ns-3.40/src/mpi/examples/nms-p2p-nix-distributed.cc
--- ns-3.39/src/mpi/examples/nms-p2p-nix-distributed.cc	2023-07-05 14:23:48.049428200 -0700
+++ ns-3.40/src/mpi/examples/nms-p2p-nix-distributed.cc	2023-09-27 13:30:37.842839700 -0700
@@ -78,7 +78,7 @@
 
     uint32_t nCN = 2;
     uint32_t nLANClients = 10;
-    bool single = 0;
+    bool single = false;
     int nPackets = 10; // Packets sent by OnOff applications
     bool nix = true;
     Time stop = Seconds(100);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mpi/model/distributed-simulator-impl.cc ns-3.40/src/mpi/model/distributed-simulator-impl.cc
--- ns-3.39/src/mpi/model/distributed-simulator-impl.cc	2023-07-05 14:23:48.049428200 -0700
+++ ns-3.40/src/mpi/model/distributed-simulator-impl.cc	2023-09-27 13:30:37.842839700 -0700
@@ -172,7 +172,7 @@
     else
     {
         NodeContainer c = NodeContainer::GetGlobal();
-        for (NodeContainer::Iterator iter = c.Begin(); iter != c.End(); ++iter)
+        for (auto iter = c.Begin(); iter != c.End(); ++iter)
         {
             if ((*iter)->GetSystemId() != MpiInterface::GetSystemId())
             {
@@ -553,7 +553,7 @@
     if (id.GetUid() == EventId::UID::DESTROY)
     {
         // destroy events.
-        for (DestroyEvents::iterator i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
+        for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
         {
             if (*i == id)
             {
@@ -599,8 +599,7 @@
             return true;
         }
         // destroy events.
-        for (DestroyEvents::const_iterator i = m_destroyEvents.begin(); i != m_destroyEvents.end();
-             i++)
+        for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
         {
             if (*i == id)
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mpi/model/granted-time-window-mpi-interface.cc ns-3.40/src/mpi/model/granted-time-window-mpi-interface.cc
--- ns-3.39/src/mpi/model/granted-time-window-mpi-interface.cc	2023-07-05 14:23:48.049428200 -0700
+++ ns-3.40/src/mpi/model/granted-time-window-mpi-interface.cc	2023-09-27 13:30:37.842839700 -0700
@@ -90,7 +90,6 @@
 char** GrantedTimeWindowMpiInterface::g_pRxBuffers;
 MPI_Comm GrantedTimeWindowMpiInterface::g_communicator = MPI_COMM_WORLD;
 bool GrantedTimeWindowMpiInterface::g_freeCommunicator = false;
-;
 
 TypeId
 GrantedTimeWindowMpiInterface::GetTypeId()
@@ -219,16 +218,16 @@
 
     SentBuffer sendBuf;
     g_pendingTx.push_back(sendBuf);
-    std::list<SentBuffer>::reverse_iterator i = g_pendingTx.rbegin(); // Points to the last element
+    auto i = g_pendingTx.rbegin(); // Points to the last element
 
     uint32_t serializedSize = p->GetSerializedSize();
-    uint8_t* buffer = new uint8_t[serializedSize + 16];
+    auto buffer = new uint8_t[serializedSize + 16];
     i->SetBuffer(buffer);
     // Add the time, dest node and dest device
     uint64_t t = rxTime.GetInteger();
-    uint64_t* pTime = reinterpret_cast<uint64_t*>(buffer);
+    auto pTime = reinterpret_cast<uint64_t*>(buffer);
     *pTime++ = t;
-    uint32_t* pData = reinterpret_cast<uint32_t*>(pTime);
+    auto pData = reinterpret_cast<uint32_t*>(pTime);
     *pData++ = node;
     *pData++ = dev;
     // Serialize the packet
@@ -270,9 +269,9 @@
         g_rxCount++; // Count this receive
 
         // Get the meta data first
-        uint64_t* pTime = reinterpret_cast<uint64_t*>(g_pRxBuffers[index]);
+        auto pTime = reinterpret_cast<uint64_t*>(g_pRxBuffers[index]);
         uint64_t time = *pTime++;
-        uint32_t* pData = reinterpret_cast<uint32_t*>(pTime);
+        auto pData = reinterpret_cast<uint32_t*>(pTime);
         uint32_t node = *pData++;
         uint32_t dev = *pData++;
 
@@ -321,14 +320,14 @@
 {
     NS_LOG_FUNCTION_NOARGS();
 
-    std::list<SentBuffer>::iterator i = g_pendingTx.begin();
+    auto i = g_pendingTx.begin();
     while (i != g_pendingTx.end())
     {
         MPI_Status status;
         int flag = 0;
         MPI_Test(i->GetRequest(), &flag, &status);
-        std::list<SentBuffer>::iterator current = i; // Save current for erasing
-        i++;                                         // Advance to next
+        auto current = i; // Save current for erasing
+        i++;              // Advance to next
         if (flag)
         { // This message is complete
             g_pendingTx.erase(current);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mpi/model/null-message-mpi-interface.cc ns-3.40/src/mpi/model/null-message-mpi-interface.cc
--- ns-3.39/src/mpi/model/null-message-mpi-interface.cc	2023-07-05 14:23:48.049428200 -0700
+++ ns-3.40/src/mpi/model/null-message-mpi-interface.cc	2023-09-27 13:30:37.842839700 -0700
@@ -26,12 +26,12 @@
 
 #include "null-message-mpi-interface.h"
 
+#include "mpi-receiver.h"
 #include "null-message-simulator-impl.h"
 #include "remote-channel-bundle-manager.h"
 #include "remote-channel-bundle.h"
 
 #include "ns3/log.h"
-#include "ns3/mpi-receiver.h"
 #include "ns3/net-device.h"
 #include "ns3/node-list.h"
 #include "ns3/node.h"
@@ -270,23 +270,22 @@
 
     NullMessageSentBuffer sendBuf;
     g_pendingTx.push_back(sendBuf);
-    std::list<NullMessageSentBuffer>::reverse_iterator iter =
-        g_pendingTx.rbegin(); // Points to the last element
+    auto iter = g_pendingTx.rbegin(); // Points to the last element
 
     uint32_t serializedSize = p->GetSerializedSize();
     uint32_t bufferSize = serializedSize + (2 * sizeof(uint64_t)) + (2 * sizeof(uint32_t));
-    uint8_t* buffer = new uint8_t[bufferSize];
+    auto buffer = new uint8_t[bufferSize];
     iter->SetBuffer(buffer);
     // Add the time, dest node and dest device
     uint64_t t = rxTime.GetInteger();
-    uint64_t* pTime = reinterpret_cast<uint64_t*>(buffer);
+    auto pTime = reinterpret_cast<uint64_t*>(buffer);
     *pTime++ = t;
 
     Time guarantee_update =
         NullMessageSimulatorImpl::GetInstance()->CalculateGuaranteeTime(nodeSysId);
     *pTime++ = guarantee_update.GetTimeStep();
 
-    uint32_t* pData = reinterpret_cast<uint32_t*>(pTime);
+    auto pData = reinterpret_cast<uint32_t*>(pTime);
     *pData++ = node;
     *pData++ = dev;
     // Serialize the packet
@@ -313,17 +312,16 @@
 
     NullMessageSentBuffer sendBuf;
     g_pendingTx.push_back(sendBuf);
-    std::list<NullMessageSentBuffer>::reverse_iterator iter =
-        g_pendingTx.rbegin(); // Points to the last element
+    auto iter = g_pendingTx.rbegin(); // Points to the last element
 
     uint32_t bufferSize = 2 * sizeof(uint64_t) + 2 * sizeof(uint32_t);
-    uint8_t* buffer = new uint8_t[bufferSize];
+    auto buffer = new uint8_t[bufferSize];
     iter->SetBuffer(buffer);
     // Add the time, dest node and dest device
-    uint64_t* pTime = reinterpret_cast<uint64_t*>(buffer);
+    auto pTime = reinterpret_cast<uint64_t*>(buffer);
     *pTime++ = 0;
     *pTime++ = guarantee_update.GetInteger();
-    uint32_t* pData = reinterpret_cast<uint32_t*>(pTime);
+    auto pData = reinterpret_cast<uint32_t*>(pTime);
     *pData++ = 0;
     *pData++ = 0;
 
@@ -395,11 +393,11 @@
             MPI_Get_count(&status, MPI_CHAR, &count);
 
             // Get the meta data first
-            uint64_t* pTime = reinterpret_cast<uint64_t*>(g_pRxBuffers[index]);
+            auto pTime = reinterpret_cast<uint64_t*>(g_pRxBuffers[index]);
             uint64_t time = *pTime++;
             uint64_t guaranteeUpdate = *pTime++;
 
-            uint32_t* pData = reinterpret_cast<uint32_t*>(pTime);
+            auto pData = reinterpret_cast<uint32_t*>(pTime);
             uint32_t node = *pData++;
             uint32_t dev = *pData++;
 
@@ -465,14 +463,14 @@
 
     NS_ASSERT(g_enabled);
 
-    std::list<NullMessageSentBuffer>::iterator iter = g_pendingTx.begin();
+    auto iter = g_pendingTx.begin();
     while (iter != g_pendingTx.end())
     {
         MPI_Status status;
         int flag = 0;
         MPI_Test(iter->GetRequest(), &flag, &status);
-        std::list<NullMessageSentBuffer>::iterator current = iter; // Save current for erasing
-        ++iter;                                                    // Advance to next
+        auto current = iter; // Save current for erasing
+        ++iter;              // Advance to next
         if (flag)
         { // This message is complete
             g_pendingTx.erase(current);
@@ -487,9 +485,7 @@
 
     if (g_enabled)
     {
-        for (std::list<NullMessageSentBuffer>::iterator iter = g_pendingTx.begin();
-             iter != g_pendingTx.end();
-             ++iter)
+        for (auto iter = g_pendingTx.begin(); iter != g_pendingTx.end(); ++iter)
         {
             MPI_Cancel(iter->GetRequest());
             MPI_Request_free(iter->GetRequest());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mpi/model/null-message-simulator-impl.cc ns-3.40/src/mpi/model/null-message-simulator-impl.cc
--- ns-3.39/src/mpi/model/null-message-simulator-impl.cc	2023-07-05 14:23:48.049428200 -0700
+++ ns-3.40/src/mpi/model/null-message-simulator-impl.cc	2023-09-27 13:30:37.842839700 -0700
@@ -140,7 +140,7 @@
     if (MpiInterface::GetSize() > 1)
     {
         NodeContainer c = NodeContainer::GetGlobal();
-        for (NodeContainer::Iterator iter = c.Begin(); iter != c.End(); ++iter)
+        for (auto iter = c.Begin(); iter != c.End(); ++iter)
         {
             if ((*iter)->GetSystemId() != MpiInterface::GetSystemId())
             {
@@ -476,7 +476,7 @@
     if (id.GetUid() == EventId::UID::DESTROY)
     {
         // destroy events.
-        for (DestroyEvents::iterator i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
+        for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
         {
             if (*i == id)
             {
@@ -522,8 +522,7 @@
             return true;
         }
         // destroy events.
-        for (DestroyEvents::const_iterator i = m_destroyEvents.begin(); i != m_destroyEvents.end();
-             i++)
+        for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
         {
             if (*i == id)
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/mpi/model/remote-channel-bundle-manager.cc ns-3.40/src/mpi/model/remote-channel-bundle-manager.cc
--- ns-3.39/src/mpi/model/remote-channel-bundle-manager.cc	2023-07-05 14:23:48.049428200 -0700
+++ ns-3.40/src/mpi/model/remote-channel-bundle-manager.cc	2023-09-27 13:30:37.842839700 -0700
@@ -41,8 +41,7 @@
 Ptr<RemoteChannelBundle>
 RemoteChannelBundleManager::Find(uint32_t systemId)
 {
-    ns3::RemoteChannelBundleManager::RemoteChannelMap::iterator kv =
-        g_remoteChannelBundles.find(systemId);
+    auto kv = g_remoteChannelBundles.find(systemId);
 
     if (kv == g_remoteChannelBundles.end())
     {
@@ -78,9 +77,7 @@
 {
     NS_ASSERT(!g_initialized);
 
-    for (RemoteChannelMap::const_iterator iter = g_remoteChannelBundles.begin();
-         iter != g_remoteChannelBundles.end();
-         ++iter)
+    for (auto iter = g_remoteChannelBundles.begin(); iter != g_remoteChannelBundles.end(); ++iter)
     {
         Ptr<RemoteChannelBundle> bundle = iter->second;
         bundle->Send(bundle->GetDelay());
@@ -98,9 +95,7 @@
 
     Time safeTime = Simulator::GetMaximumSimulationTime();
 
-    for (RemoteChannelMap::const_iterator kv = g_remoteChannelBundles.begin();
-         kv != g_remoteChannelBundles.end();
-         ++kv)
+    for (auto kv = g_remoteChannelBundles.begin(); kv != g_remoteChannelBundles.end(); ++kv)
     {
         safeTime = Min(safeTime, kv->second->GetGuaranteeTime());
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/netanim/doc/animation.rst ns-3.40/src/netanim/doc/animation.rst
--- ns-3.39/src/netanim/doc/animation.rst	2023-07-05 14:23:48.049428200 -0700
+++ ns-3.40/src/netanim/doc/animation.rst	2023-09-27 13:30:37.842839700 -0700
@@ -14,7 +14,7 @@
 NetAnim
 *******
 
-NetAnim is a standalone, Qt4-based software executable that uses a trace file generated during
+NetAnim is a standalone, Qt5-based software executable that uses a trace file generated during
 an |ns3| simulation to display the topology and animate the packet flow between nodes.
 
 .. figure:: figures/NetAnim_3_105.*
@@ -77,33 +77,23 @@
 ===================
 If NetAnim is not already available in the |ns3| package you downloaded, you can do the following:
 
-Please ensure that you have installed mercurial.
-The latest version of NetAnim can be downloaded using mercurial with the following command:
+The latest version of NetAnim can be downloaded using git with the following command:
 
 .. sourcecode:: bash
 
-  $ hg clone http://code.nsnam.org/netanim
+  $ git clone https://gitlab.com/nsnam/netanim.git
 
 Building NetAnim
 ================
 Prerequisites
 ~~~~~~~~~~~~~
-Qt5 (5.4 and over) is required to build NetAnim. This can be obtained using the following ways:
+Qt5 (5.4 and over) is required to build NetAnim. The ns-3 Installation Guide
+lists some packages to install for some
+`Linux <https://www.nsnam.org/docs/installation/html/linux.html#optional>`_ systems,
+for `macOS <https://www.nsnam.org/docs/installation/html/macos.html#optional>`, and
+for `Windows <https://www.nsnam.org/docs/installation/html/windows.html>`_.
 
-For Ubuntu Linux distributions:
-
-.. sourcecode:: bash
-
-  $ apt-get install qt5-default
-
-For Red Hat/Fedora based distribution:
-
-.. sourcecode:: bash
-
-  $ yum install qt5
-  $ yum install qt5-devel
-
-For Mac/OSX, see https://www.qt.io/download
+The `Qt site <https://www.qt.io/download>`_ also provides download options.
 
 Build steps
 ~~~~~~~~~~~
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/netanim/examples/uan-animation.cc ns-3.40/src/netanim/examples/uan-animation.cc
--- ns-3.39/src/netanim/examples/uan-animation.cc	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/netanim/examples/uan-animation.cc	2023-09-27 13:30:37.850839600 -0700
@@ -98,7 +98,7 @@
 NetAnimExperiment::UpdatePositions(NodeContainer& nodes) const
 {
     NS_LOG_DEBUG(Simulator::Now().As(Time::S) << " Updating positions");
-    NodeContainer::Iterator it = nodes.Begin();
+    auto it = nodes.Begin();
     Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable>();
     uv->SetAttribute("Min", DoubleValue(0.0));
     uv->SetAttribute("Max", DoubleValue(m_boundary));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/netanim/model/animation-interface.cc ns-3.40/src/netanim/model/animation-interface.cc
--- ns-3.39/src/netanim/model/animation-interface.cc	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/netanim/model/animation-interface.cc	2023-09-27 13:30:37.850839600 -0700
@@ -38,7 +38,6 @@
 #endif
 #include "animation-interface.h"
 
-#include "ns3/animation-interface.h"
 #include "ns3/channel.h"
 #include "ns3/config.h"
 #include "ns3/constant-position-mobility-model.h"
@@ -136,7 +135,7 @@
     m_wifiPhyCountersPollInterval = pollInterval;
     m_wifiPhyTxDropCounterId = AddNodeCounter("WifiPhy TxDrop", AnimationInterface::DOUBLE_COUNTER);
     m_wifiPhyRxDropCounterId = AddNodeCounter("WifiPhy RxDrop", AnimationInterface::DOUBLE_COUNTER);
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         m_nodeWifiPhyTxDrop[n->GetId()] = 0;
@@ -156,7 +155,7 @@
     m_wifiMacTxDropCounterId = AddNodeCounter("WifiMac TxDrop", AnimationInterface::DOUBLE_COUNTER);
     m_wifiMacRxCounterId = AddNodeCounter("WifiMac Rx", AnimationInterface::DOUBLE_COUNTER);
     m_wifiMacRxDropCounterId = AddNodeCounter("WifiMac RxDrop", AnimationInterface::DOUBLE_COUNTER);
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         m_nodeWifiMacTx[n->GetId()] = 0;
@@ -179,7 +178,7 @@
     m_queueEnqueueCounterId = AddNodeCounter("Enqueue", AnimationInterface::DOUBLE_COUNTER);
     m_queueDequeueCounterId = AddNodeCounter("Dequeue", AnimationInterface::DOUBLE_COUNTER);
     m_queueDropCounterId = AddNodeCounter("Queue Drop", AnimationInterface::DOUBLE_COUNTER);
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         m_nodeQueueEnqueue[n->GetId()] = 0;
@@ -200,7 +199,7 @@
     m_ipv4L3ProtocolTxCounterId = AddNodeCounter("Ipv4 Tx", AnimationInterface::DOUBLE_COUNTER);
     m_ipv4L3ProtocolRxCounterId = AddNodeCounter("Ipv4 Rx", AnimationInterface::DOUBLE_COUNTER);
     m_ipv4L3ProtocolDropCounterId = AddNodeCounter("Ipv4 Drop", AnimationInterface::DOUBLE_COUNTER);
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         m_nodeIpv4Tx[n->GetId()] = 0;
@@ -441,7 +440,7 @@
 double
 AnimationInterface::GetNodeEnergyFraction(Ptr<const Node> node) const
 {
-    const EnergyFractionMap::const_iterator fractionIter = m_nodeEnergyFraction.find(node->GetId());
+    const auto fractionIter = m_nodeEnergyFraction.find(node->GetId());
     NS_ASSERT(fractionIter != m_nodeEnergyFraction.end());
     return fractionIter->second;
 }
@@ -501,7 +500,7 @@
 AnimationInterface::GetMovedNodes()
 {
     std::vector<Ptr<Node>> movedNodes;
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         NS_ASSERT(n);
@@ -574,9 +573,8 @@
 {
     NS_LOG_INFO("Writing Route Path From :" << nodeId << " To: " << destination);
     WriteXmlRp(nodeId, destination, rpElements);
-    /*for (Ipv4RoutePathElements::const_iterator i = rpElements.begin ();
-         i != rpElements.end ();
-         ++i)
+    /*
+    for (auto i = rpElements.begin (); i != rpElements.end (); ++i)
       {
         Ipv4RoutePathElement rpElement = *i;
         NS_LOG_INFO ("Node:" << rpElement.nodeId << "-->" << rpElement.nextHop.c_str ());
@@ -1125,7 +1123,7 @@
     UpdatePosition(ndev);
 
     std::list<Ptr<Packet>> pbList = pb->GetPackets();
-    for (std::list<Ptr<Packet>>::iterator i = pbList.begin(); i != pbList.end(); ++i)
+    for (auto i = pbList.begin(); i != pbList.end(); ++i)
     {
         Ptr<Packet> p = *i;
         ++gAnimUid;
@@ -1153,7 +1151,7 @@
     UpdatePosition(ndev);
 
     std::list<Ptr<Packet>> pbList = pb->GetPackets();
-    for (std::list<Ptr<Packet>>::iterator i = pbList.begin(); i != pbList.end(); ++i)
+    for (auto i = pbList.begin(); i != pbList.end(); ++i)
     {
         Ptr<Packet> p = *i;
         uint64_t animUid = GetAnimUidFromPacket(p);
@@ -1326,8 +1324,7 @@
         return;
     }
     std::vector<uint64_t> purgeList;
-    for (AnimUidPacketInfoMap::iterator i = pendingPackets->begin(); i != pendingPackets->end();
-         ++i)
+    for (auto i = pendingPackets->begin(); i != pendingPackets->end(); ++i)
     {
         AnimPacketInfo pktInfo = i->second;
         double delta = (Simulator::Now().GetSeconds() - pktInfo.m_fbTx);
@@ -1336,7 +1333,7 @@
             purgeList.push_back(i->first);
         }
     }
-    for (std::vector<uint64_t>::iterator i = purgeList.begin(); i != purgeList.end(); ++i)
+    for (auto i = purgeList.begin(); i != purgeList.end(); ++i)
     {
         pendingPackets->erase(*i);
     }
@@ -1503,9 +1500,7 @@
 AnimationInterface::AddToIpv4AddressNodeIdTable(std::vector<std::string> ipv4Addresses,
                                                 uint32_t nodeId)
 {
-    for (std::vector<std::string>::const_iterator i = ipv4Addresses.begin();
-         i != ipv4Addresses.end();
-         ++i)
+    for (auto i = ipv4Addresses.begin(); i != ipv4Addresses.end(); ++i)
     {
         AddToIpv4AddressNodeIdTable(*i, nodeId);
     }
@@ -1522,9 +1517,7 @@
 AnimationInterface::AddToIpv6AddressNodeIdTable(std::vector<std::string> ipv6Addresses,
                                                 uint32_t nodeId)
 {
-    for (std::vector<std::string>::const_iterator i = ipv6Addresses.begin();
-         i != ipv6Addresses.end();
-         ++i)
+    for (auto i = ipv6Addresses.begin(); i != ipv6Addresses.end(); ++i)
     {
         AddToIpv6AddressNodeIdTable(*i, nodeId);
     }
@@ -1592,7 +1585,7 @@
 void
 AnimationInterface::ConnectLte()
 {
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         NS_ASSERT(n);
@@ -1893,12 +1886,11 @@
 void
 AnimationInterface::WriteIpv4Addresses()
 {
-    for (NodeIdIpv4Map::const_iterator i = m_nodeIdIpv4Map.begin(); i != m_nodeIdIpv4Map.end(); ++i)
+    for (auto i = m_nodeIdIpv4Map.begin(); i != m_nodeIdIpv4Map.end(); ++i)
     {
         std::vector<std::string> ipv4Addresses;
-        std::pair<NodeIdIpv4Map::const_iterator, NodeIdIpv4Map::const_iterator> iterPair =
-            m_nodeIdIpv4Map.equal_range(i->first);
-        for (NodeIdIpv4Map::const_iterator it = iterPair.first; it != iterPair.second; ++it)
+        auto iterPair = m_nodeIdIpv4Map.equal_range(i->first);
+        for (auto it = iterPair.first; it != iterPair.second; ++it)
         {
             ipv4Addresses.push_back(it->second);
         }
@@ -1909,13 +1901,12 @@
 void
 AnimationInterface::WriteIpv6Addresses()
 {
-    for (NodeIdIpv6Map::const_iterator i = m_nodeIdIpv6Map.begin(); i != m_nodeIdIpv6Map.end();
+    for (auto i = m_nodeIdIpv6Map.begin(); i != m_nodeIdIpv6Map.end();
          i = m_nodeIdIpv6Map.upper_bound(i->first))
     {
         std::vector<std::string> ipv6Addresses;
-        std::pair<NodeIdIpv6Map::const_iterator, NodeIdIpv6Map::const_iterator> iterPair =
-            m_nodeIdIpv6Map.equal_range(i->first);
-        for (NodeIdIpv6Map::const_iterator it = iterPair.first; it != iterPair.second; ++it)
+        auto iterPair = m_nodeIdIpv6Map.equal_range(i->first);
+        for (auto it = iterPair.first; it != iterPair.second; ++it)
         {
             ipv6Addresses.push_back(it->second);
         }
@@ -1926,7 +1917,7 @@
 void
 AnimationInterface::WriteLinkProperties()
 {
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         UpdatePosition(n);
@@ -2027,7 +2018,7 @@
 void
 AnimationInterface::WriteNodes()
 {
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         NS_LOG_INFO("Update Position for Node: " << n->GetId());
@@ -2039,7 +2030,7 @@
 void
 AnimationInterface::WriteNodeColors()
 {
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         Rgb rgb = {255, 0, 0};
@@ -2054,7 +2045,7 @@
 void
 AnimationInterface::WriteNodeSizes()
 {
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         NS_LOG_INFO("Update Size for Node: " << n->GetId());
@@ -2069,7 +2060,7 @@
 {
     m_remainingEnergyCounterId =
         AddNodeCounter("RemainingEnergy", AnimationInterface::DOUBLE_COUNTER);
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
         if (NodeList::GetNode(n->GetId())->GetObject<EnergySource>())
@@ -2145,7 +2136,7 @@
         NS_LOG_INFO("TrackQueueCounters Completed");
         return;
     }
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         uint32_t nodeId = Ptr<Node>(*i)->GetId();
         UpdateNodeCounter(m_queueEnqueueCounterId, nodeId, m_nodeQueueEnqueue[nodeId]);
@@ -2163,7 +2154,7 @@
         NS_LOG_INFO("TrackWifiMacCounters Completed");
         return;
     }
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         uint32_t nodeId = Ptr<Node>(*i)->GetId();
         UpdateNodeCounter(m_wifiMacTxCounterId, nodeId, m_nodeWifiMacTx[nodeId]);
@@ -2184,7 +2175,7 @@
         NS_LOG_INFO("TrackWifiPhyCounters Completed");
         return;
     }
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         uint32_t nodeId = Ptr<Node>(*i)->GetId();
         UpdateNodeCounter(m_wifiPhyTxDropCounterId, nodeId, m_nodeWifiPhyTxDrop[nodeId]);
@@ -2203,7 +2194,7 @@
         NS_LOG_INFO("TrackIpv4L3ProtocolCounters Completed");
         return;
     }
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         uint32_t nodeId = Ptr<Node>(*i)->GetId();
         UpdateNodeCounter(m_ipv4L3ProtocolTxCounterId, nodeId, m_nodeIpv4Tx[nodeId]);
@@ -2224,9 +2215,7 @@
     {
         return;
     }
-    for (std::vector<Ipv4RouteTrackElement>::const_iterator i = m_ipv4RouteTrackElements.begin();
-         i != m_ipv4RouteTrackElements.end();
-         ++i)
+    for (auto i = m_ipv4RouteTrackElements.begin(); i != m_ipv4RouteTrackElements.end(); ++i)
     {
         Ipv4RouteTrackElement trackElement = *i;
         Ptr<Node> fromNode = NodeList::GetNode(trackElement.fromNodeId);
@@ -2301,7 +2290,7 @@
     }
     if (m_routingNc.GetN())
     {
-        for (NodeContainer::Iterator i = m_routingNc.Begin(); i != m_routingNc.End(); ++i)
+        for (auto i = m_routingNc.Begin(); i != m_routingNc.End(); ++i)
         {
             Ptr<Node> n = *i;
             WriteXmlRouting(n->GetId(), GetIpv4RoutingTable(n));
@@ -2309,7 +2298,7 @@
     }
     else
     {
-        for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+        for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
         {
             Ptr<Node> n = *i;
             WriteXmlRouting(n->GetId(), GetIpv4RoutingTable(n));
@@ -2496,9 +2485,7 @@
 {
     AnimXmlElement element("ip");
     element.AddAttribute("n", nodeId);
-    for (std::vector<std::string>::const_iterator i = ipv4Addresses.begin();
-         i != ipv4Addresses.end();
-         ++i)
+    for (auto i = ipv4Addresses.begin(); i != ipv4Addresses.end(); ++i)
     {
         AnimXmlElement valueElement("address");
         valueElement.SetText(*i);
@@ -2512,9 +2499,7 @@
 {
     AnimXmlElement element("ipv6");
     element.AddAttribute("n", nodeId);
-    for (std::vector<std::string>::const_iterator i = ipv6Addresses.begin();
-         i != ipv6Addresses.end();
-         ++i)
+    for (auto i = ipv6Addresses.begin(); i != ipv6Addresses.end(); ++i)
     {
         AnimXmlElement valueElement("address");
         valueElement.SetText(*i);
@@ -2544,7 +2529,7 @@
     element.AddAttribute("id", nodeId);
     element.AddAttribute("d", destination.c_str());
     element.AddAttribute("c", rpElements.size());
-    for (Ipv4RoutePathElements::const_iterator i = rpElements.begin(); i != rpElements.end(); ++i)
+    for (auto i = rpElements.begin(); i != rpElements.end(); ++i)
     {
         Ipv4RoutePathElement rpElement = *i;
         AnimXmlElement rpeElement("rpe");
@@ -2754,7 +2739,7 @@
     {
         attributeString += "=\"";
         std::string valueStr = oss.str();
-        for (std::string::iterator it = valueStr.begin(); it != valueStr.end(); ++it)
+        for (auto it = valueStr.begin(); it != valueStr.end(); ++it)
         {
             switch (*it)
             {
@@ -2804,8 +2789,7 @@
 {
     std::string elementString = "<" + m_tagName + " ";
 
-    for (std::vector<std::string>::const_iterator i = m_attributes.begin(); i != m_attributes.end();
-         ++i)
+    for (auto i = m_attributes.begin(); i != m_attributes.end(); ++i)
     {
         elementString += *i;
     }
@@ -2826,9 +2810,7 @@
         if (!m_children.empty())
         {
             elementString += "\n";
-            for (std::vector<std::string>::const_iterator i = m_children.begin();
-                 i != m_children.end();
-                 ++i)
+            for (auto i = m_children.begin(); i != m_children.end(); ++i)
             {
                 elementString += *i + "\n";
             }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/netanim/test/netanim-test.cc ns-3.40/src/netanim/test/netanim-test.cc
--- ns-3.39/src/netanim/test/netanim-test.cc	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/netanim/test/netanim-test.cc	2023-09-27 13:30:37.850839600 -0700
@@ -19,7 +19,6 @@
 
 #include "unistd.h"
 
-#include "ns3/applications-module.h"
 #include "ns3/basic-energy-source.h"
 #include "ns3/core-module.h"
 #include "ns3/internet-module.h"
@@ -28,6 +27,7 @@
 #include "ns3/point-to-point-layout-module.h"
 #include "ns3/point-to-point-module.h"
 #include "ns3/simple-device-energy-model.h"
+#include "ns3/udp-echo-helper.h"
 
 #include <iostream>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/helper/application-container.cc ns-3.40/src/network/helper/application-container.cc
--- ns-3.39/src/network/helper/application-container.cc	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/helper/application-container.cc	2023-09-27 13:30:37.850839600 -0700
@@ -69,7 +69,7 @@
 void
 ApplicationContainer::Add(ApplicationContainer other)
 {
-    for (Iterator i = other.Begin(); i != other.End(); i++)
+    for (auto i = other.Begin(); i != other.End(); i++)
     {
         m_applications.push_back(*i);
     }
@@ -91,7 +91,7 @@
 void
 ApplicationContainer::Start(Time start) const
 {
-    for (Iterator i = Begin(); i != End(); ++i)
+    for (auto i = Begin(); i != End(); ++i)
     {
         Ptr<Application> app = *i;
         app->SetStartTime(start);
@@ -101,7 +101,7 @@
 void
 ApplicationContainer::StartWithJitter(Time start, Ptr<RandomVariableStream> rv) const
 {
-    for (Iterator i = Begin(); i != End(); ++i)
+    for (auto i = Begin(); i != End(); ++i)
     {
         Ptr<Application> app = *i;
         double value = rv->GetValue();
@@ -113,7 +113,7 @@
 void
 ApplicationContainer::Stop(Time stop) const
 {
-    for (Iterator i = Begin(); i != End(); ++i)
+    for (auto i = Begin(); i != End(); ++i)
     {
         Ptr<Application> app = *i;
         app->SetStopTime(stop);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/helper/net-device-container.cc ns-3.40/src/network/helper/net-device-container.cc
--- ns-3.39/src/network/helper/net-device-container.cc	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/helper/net-device-container.cc	2023-09-27 13:30:37.850839600 -0700
@@ -72,7 +72,7 @@
 void
 NetDeviceContainer::Add(NetDeviceContainer other)
 {
-    for (Iterator i = other.Begin(); i != other.End(); i++)
+    for (auto i = other.Begin(); i != other.End(); i++)
     {
         m_devices.push_back(*i);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/helper/node-container.cc ns-3.40/src/network/helper/node-container.cc
--- ns-3.39/src/network/helper/node-container.cc	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/helper/node-container.cc	2023-09-27 13:30:37.850839600 -0700
@@ -28,7 +28,7 @@
 NodeContainer::GetGlobal()
 {
     NodeContainer c;
-    for (NodeList::Iterator i = NodeList::Begin(); i != NodeList::End(); ++i)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         c.Add(*i);
     }
@@ -101,7 +101,7 @@
 void
 NodeContainer::Add(const NodeContainer& nc)
 {
-    for (Iterator i = nc.Begin(); i != nc.End(); i++)
+    for (auto i = nc.Begin(); i != nc.End(); i++)
     {
         m_nodes.push_back(*i);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/helper/packet-socket-helper.cc ns-3.40/src/network/helper/packet-socket-helper.cc
--- ns-3.39/src/network/helper/packet-socket-helper.cc	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/helper/packet-socket-helper.cc	2023-09-27 13:30:37.850839600 -0700
@@ -28,7 +28,7 @@
 void
 PacketSocketHelper::Install(NodeContainer c) const
 {
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Install(*i);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/helper/packet-socket-helper.h ns-3.40/src/network/helper/packet-socket-helper.h
--- ns-3.39/src/network/helper/packet-socket-helper.h	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/helper/packet-socket-helper.h	2023-09-27 13:30:37.850839600 -0700
@@ -20,7 +20,7 @@
 #ifndef PACKET_SOCKET_HELPER_H
 #define PACKET_SOCKET_HELPER_H
 
-#include "ns3/node-container.h"
+#include "node-container.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/helper/simple-net-device-helper.cc ns-3.40/src/network/helper/simple-net-device-helper.cc
--- ns-3.39/src/network/helper/simple-net-device-helper.cc	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/helper/simple-net-device-helper.cc	2023-09-27 13:30:37.850839600 -0700
@@ -19,6 +19,8 @@
 
 #include "simple-net-device-helper.h"
 
+#include "trace-helper.h"
+
 #include "ns3/abort.h"
 #include "ns3/boolean.h"
 #include "ns3/config.h"
@@ -30,7 +32,6 @@
 #include "ns3/simple-channel.h"
 #include "ns3/simple-net-device.h"
 #include "ns3/simulator.h"
-#include "ns3/trace-helper.h"
 
 #include <string>
 
@@ -98,7 +99,7 @@
 {
     NetDeviceContainer devs;
 
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); i++)
+    for (auto i = c.Begin(); i != c.End(); i++)
     {
         devs.Add(InstallPriv(*i, channel));
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/helper/simple-net-device-helper.h ns-3.40/src/network/helper/simple-net-device-helper.h
--- ns-3.39/src/network/helper/simple-net-device-helper.h	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/helper/simple-net-device-helper.h	2023-09-27 13:30:37.850839600 -0700
@@ -19,9 +19,10 @@
 #ifndef SIMPLE_NETDEVICE_HELPER_H
 #define SIMPLE_NETDEVICE_HELPER_H
 
+#include "net-device-container.h"
+#include "node-container.h"
+
 #include "ns3/attribute.h"
-#include "ns3/net-device-container.h"
-#include "ns3/node-container.h"
 #include "ns3/object-factory.h"
 #include "ns3/queue.h"
 #include "ns3/simple-channel.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/helper/trace-helper.cc ns-3.40/src/network/helper/trace-helper.cc
--- ns-3.39/src/network/helper/trace-helper.cc	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/helper/trace-helper.cc	2023-09-27 13:30:37.850839600 -0700
@@ -438,7 +438,7 @@
 void
 PcapHelperForDevice::EnablePcap(std::string prefix, NetDeviceContainer d, bool promiscuous)
 {
-    for (NetDeviceContainer::Iterator i = d.Begin(); i != d.End(); ++i)
+    for (auto i = d.Begin(); i != d.End(); ++i)
     {
         Ptr<NetDevice> dev = *i;
         EnablePcap(prefix, dev, promiscuous);
@@ -449,7 +449,7 @@
 PcapHelperForDevice::EnablePcap(std::string prefix, NodeContainer n, bool promiscuous)
 {
     NetDeviceContainer devs;
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         for (uint32_t j = 0; j < node->GetNDevices(); ++j)
@@ -474,7 +474,7 @@
 {
     NodeContainer n = NodeContainer::GetGlobal();
 
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         if (node->GetId() != nodeid)
@@ -567,7 +567,7 @@
                                            std::string prefix,
                                            NetDeviceContainer d)
 {
-    for (NetDeviceContainer::Iterator i = d.Begin(); i != d.End(); ++i)
+    for (auto i = d.Begin(); i != d.End(); ++i)
     {
         Ptr<NetDevice> dev = *i;
         EnableAsciiInternal(stream, prefix, dev, false);
@@ -601,7 +601,7 @@
                                            NodeContainer n)
 {
     NetDeviceContainer devs;
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         for (uint32_t j = 0; j < node->GetNDevices(); ++j)
@@ -665,7 +665,7 @@
 {
     NodeContainer n = NodeContainer::GetGlobal();
 
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         if (node->GetId() != nodeid)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/helper/trace-helper.h ns-3.40/src/network/helper/trace-helper.h
--- ns-3.39/src/network/helper/trace-helper.h	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/helper/trace-helper.h	2023-09-27 13:30:37.850839600 -0700
@@ -18,9 +18,10 @@
 #ifndef TRACE_HELPER_H
 #define TRACE_HELPER_H
 
+#include "net-device-container.h"
+#include "node-container.h"
+
 #include "ns3/assert.h"
-#include "ns3/net-device-container.h"
-#include "ns3/node-container.h"
 #include "ns3/output-stream-wrapper.h"
 #include "ns3/pcap-file-wrapper.h"
 #include "ns3/simulator.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/address.h ns-3.40/src/network/model/address.h
--- ns-3.39/src/network/model/address.h	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/model/address.h	2023-09-27 13:30:37.850839600 -0700
@@ -20,9 +20,10 @@
 #ifndef ADDRESS_H
 #define ADDRESS_H
 
+#include "tag-buffer.h"
+
 #include "ns3/attribute-helper.h"
 #include "ns3/attribute.h"
-#include "ns3/tag-buffer.h"
 
 #include <ostream>
 #include <stdint.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/application.cc ns-3.40/src/network/model/application.cc
--- ns-3.39/src/network/model/application.cc	2023-07-05 14:23:48.057428100 -0700
+++ ns-3.40/src/network/model/application.cc	2023-09-27 13:30:37.850839600 -0700
@@ -22,8 +22,9 @@
 
 #include "application.h"
 
+#include "node.h"
+
 #include "ns3/log.h"
-#include "ns3/node.h"
 #include "ns3/nstime.h"
 #include "ns3/simulator.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/application.h ns-3.40/src/network/model/application.h
--- ns-3.39/src/network/model/application.h	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/application.h	2023-09-27 13:30:37.850839600 -0700
@@ -20,8 +20,9 @@
 #ifndef APPLICATION_H
 #define APPLICATION_H
 
+#include "node.h"
+
 #include "ns3/event-id.h"
-#include "ns3/node.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
 #include "ns3/ptr.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/buffer.cc ns-3.40/src/network/model/buffer.cc
--- ns-3.39/src/network/model/buffer.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/buffer.cc	2023-09-27 13:30:37.850839600 -0700
@@ -88,7 +88,7 @@
     NS_LOG_FUNCTION(this);
     if (IS_INITIALIZED(g_freeList))
     {
-        for (Buffer::FreeList::iterator i = g_freeList->begin(); i != g_freeList->end(); i++)
+        for (auto i = g_freeList->begin(); i != g_freeList->end(); i++)
         {
             Buffer::Deallocate(*i);
         }
@@ -173,8 +173,8 @@
     NS_ASSERT(reqSize >= 1);
     reqSize += ALLOC_OVER_PROVISION;
     uint32_t size = reqSize - 1 + sizeof(Buffer::Data);
-    uint8_t* b = new uint8_t[size];
-    Buffer::Data* data = reinterpret_cast<Buffer::Data*>(b);
+    auto b = new uint8_t[size];
+    auto data = reinterpret_cast<Buffer::Data*>(b);
     data->m_size = reqSize;
     data->m_count = 1;
     return data;
@@ -185,7 +185,7 @@
 {
     NS_LOG_FUNCTION(data);
     NS_ASSERT(data->m_count == 0);
-    uint8_t* buf = reinterpret_cast<uint8_t*>(data);
+    auto buf = reinterpret_cast<uint8_t*>(data);
     delete[] buf;
 }
 
@@ -582,7 +582,7 @@
 Buffer::Serialize(uint8_t* buffer, uint32_t maxSize) const
 {
     NS_LOG_FUNCTION(this << &buffer << maxSize);
-    uint32_t* p = reinterpret_cast<uint32_t*>(buffer);
+    auto p = reinterpret_cast<uint32_t*>(buffer);
     uint32_t size = 0;
 
     // Add the zero data length
@@ -654,7 +654,7 @@
 Buffer::Deserialize(const uint8_t* buffer, uint32_t size)
 {
     NS_LOG_FUNCTION(this << &buffer << size);
-    const uint32_t* p = reinterpret_cast<const uint32_t*>(buffer);
+    auto p = reinterpret_cast<const uint32_t*>(buffer);
     uint32_t sizeCheck = size - 4;
 
     NS_ASSERT(sizeCheck >= 4);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/byte-tag-list.cc ns-3.40/src/network/model/byte-tag-list.cc
--- ns-3.39/src/network/model/byte-tag-list.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/byte-tag-list.cc	2023-09-27 13:30:37.850839600 -0700
@@ -67,9 +67,9 @@
 ByteTagListDataFreeList::~ByteTagListDataFreeList()
 {
     NS_LOG_FUNCTION(this);
-    for (ByteTagListDataFreeList::iterator i = begin(); i != end(); i++)
+    for (auto i = begin(); i != end(); i++)
     {
-        uint8_t* buffer = (uint8_t*)(*i);
+        auto buffer = (uint8_t*)(*i);
         delete[] buffer;
     }
 }
@@ -366,11 +366,11 @@
             data->dirty = 0;
             return data;
         }
-        uint8_t* buffer = (uint8_t*)data;
+        auto buffer = (uint8_t*)data;
         delete[] buffer;
     }
-    uint8_t* buffer = new uint8_t[std::max(size, g_maxSize) + sizeof(ByteTagListData) - 4];
-    ByteTagListData* data = (ByteTagListData*)buffer;
+    auto buffer = new uint8_t[std::max(size, g_maxSize) + sizeof(ByteTagListData) - 4];
+    auto data = (ByteTagListData*)buffer;
     data->count = 1;
     data->size = size;
     data->dirty = 0;
@@ -391,7 +391,7 @@
     {
         if (g_freeList.size() > FREE_LIST_SIZE || data->size < g_maxSize)
         {
-            uint8_t* buffer = (uint8_t*)data;
+            auto buffer = (uint8_t*)data;
             delete[] buffer;
         }
         else
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/channel-list.cc ns-3.40/src/network/model/channel-list.cc
--- ns-3.39/src/network/model/channel-list.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/channel-list.cc	2023-09-27 13:30:37.850839600 -0700
@@ -162,7 +162,7 @@
 ChannelListPriv::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (std::vector<Ptr<Channel>>::iterator i = m_channels.begin(); i != m_channels.end(); i++)
+    for (auto i = m_channels.begin(); i != m_channels.end(); i++)
     {
         Ptr<Channel> channel = *i;
         channel->Dispose();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/nix-vector.h ns-3.40/src/network/model/nix-vector.h
--- ns-3.39/src/network/model/nix-vector.h	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/nix-vector.h	2023-09-27 13:30:37.854839600 -0700
@@ -20,7 +20,8 @@
 #ifndef NIX_VECTOR_H
 #define NIX_VECTOR_H
 
-#include "ns3/buffer.h"
+#include "buffer.h"
+
 #include "ns3/ptr.h"
 #include "ns3/simple-ref-count.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/node.cc ns-3.40/src/network/model/node.cc
--- ns-3.39/src/network/model/node.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/node.cc	2023-09-27 13:30:37.854839600 -0700
@@ -23,13 +23,13 @@
 #include "application.h"
 #include "net-device.h"
 #include "node-list.h"
+#include "packet.h"
 
 #include "ns3/assert.h"
 #include "ns3/boolean.h"
 #include "ns3/global-value.h"
 #include "ns3/log.h"
 #include "ns3/object-vector.h"
-#include "ns3/packet.h"
 #include "ns3/simulator.h"
 #include "ns3/uinteger.h"
 
@@ -199,16 +199,14 @@
     NS_LOG_FUNCTION(this);
     m_deviceAdditionListeners.clear();
     m_handlers.clear();
-    for (std::vector<Ptr<NetDevice>>::iterator i = m_devices.begin(); i != m_devices.end(); i++)
+    for (auto i = m_devices.begin(); i != m_devices.end(); i++)
     {
         Ptr<NetDevice> device = *i;
         device->Dispose();
         *i = nullptr;
     }
     m_devices.clear();
-    for (std::vector<Ptr<Application>>::iterator i = m_applications.begin();
-         i != m_applications.end();
-         i++)
+    for (auto i = m_applications.begin(); i != m_applications.end(); i++)
     {
         Ptr<Application> application = *i;
         application->Dispose();
@@ -222,14 +220,12 @@
 Node::DoInitialize()
 {
     NS_LOG_FUNCTION(this);
-    for (std::vector<Ptr<NetDevice>>::iterator i = m_devices.begin(); i != m_devices.end(); i++)
+    for (auto i = m_devices.begin(); i != m_devices.end(); i++)
     {
         Ptr<NetDevice> device = *i;
         device->Initialize();
     }
-    for (std::vector<Ptr<Application>>::iterator i = m_applications.begin();
-         i != m_applications.end();
-         i++)
+    for (auto i = m_applications.begin(); i != m_applications.end(); i++)
     {
         Ptr<Application> application = *i;
         application->Initialize();
@@ -256,8 +252,7 @@
     {
         if (!device)
         {
-            for (std::vector<Ptr<NetDevice>>::iterator i = m_devices.begin(); i != m_devices.end();
-                 i++)
+            for (auto i = m_devices.begin(); i != m_devices.end(); i++)
             {
                 Ptr<NetDevice> dev = *i;
                 dev->SetPromiscReceiveCallback(MakeCallback(&Node::PromiscReceiveFromDevice, this));
@@ -276,7 +271,7 @@
 Node::UnregisterProtocolHandler(ProtocolHandler handler)
 {
     NS_LOG_FUNCTION(this << &handler);
-    for (ProtocolHandlerList::iterator i = m_handlers.begin(); i != m_handlers.end(); i++)
+    for (auto i = m_handlers.begin(); i != m_handlers.end(); i++)
     {
         if (i->handler.IsEqual(handler))
         {
@@ -343,7 +338,7 @@
                          << packet->GetUid());
     bool found = false;
 
-    for (ProtocolHandlerList::iterator i = m_handlers.begin(); i != m_handlers.end(); i++)
+    for (auto i = m_handlers.begin(); i != m_handlers.end(); i++)
     {
         if (!i->device || (i->device == device))
         {
@@ -366,8 +361,7 @@
     NS_LOG_FUNCTION(this << &listener);
     m_deviceAdditionListeners.push_back(listener);
     // and, then, notify the new listener about all existing devices.
-    for (std::vector<Ptr<NetDevice>>::const_iterator i = m_devices.begin(); i != m_devices.end();
-         ++i)
+    for (auto i = m_devices.begin(); i != m_devices.end(); ++i)
     {
         listener(*i);
     }
@@ -377,9 +371,7 @@
 Node::UnregisterDeviceAdditionListener(DeviceAdditionListener listener)
 {
     NS_LOG_FUNCTION(this << &listener);
-    for (DeviceAdditionListenerList::iterator i = m_deviceAdditionListeners.begin();
-         i != m_deviceAdditionListeners.end();
-         i++)
+    for (auto i = m_deviceAdditionListeners.begin(); i != m_deviceAdditionListeners.end(); i++)
     {
         if ((*i).IsEqual(listener))
         {
@@ -393,9 +385,7 @@
 Node::NotifyDeviceAdded(Ptr<NetDevice> device)
 {
     NS_LOG_FUNCTION(this << device);
-    for (DeviceAdditionListenerList::iterator i = m_deviceAdditionListeners.begin();
-         i != m_deviceAdditionListeners.end();
-         i++)
+    for (auto i = m_deviceAdditionListeners.begin(); i != m_deviceAdditionListeners.end(); i++)
     {
         (*i)(device);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/node.h ns-3.40/src/network/model/node.h
--- ns-3.39/src/network/model/node.h	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/node.h	2023-09-27 13:30:37.854839600 -0700
@@ -20,8 +20,9 @@
 #ifndef NODE_H
 #define NODE_H
 
+#include "net-device.h"
+
 #include "ns3/callback.h"
-#include "ns3/net-device.h"
 #include "ns3/object.h"
 #include "ns3/ptr.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/node-list.cc ns-3.40/src/network/model/node-list.cc
--- ns-3.39/src/network/model/node-list.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/node-list.cc	2023-09-27 13:30:37.854839600 -0700
@@ -165,7 +165,7 @@
 NodeListPriv::DoDispose()
 {
     NS_LOG_FUNCTION(this);
-    for (std::vector<Ptr<Node>>::iterator i = m_nodes.begin(); i != m_nodes.end(); i++)
+    for (auto i = m_nodes.begin(); i != m_nodes.end(); i++)
     {
         Ptr<Node> node = *i;
         node->Dispose();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/packet.cc ns-3.40/src/network/model/packet.cc
--- ns-3.39/src/network/model/packet.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/packet.cc	2023-09-27 13:30:37.854839600 -0700
@@ -490,7 +490,7 @@
                     NS_ASSERT(!constructor.IsNull());
                     ObjectBase* instance = constructor();
                     NS_ASSERT(instance != nullptr);
-                    Chunk* chunk = dynamic_cast<Chunk*>(instance);
+                    auto chunk = dynamic_cast<Chunk*>(instance);
                     NS_ASSERT(chunk != nullptr);
                     if (item.type == PacketMetadata::Item::HEADER)
                     {
@@ -662,7 +662,7 @@
 uint32_t
 Packet::Serialize(uint8_t* buffer, uint32_t maxSize) const
 {
-    uint32_t* p = reinterpret_cast<uint32_t*>(buffer);
+    auto p = reinterpret_cast<uint32_t*>(buffer);
     uint32_t size = 0;
 
     // if nix-vector exists, serialize it
@@ -825,7 +825,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    const uint32_t* p = reinterpret_cast<const uint32_t*>(buffer);
+    auto p = reinterpret_cast<const uint32_t*>(buffer);
 
     // read nix-vector
     NS_ASSERT(!m_nixVector);
@@ -934,7 +934,7 @@
 Packet::AddByteTag(const Tag& tag) const
 {
     NS_LOG_FUNCTION(this << tag.GetInstanceTypeId().GetName() << tag.GetSerializedSize());
-    ByteTagList* list = const_cast<ByteTagList*>(&m_byteTagList);
+    auto list = const_cast<ByteTagList*>(&m_byteTagList);
     TagBuffer buffer = list->Add(tag.GetInstanceTypeId(), tag.GetSerializedSize(), 0, GetSize());
     tag.Serialize(buffer);
 }
@@ -944,7 +944,7 @@
 {
     NS_LOG_FUNCTION(this << tag.GetInstanceTypeId().GetName() << tag.GetSerializedSize());
     NS_ABORT_MSG_IF(end < start, "Invalid byte range");
-    ByteTagList* list = const_cast<ByteTagList*>(&m_byteTagList);
+    auto list = const_cast<ByteTagList*>(&m_byteTagList);
     TagBuffer buffer = list->Add(tag.GetInstanceTypeId(),
                                  tag.GetSerializedSize(),
                                  static_cast<int32_t>(start),
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/packet-metadata.cc ns-3.40/src/network/model/packet-metadata.cc
--- ns-3.39/src/network/model/packet-metadata.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/packet-metadata.cc	2023-09-27 13:30:37.854839600 -0700
@@ -44,7 +44,7 @@
 PacketMetadata::DataFreeList::~DataFreeList()
 {
     NS_LOG_FUNCTION(this);
-    for (iterator i = begin(); i != end(); i++)
+    for (auto i = begin(); i != end(); i++)
     {
         PacketMetadata::Deallocate(*i);
     }
@@ -620,8 +620,8 @@
         n = PACKET_METADATA_DATA_M_DATA_SIZE;
     }
     size += n - PACKET_METADATA_DATA_M_DATA_SIZE;
-    uint8_t* buf = new uint8_t[size];
-    PacketMetadata::Data* data = (PacketMetadata::Data*)buf;
+    auto buf = new uint8_t[size];
+    auto data = (PacketMetadata::Data*)buf;
     data->m_size = n;
     data->m_count = 1;
     data->m_dirtyEnd = 0;
@@ -632,7 +632,7 @@
 PacketMetadata::Deallocate(PacketMetadata::Data* data)
 {
     NS_LOG_FUNCTION(data);
-    uint8_t* buf = (uint8_t*)data;
+    auto buf = (uint8_t*)data;
     delete[] buf;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/packet-tag-list.cc ns-3.40/src/network/model/packet-tag-list.cc
--- ns-3.39/src/network/model/packet-tag-list.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/packet-tag-list.cc	2023-09-27 13:30:37.854839600 -0700
@@ -47,7 +47,7 @@
     void* p = std::malloc(sizeof(TagData) + dataSize - 1);
     // The matching frees are in RemoveAll and RemoveWriter
 
-    TagData* tag = new (p) TagData;
+    auto tag = new (p) TagData;
     tag->size = dataSize;
     return tag;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/socket.cc ns-3.40/src/network/model/socket.cc
--- ns-3.39/src/network/model/socket.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/socket.cc	2023-09-27 13:30:37.854839600 -0700
@@ -22,10 +22,10 @@
 #include "socket.h"
 
 #include "node.h"
+#include "packet.h"
 #include "socket-factory.h"
 
 #include "ns3/log.h"
-#include "ns3/packet.h"
 
 #include <limits>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/socket.h ns-3.40/src/network/model/socket.h
--- ns-3.39/src/network/model/socket.h	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/socket.h	2023-09-27 13:30:37.854839600 -0700
@@ -23,14 +23,14 @@
 #define NS3_SOCKET_H
 
 #include "address.h"
+#include "net-device.h"
+#include "tag.h"
 
 #include "ns3/callback.h"
 #include "ns3/inet-socket-address.h"
 #include "ns3/inet6-socket-address.h"
-#include "ns3/net-device.h"
 #include "ns3/object.h"
 #include "ns3/ptr.h"
-#include "ns3/tag.h"
 
 #include <stdint.h>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/model/tag-buffer.cc ns-3.40/src/network/model/tag-buffer.cc
--- ns-3.39/src/network/model/tag-buffer.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/model/tag-buffer.cc	2023-09-27 13:30:37.854839600 -0700
@@ -118,7 +118,7 @@
 TagBuffer::WriteDouble(double v)
 {
     NS_LOG_FUNCTION(this << v);
-    uint8_t* buf = (uint8_t*)&v;
+    auto buf = (uint8_t*)&v;
     for (uint32_t i = 0; i < sizeof(double); ++i, ++buf)
     {
         WriteU8(*buf);
@@ -171,7 +171,7 @@
 {
     NS_LOG_FUNCTION(this);
     double v;
-    uint8_t* buf = (uint8_t*)&v;
+    auto buf = (uint8_t*)&v;
     for (uint32_t i = 0; i < sizeof(double); ++i, ++buf)
     {
         *buf = ReadU8();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/test/buffer-test.cc ns-3.40/src/network/test/buffer-test.cc
--- ns-3.39/src/network/test/buffer-test.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/test/buffer-test.cc	2023-09-27 13:30:37.854839600 -0700
@@ -363,7 +363,7 @@
     NS_TEST_ASSERT_MSG_EQ(sizeBuffer, ct.size(), "Buffer bad size");
     const uint8_t* evilBuffer = buffer.PeekData();
     NS_TEST_ASSERT_MSG_NE(evilBuffer, 0, "Buffer PeekData failed");
-    uint8_t* cBuf = (uint8_t*)malloc(sizeBuffer);
+    auto cBuf = (uint8_t*)malloc(sizeBuffer);
     uint32_t copyLen = buffer.CopyData(cBuf, sizeBuffer);
     NS_TEST_ASSERT_MSG_EQ(copyLen, sizeBuffer, "CopyData return bad size");
     for (uint32_t i = 0; i < sizeBuffer; i++)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/test/packet-metadata-test.cc ns-3.40/src/network/test/packet-metadata-test.cc
--- ns-3.39/src/network/test/packet-metadata-test.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/test/packet-metadata-test.cc	2023-09-27 13:30:37.854839600 -0700
@@ -381,7 +381,7 @@
         if (item.type == PacketMetadata::Item::HEADER)
         {
             Callback<ObjectBase*> constructor = item.tid.GetConstructor();
-            HistoryHeaderBase* header = dynamic_cast<HistoryHeaderBase*>(constructor());
+            auto header = dynamic_cast<HistoryHeaderBase*>(constructor());
             if (header == nullptr)
             {
                 goto error;
@@ -397,7 +397,7 @@
         else if (item.type == PacketMetadata::Item::TRAILER)
         {
             Callback<ObjectBase*> constructor = item.tid.GetConstructor();
-            HistoryTrailerBase* trailer = dynamic_cast<HistoryTrailerBase*>(constructor());
+            auto trailer = dynamic_cast<HistoryTrailerBase*>(constructor());
             if (trailer == nullptr)
             {
                 goto error;
@@ -413,7 +413,7 @@
         got.push_back(item.currentSize);
     }
 
-    for (std::list<int>::iterator i = got.begin(), j = expected.begin(); i != got.end(); i++, j++)
+    for (auto i = got.begin(), j = expected.begin(); i != got.end(); i++, j++)
     {
         NS_ASSERT(j != expected.end());
         if (*j != *i)
@@ -425,12 +425,12 @@
 error:
     std::ostringstream failure;
     failure << "PacketMetadata error. Got:\"";
-    for (std::list<int>::iterator i = got.begin(); i != got.end(); i++)
+    for (auto i = got.begin(); i != got.end(); i++)
     {
         failure << *i << ", ";
     }
     failure << "\", expected: \"";
-    for (std::list<int>::iterator j = expected.begin(); j != expected.end(); j++)
+    for (auto j = expected.begin(); j != expected.end(); j++)
     {
         failure << *j << ", ";
     }
@@ -872,7 +872,7 @@
     REM_HEADER(p3, 2);
     CHECK_HISTORY(p3, 1, 11);
 
-    uint8_t* buf = new uint8_t[p3->GetSize()];
+    auto buf = new uint8_t[p3->GetSize()];
     p3->CopyData(buf, p3->GetSize());
     std::string msg = std::string(reinterpret_cast<const char*>(buf), p3->GetSize());
     delete[] buf;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/test/packet-test-suite.cc ns-3.40/src/network/test/packet-test-suite.cc
--- ns-3.39/src/network/test/packet-test-suite.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/test/packet-test-suite.cc	2023-09-27 13:30:37.854839600 -0700
@@ -632,7 +632,7 @@
 
     NS_TEST_EXPECT_MSG_EQ(packet->GetSize(), 11, "trivial");
 
-    uint8_t* buf = new uint8_t[packet->GetSize()];
+    auto buf = new uint8_t[packet->GetSize()];
     packet->CopyData(buf, packet->GetSize());
 
     std::string msg = std::string(reinterpret_cast<const char*>(buf), packet->GetSize());
@@ -811,7 +811,7 @@
         p1->AddPacketTag(c1);
 
         uint32_t serializedSize = p1->GetSerializedSize();
-        uint8_t* buffer = new uint8_t[serializedSize + 16];
+        auto buffer = new uint8_t[serializedSize + 16];
         p1->Serialize(buffer, serializedSize);
 
         Ptr<Packet> p2 = Create<Packet>(buffer, serializedSize, true);
@@ -846,7 +846,7 @@
         CHECK(p1, 3, E(10, 0, 1000), E(11, 0, 1000), E(12, 0, 1000));
 
         uint32_t serializedSize = p1->GetSerializedSize();
-        uint8_t* buffer = new uint8_t[serializedSize];
+        auto buffer = new uint8_t[serializedSize];
         p1->Serialize(buffer, serializedSize);
 
         Ptr<Packet> p2 = Create<Packet>(buffer, serializedSize, true);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/drop-tail-queue.h ns-3.40/src/network/utils/drop-tail-queue.h
--- ns-3.39/src/network/utils/drop-tail-queue.h	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/utils/drop-tail-queue.h	2023-09-27 13:30:37.854839600 -0700
@@ -18,7 +18,7 @@
 #ifndef DROPTAIL_H
 #define DROPTAIL_H
 
-#include "ns3/queue.h"
+#include "queue.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/error-channel.cc ns-3.40/src/network/utils/error-channel.cc
--- ns-3.39/src/network/utils/error-channel.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/utils/error-channel.cc	2023-09-27 13:30:37.854839600 -0700
@@ -19,10 +19,11 @@
 
 #include "error-channel.h"
 
+#include "simple-net-device.h"
+
 #include "ns3/log.h"
 #include "ns3/node.h"
 #include "ns3/packet.h"
-#include "ns3/simple-net-device.h"
 #include "ns3/simulator.h"
 
 namespace ns3
@@ -86,9 +87,7 @@
                    Ptr<SimpleNetDevice> sender)
 {
     NS_LOG_FUNCTION(p << protocol << to << from << sender);
-    for (std::vector<Ptr<SimpleNetDevice>>::const_iterator i = m_devices.begin();
-         i != m_devices.end();
-         ++i)
+    for (auto i = m_devices.begin(); i != m_devices.end(); ++i)
     {
         Ptr<SimpleNetDevice> tmp = *i;
         if (tmp == sender)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/error-channel.h ns-3.40/src/network/utils/error-channel.h
--- ns-3.39/src/network/utils/error-channel.h	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/utils/error-channel.h	2023-09-27 13:30:37.854839600 -0700
@@ -19,11 +19,12 @@
 #ifndef ERROR_CHANNEL_H
 #define ERROR_CHANNEL_H
 
+#include "error-model.h"
+#include "mac48-address.h"
+#include "simple-channel.h"
+
 #include "ns3/channel.h"
-#include "ns3/error-model.h"
-#include "ns3/mac48-address.h"
 #include "ns3/nstime.h"
-#include "ns3/simple-channel.h"
 
 #include <vector>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/error-model.cc ns-3.40/src/network/utils/error-model.cc
--- ns-3.39/src/network/utils/error-model.cc	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/utils/error-model.cc	2023-09-27 13:30:37.854839600 -0700
@@ -471,7 +471,7 @@
         return false;
     }
     auto uid = p->GetUid();
-    for (PacketListCI i = m_packetList.begin(); i != m_packetList.end(); i++)
+    for (auto i = m_packetList.begin(); i != m_packetList.end(); i++)
     {
         if (uid == *i)
         {
@@ -538,7 +538,7 @@
         return false;
     }
     m_timesInvoked += 1;
-    for (PacketListCI i = m_packetList.begin(); i != m_packetList.end(); i++)
+    for (auto i = m_packetList.begin(); i != m_packetList.end(); i++)
     {
         if (m_timesInvoked - 1 == *i)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/ethernet-header.h ns-3.40/src/network/utils/ethernet-header.h
--- ns-3.39/src/network/utils/ethernet-header.h	2023-07-05 14:23:48.061428300 -0700
+++ ns-3.40/src/network/utils/ethernet-header.h	2023-09-27 13:30:37.854839600 -0700
@@ -20,8 +20,9 @@
 #ifndef ETHERNET_HEADER_H
 #define ETHERNET_HEADER_H
 
+#include "mac48-address.h"
+
 #include "ns3/header.h"
-#include "ns3/mac48-address.h"
 
 #include <string>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/ipv4-address.cc ns-3.40/src/network/utils/ipv4-address.cc
--- ns-3.39/src/network/utils/ipv4-address.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/ipv4-address.cc	2023-09-27 13:30:37.854839600 -0700
@@ -52,7 +52,7 @@
     NS_LOG_FUNCTION(this << mask);
     if (*mask == '/')
     {
-        uint32_t plen = static_cast<uint32_t>(std::atoi(++mask));
+        auto plen = static_cast<uint32_t>(std::atoi(++mask));
         NS_ASSERT(plen <= 32);
         if (plen > 0)
         {
@@ -113,7 +113,7 @@
 Ipv4Mask::GetLoopback()
 {
     NS_LOG_FUNCTION_NOARGS();
-    static Ipv4Mask loopback = Ipv4Mask("255.0.0.0");
+    static Ipv4Mask loopback("255.0.0.0");
     return loopback;
 }
 
@@ -121,7 +121,7 @@
 Ipv4Mask::GetZero()
 {
     NS_LOG_FUNCTION_NOARGS();
-    static Ipv4Mask zero = Ipv4Mask("0.0.0.0");
+    static Ipv4Mask zero("0.0.0.0");
     return zero;
 }
 
@@ -129,7 +129,7 @@
 Ipv4Mask::GetOnes()
 {
     NS_LOG_FUNCTION_NOARGS();
-    static Ipv4Mask ones = Ipv4Mask("255.255.255.255");
+    static Ipv4Mask ones("255.255.255.255");
     return ones;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/ipv6-address.h ns-3.40/src/network/utils/ipv6-address.h
--- ns-3.39/src/network/utils/ipv6-address.h	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/ipv6-address.h	2023-09-27 13:30:37.858839800 -0700
@@ -20,11 +20,11 @@
 #ifndef IPV6_ADDRESS_H
 #define IPV6_ADDRESS_H
 
+#include "ipv4-address.h"
 #include "mac8-address.h"
 
 #include "ns3/address.h"
 #include "ns3/attribute-helper.h"
-#include "ns3/ipv4-address.h"
 
 #include <cstring>
 #include <ostream>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/mac16-address.cc ns-3.40/src/network/utils/mac16-address.cc
--- ns-3.39/src/network/utils/mac16-address.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/mac16-address.cc	2023-09-27 13:30:37.858839800 -0700
@@ -201,7 +201,7 @@
 {
     NS_LOG_FUNCTION_NOARGS();
 
-    static Mac16Address broadcast = Mac16Address("ff:ff");
+    static Mac16Address broadcast("ff:ff");
     return broadcast;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/mac48-address.cc ns-3.40/src/network/utils/mac48-address.cc
--- ns-3.39/src/network/utils/mac48-address.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/mac48-address.cc	2023-09-27 13:30:37.858839800 -0700
@@ -201,7 +201,7 @@
 Mac48Address::GetBroadcast()
 {
     NS_LOG_FUNCTION_NOARGS();
-    static Mac48Address broadcast = Mac48Address("ff:ff:ff:ff:ff:ff");
+    static Mac48Address broadcast("ff:ff:ff:ff:ff:ff");
     return broadcast;
 }
 
@@ -209,7 +209,7 @@
 Mac48Address::GetMulticastPrefix()
 {
     NS_LOG_FUNCTION_NOARGS();
-    static Mac48Address multicast = Mac48Address("01:00:5e:00:00:00");
+    static Mac48Address multicast("01:00:5e:00:00:00");
     return multicast;
 }
 
@@ -217,7 +217,7 @@
 Mac48Address::GetMulticast6Prefix()
 {
     NS_LOG_FUNCTION_NOARGS();
-    static Mac48Address multicast = Mac48Address("33:33:00:00:00:00");
+    static Mac48Address multicast("33:33:00:00:00:00");
     return multicast;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/net-device-queue-interface.cc ns-3.40/src/network/utils/net-device-queue-interface.cc
--- ns-3.39/src/network/utils/net-device-queue-interface.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/net-device-queue-interface.cc	2023-09-27 13:30:37.858839800 -0700
@@ -17,11 +17,12 @@
  * Author: Stefano Avallone <stefano.avallone@.unina.it>
  */
 
-#include "ns3/net-device-queue-interface.h"
+#include "net-device-queue-interface.h"
+
+#include "queue-item.h"
+#include "queue-limits.h"
 
 #include "ns3/abort.h"
-#include "ns3/queue-item.h"
-#include "ns3/queue-limits.h"
 #include "ns3/uinteger.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/output-stream-wrapper.cc ns-3.40/src/network/utils/output-stream-wrapper.cc
--- ns-3.39/src/network/utils/output-stream-wrapper.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/output-stream-wrapper.cc	2023-09-27 13:30:37.858839800 -0700
@@ -32,7 +32,7 @@
     : m_destroyable(true)
 {
     NS_LOG_FUNCTION(this << filename << filemode);
-    std::ofstream* os = new std::ofstream();
+    auto os = new std::ofstream();
     os->open(filename, filemode);
     m_ostream = os;
     FatalImpl::RegisterStream(m_ostream);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/packetbb.cc ns-3.40/src/network/utils/packetbb.cc
--- ns-3.39/src/network/utils/packetbb.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/packetbb.cc	2023-09-27 13:30:37.858839800 -0700
@@ -23,9 +23,10 @@
 
 #include "packetbb.h"
 
+#include "ipv4-address.h"
+#include "ipv6-address.h"
+
 #include "ns3/assert.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv6-address.h"
 #include "ns3/log.h"
 
 static const uint8_t VERSION = 0;
@@ -181,7 +182,7 @@
 PbbTlvBlock::Clear()
 {
     NS_LOG_FUNCTION(this);
-    for (Iterator iter = Begin(); iter != End(); iter++)
+    for (auto iter = Begin(); iter != End(); iter++)
     {
         *iter = nullptr;
     }
@@ -194,7 +195,7 @@
     NS_LOG_FUNCTION(this);
     /* tlv size */
     uint32_t size = 2;
-    for (ConstIterator iter = Begin(); iter != End(); iter++)
+    for (auto iter = Begin(); iter != End(); iter++)
     {
         size += (*iter)->GetSerializedSize();
     }
@@ -215,7 +216,7 @@
      * position. */
     Buffer::Iterator tlvsize = start;
     start.Next(2);
-    for (ConstIterator iter = Begin(); iter != End(); iter++)
+    for (auto iter = Begin(); iter != End(); iter++)
     {
         (*iter)->Serialize(start);
     }
@@ -263,7 +264,7 @@
     os << prefix << "\tsize = " << Size() << std::endl;
     os << prefix << "\tmembers [" << std::endl;
 
-    for (ConstIterator iter = Begin(); iter != End(); iter++)
+    for (auto iter = Begin(); iter != End(); iter++)
     {
         (*iter)->Print(os, level + 2);
     }
@@ -420,7 +421,7 @@
 PbbAddressTlvBlock::Clear()
 {
     NS_LOG_FUNCTION(this);
-    for (Iterator iter = Begin(); iter != End(); iter++)
+    for (auto iter = Begin(); iter != End(); iter++)
     {
         *iter = nullptr;
     }
@@ -433,7 +434,7 @@
     NS_LOG_FUNCTION(this);
     /* tlv size */
     uint32_t size = 2;
-    for (ConstIterator iter = Begin(); iter != End(); iter++)
+    for (auto iter = Begin(); iter != End(); iter++)
     {
         size += (*iter)->GetSerializedSize();
     }
@@ -454,7 +455,7 @@
      * position. */
     Buffer::Iterator tlvsize = start;
     start.Next(2);
-    for (ConstIterator iter = Begin(); iter != End(); iter++)
+    for (auto iter = Begin(); iter != End(); iter++)
     {
         (*iter)->Serialize(start);
     }
@@ -502,7 +503,7 @@
     os << prefix << "\tsize = " << Size() << std::endl;
     os << prefix << "\tmembers [" << std::endl;
 
-    for (ConstIterator iter = Begin(); iter != End(); iter++)
+    for (auto iter = Begin(); iter != End(); iter++)
     {
         (*iter)->Print(os, level + 2);
     }
@@ -821,7 +822,7 @@
 PbbPacket::MessageClear()
 {
     NS_LOG_FUNCTION(this);
-    for (MessageIterator iter = MessageBegin(); iter != MessageEnd(); iter++)
+    for (auto iter = MessageBegin(); iter != MessageEnd(); iter++)
     {
         *iter = nullptr;
     }
@@ -861,7 +862,7 @@
         size += m_tlvList.GetSerializedSize();
     }
 
-    for (ConstMessageIterator iter = MessageBegin(); iter != MessageEnd(); iter++)
+    for (auto iter = MessageBegin(); iter != MessageEnd(); iter++)
     {
         size += (*iter)->GetSerializedSize();
     }
@@ -896,7 +897,7 @@
 
     bufref.WriteU8(flags);
 
-    for (ConstMessageIterator iter = MessageBegin(); iter != MessageEnd(); iter++)
+    for (auto iter = MessageBegin(); iter != MessageEnd(); iter++)
     {
         (*iter)->Serialize(start);
     }
@@ -951,7 +952,7 @@
 
     m_tlvList.Print(os, 1);
 
-    for (ConstMessageIterator iter = MessageBegin(); iter != MessageEnd(); iter++)
+    for (auto iter = MessageBegin(); iter != MessageEnd(); iter++)
     {
         (*iter)->Print(os, 1);
     }
@@ -1382,7 +1383,7 @@
 PbbMessage::AddressBlockClear()
 {
     NS_LOG_FUNCTION(this);
-    for (AddressBlockIterator iter = AddressBlockBegin(); iter != AddressBlockEnd(); iter++)
+    for (auto iter = AddressBlockBegin(); iter != AddressBlockEnd(); iter++)
     {
         *iter = nullptr;
     }
@@ -1418,7 +1419,7 @@
 
     size += m_tlvList.GetSerializedSize();
 
-    for (ConstAddressBlockIterator iter = AddressBlockBegin(); iter != AddressBlockEnd(); iter++)
+    for (auto iter = AddressBlockBegin(); iter != AddressBlockEnd(); iter++)
     {
         size += (*iter)->GetSerializedSize();
     }
@@ -1473,7 +1474,7 @@
 
     m_tlvList.Serialize(start);
 
-    for (ConstAddressBlockIterator iter = AddressBlockBegin(); iter != AddressBlockEnd(); iter++)
+    for (auto iter = AddressBlockBegin(); iter != AddressBlockEnd(); iter++)
     {
         (*iter)->Serialize(start);
     }
@@ -1601,7 +1602,7 @@
 
     m_tlvList.Print(os, level + 1);
 
-    for (ConstAddressBlockIterator iter = AddressBlockBegin(); iter != AddressBlockEnd(); iter++)
+    for (auto iter = AddressBlockBegin(); iter != AddressBlockEnd(); iter++)
     {
         (*iter)->Print(os, level + 1);
     }
@@ -1721,7 +1722,7 @@
 PbbMessageIpv4::SerializeOriginatorAddress(Buffer::Iterator& start) const
 {
     NS_LOG_FUNCTION(this << &start);
-    uint8_t* buffer = new uint8_t[GetAddressLength() + 1];
+    auto buffer = new uint8_t[GetAddressLength() + 1];
     Ipv4Address::ConvertFrom(GetOriginatorAddress()).Serialize(buffer);
     start.Write(buffer, GetAddressLength() + 1);
     delete[] buffer;
@@ -1731,7 +1732,7 @@
 PbbMessageIpv4::DeserializeOriginatorAddress(Buffer::Iterator& start) const
 {
     NS_LOG_FUNCTION(this << &start);
-    uint8_t* buffer = new uint8_t[GetAddressLength() + 1];
+    auto buffer = new uint8_t[GetAddressLength() + 1];
     start.Read(buffer, GetAddressLength() + 1);
     Address result = Ipv4Address::Deserialize(buffer);
     delete[] buffer;
@@ -1772,7 +1773,7 @@
 PbbMessageIpv6::SerializeOriginatorAddress(Buffer::Iterator& start) const
 {
     NS_LOG_FUNCTION(this << &start);
-    uint8_t* buffer = new uint8_t[GetAddressLength() + 1];
+    auto buffer = new uint8_t[GetAddressLength() + 1];
     Ipv6Address::ConvertFrom(GetOriginatorAddress()).Serialize(buffer);
     start.Write(buffer, GetAddressLength() + 1);
     delete[] buffer;
@@ -1782,7 +1783,7 @@
 PbbMessageIpv6::DeserializeOriginatorAddress(Buffer::Iterator& start) const
 {
     NS_LOG_FUNCTION(this << &start);
-    uint8_t* buffer = new uint8_t[GetAddressLength() + 1];
+    auto buffer = new uint8_t[GetAddressLength() + 1];
     start.Read(buffer, GetAddressLength() + 1);
     Address res = Ipv6Address::Deserialize(buffer);
     delete[] buffer;
@@ -2174,9 +2175,9 @@
     }
     else if (AddressSize() > 0)
     {
-        uint8_t* head = new uint8_t[GetAddressLength()];
+        auto head = new uint8_t[GetAddressLength()];
         uint8_t headlen = 0;
-        uint8_t* tail = new uint8_t[GetAddressLength()];
+        auto tail = new uint8_t[GetAddressLength()];
         uint8_t taillen = 0;
 
         GetHeadTail(head, headlen, tail, taillen);
@@ -2220,7 +2221,7 @@
 
     if (AddressSize() == 1)
     {
-        uint8_t* buf = new uint8_t[GetAddressLength()];
+        auto buf = new uint8_t[GetAddressLength()];
         SerializeAddress(buf, AddressBegin());
         start.Write(buf, GetAddressLength());
 
@@ -2234,8 +2235,8 @@
     }
     else if (AddressSize() > 0)
     {
-        uint8_t* head = new uint8_t[GetAddressLength()];
-        uint8_t* tail = new uint8_t[GetAddressLength()];
+        auto head = new uint8_t[GetAddressLength()];
+        auto tail = new uint8_t[GetAddressLength()];
         uint8_t headlen = 0;
         uint8_t taillen = 0;
 
@@ -2265,9 +2266,8 @@
 
         if (headlen + taillen < GetAddressLength())
         {
-            uint8_t* mid = new uint8_t[GetAddressLength()];
-            for (PbbAddressBlock::ConstAddressIterator iter = AddressBegin(); iter != AddressEnd();
-                 iter++)
+            auto mid = new uint8_t[GetAddressLength()];
+            for (auto iter = AddressBegin(); iter != AddressEnd(); iter++)
             {
                 SerializeAddress(mid, iter);
                 start.Write(mid + headlen, GetAddressLength() - headlen - taillen);
@@ -2278,7 +2278,7 @@
         flags |= GetPrefixFlags();
         bufref.WriteU8(flags);
 
-        for (ConstPrefixIterator iter = PrefixBegin(); iter != PrefixEnd(); iter++)
+        for (auto iter = PrefixBegin(); iter != PrefixEnd(); iter++)
         {
             start.WriteU8(*iter);
         }
@@ -2301,7 +2301,7 @@
     {
         uint8_t headlen = 0;
         uint8_t taillen = 0;
-        uint8_t* addrtmp = new uint8_t[GetAddressLength()];
+        auto addrtmp = new uint8_t[GetAddressLength()];
         memset(addrtmp, 0, GetAddressLength());
 
         if (flags & AHAS_HEAD)
@@ -2363,7 +2363,7 @@
 
     os << prefix << "PbbAddressBlock {" << std::endl;
     os << prefix << "\taddresses = " << std::endl;
-    for (ConstAddressIterator iter = AddressBegin(); iter != AddressEnd(); iter++)
+    for (auto iter = AddressBegin(); iter != AddressEnd(); iter++)
     {
         os << prefix << "\t\t";
         PrintAddress(os, iter);
@@ -2371,7 +2371,7 @@
     }
 
     os << prefix << "\tprefixes = " << std::endl;
-    for (ConstPrefixIterator iter = PrefixBegin(); iter != PrefixEnd(); iter++)
+    for (auto iter = PrefixBegin(); iter != PrefixEnd(); iter++)
     {
         os << prefix << "\t\t" << (int)(*iter) << std::endl;
     }
@@ -2452,15 +2452,14 @@
     taillen = headlen;
 
     /* Temporary automatic buffers to store serialized addresses */
-    uint8_t* buflast = new uint8_t[GetAddressLength()];
-    uint8_t* bufcur = new uint8_t[GetAddressLength()];
+    auto buflast = new uint8_t[GetAddressLength()];
+    auto bufcur = new uint8_t[GetAddressLength()];
     uint8_t* tmp;
 
     SerializeAddress(buflast, AddressBegin());
 
     /* Skip the first item */
-    for (PbbAddressBlock::ConstAddressIterator iter = AddressBegin()++; iter != AddressEnd();
-         iter++)
+    for (auto iter = AddressBegin()++; iter != AddressEnd(); iter++)
     {
         SerializeAddress(bufcur, iter);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/packet-burst.cc ns-3.40/src/network/utils/packet-burst.cc
--- ns-3.39/src/network/utils/packet-burst.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/packet-burst.cc	2023-09-27 13:30:37.858839800 -0700
@@ -50,8 +50,7 @@
 PacketBurst::~PacketBurst()
 {
     NS_LOG_FUNCTION(this);
-    for (std::list<Ptr<Packet>>::const_iterator iter = m_packets.begin(); iter != m_packets.end();
-         ++iter)
+    for (auto iter = m_packets.begin(); iter != m_packets.end(); ++iter)
     {
         (*iter)->Unref();
     }
@@ -70,8 +69,7 @@
     NS_LOG_FUNCTION(this);
     Ptr<PacketBurst> burst = Create<PacketBurst>();
 
-    for (std::list<Ptr<Packet>>::const_iterator iter = m_packets.begin(); iter != m_packets.end();
-         ++iter)
+    for (auto iter = m_packets.begin(); iter != m_packets.end(); ++iter)
     {
         Ptr<Packet> packet = (*iter)->Copy();
         burst->AddPacket(packet);
@@ -108,8 +106,7 @@
 {
     NS_LOG_FUNCTION(this);
     uint32_t size = 0;
-    for (std::list<Ptr<Packet>>::const_iterator iter = m_packets.begin(); iter != m_packets.end();
-         ++iter)
+    for (auto iter = m_packets.begin(); iter != m_packets.end(); ++iter)
     {
         Ptr<Packet> packet = *iter;
         size += packet->GetSize();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/packet-data-calculators.cc ns-3.40/src/network/utils/packet-data-calculators.cc
--- ns-3.39/src/network/utils/packet-data-calculators.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/packet-data-calculators.cc	2023-09-27 13:30:37.858839800 -0700
@@ -19,9 +19,10 @@
 
 #include "packet-data-calculators.h"
 
+#include "mac48-address.h"
+
 #include "ns3/basic-data-calculators.h"
 #include "ns3/log.h"
-#include "ns3/mac48-address.h"
 #include "ns3/packet.h"
 
 using namespace ns3;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/packet-data-calculators.h ns-3.40/src/network/utils/packet-data-calculators.h
--- ns-3.39/src/network/utils/packet-data-calculators.h	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/packet-data-calculators.h	2023-09-27 13:30:37.858839800 -0700
@@ -20,9 +20,10 @@
 #ifndef PACKET_DATA_CALCULATORS_H
 #define PACKET_DATA_CALCULATORS_H
 
+#include "mac48-address.h"
+
 #include "ns3/basic-data-calculators.h"
 #include "ns3/data-calculator.h"
-#include "ns3/mac48-address.h"
 #include "ns3/packet.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/packet-probe.cc ns-3.40/src/network/utils/packet-probe.cc
--- ns-3.39/src/network/utils/packet-probe.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/packet-probe.cc	2023-09-27 13:30:37.858839800 -0700
@@ -20,7 +20,7 @@
  * Modified by: Mitch Watrous (watrous@u.washington.edu)
  */
 
-#include "ns3/packet-probe.h"
+#include "packet-probe.h"
 
 #include "ns3/config.h"
 #include "ns3/log.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/packet-socket.cc ns-3.40/src/network/utils/packet-socket.cc
--- ns-3.39/src/network/utils/packet-socket.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/packet-socket.cc	2023-09-27 13:30:37.858839800 -0700
@@ -659,7 +659,7 @@
 DeviceNameTag::Serialize(TagBuffer i) const
 {
     const char* n = m_deviceName.c_str();
-    uint8_t l = (uint8_t)m_deviceName.size();
+    auto l = (uint8_t)m_deviceName.size();
 
     i.WriteU8(l);
     i.Write((uint8_t*)n, (uint32_t)l);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/packet-socket-client.cc ns-3.40/src/network/utils/packet-socket-client.cc
--- ns-3.39/src/network/utils/packet-socket-client.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/packet-socket-client.cc	2023-09-27 13:30:37.858839800 -0700
@@ -19,12 +19,13 @@
 
 #include "packet-socket-client.h"
 
+#include "packet-socket-address.h"
+#include "packet-socket-factory.h"
+#include "packet-socket.h"
+
 #include "ns3/abort.h"
 #include "ns3/log.h"
 #include "ns3/nstime.h"
-#include "ns3/packet-socket-address.h"
-#include "ns3/packet-socket-factory.h"
-#include "ns3/packet-socket.h"
 #include "ns3/packet.h"
 #include "ns3/simulator.h"
 #include "ns3/socket-factory.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/packet-socket-client.h ns-3.40/src/network/utils/packet-socket-client.h
--- ns-3.39/src/network/utils/packet-socket-client.h	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/packet-socket-client.h	2023-09-27 13:30:37.858839800 -0700
@@ -20,9 +20,10 @@
 #ifndef PACKET_SOCKET_CLIENT_H
 #define PACKET_SOCKET_CLIENT_H
 
+#include "packet-socket-address.h"
+
 #include "ns3/application.h"
 #include "ns3/event-id.h"
-#include "ns3/packet-socket-address.h"
 #include "ns3/ptr.h"
 #include "ns3/traced-callback.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/packet-socket-server.cc ns-3.40/src/network/utils/packet-socket-server.cc
--- ns-3.39/src/network/utils/packet-socket-server.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/packet-socket-server.cc	2023-09-27 13:30:37.858839800 -0700
@@ -19,12 +19,13 @@
 
 #include "packet-socket-server.h"
 
+#include "packet-socket-address.h"
+#include "packet-socket-factory.h"
+#include "packet-socket.h"
+
 #include "ns3/abort.h"
 #include "ns3/log.h"
 #include "ns3/nstime.h"
-#include "ns3/packet-socket-address.h"
-#include "ns3/packet-socket-factory.h"
-#include "ns3/packet-socket.h"
 #include "ns3/packet.h"
 #include "ns3/simulator.h"
 #include "ns3/socket-factory.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/packet-socket-server.h ns-3.40/src/network/utils/packet-socket-server.h
--- ns-3.39/src/network/utils/packet-socket-server.h	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/packet-socket-server.h	2023-09-27 13:30:37.858839800 -0700
@@ -20,9 +20,10 @@
 #ifndef PACKET_SOCKET_SERVER_H
 #define PACKET_SOCKET_SERVER_H
 
+#include "packet-socket-address.h"
+
 #include "ns3/application.h"
 #include "ns3/event-id.h"
-#include "ns3/packet-socket-address.h"
 #include "ns3/ptr.h"
 #include "ns3/traced-callback.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/pcap-file.cc ns-3.40/src/network/utils/pcap-file.cc
--- ns-3.39/src/network/utils/pcap-file.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/pcap-file.cc	2023-09-27 13:30:37.858839800 -0700
@@ -404,7 +404,7 @@
     //
     // And set swap mode if requested or we are on a big-endian system.
     //
-    m_swapMode = swapMode | bigEndian;
+    m_swapMode = swapMode || bigEndian;
 
     WriteFileHeader();
 }
@@ -552,8 +552,8 @@
         return true;
     }
 
-    uint8_t* data1 = new uint8_t[snapLen]();
-    uint8_t* data2 = new uint8_t[snapLen]();
+    auto data1 = new uint8_t[snapLen]();
+    auto data2 = new uint8_t[snapLen]();
     uint32_t tsSec1 = 0;
     uint32_t tsSec2 = 0;
     uint32_t tsUsec1 = 0;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/queue.h ns-3.40/src/network/utils/queue.h
--- ns-3.39/src/network/utils/queue.h	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/queue.h	2023-09-27 13:30:37.858839800 -0700
@@ -22,12 +22,13 @@
 #ifndef QUEUE_H
 #define QUEUE_H
 
+#include "queue-fwd.h"
+#include "queue-item.h"
+#include "queue-size.h"
+
 #include "ns3/log.h"
 #include "ns3/object.h"
 #include "ns3/packet.h"
-#include "ns3/queue-fwd.h"
-#include "ns3/queue-item.h"
-#include "ns3/queue-size.h"
 #include "ns3/traced-callback.h"
 #include "ns3/traced-value.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/simple-channel.cc ns-3.40/src/network/utils/simple-channel.cc
--- ns-3.39/src/network/utils/simple-channel.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/simple-channel.cc	2023-09-27 13:30:37.858839800 -0700
@@ -62,9 +62,7 @@
                     Ptr<SimpleNetDevice> sender)
 {
     NS_LOG_FUNCTION(this << p << protocol << to << from << sender);
-    for (std::vector<Ptr<SimpleNetDevice>>::const_iterator i = m_devices.begin();
-         i != m_devices.end();
-         ++i)
+    for (auto i = m_devices.begin(); i != m_devices.end(); ++i)
     {
         Ptr<SimpleNetDevice> tmp = *i;
         if (tmp == sender)
@@ -133,8 +131,7 @@
 {
     if (m_blackListedDevices.find(to) != m_blackListedDevices.end())
     {
-        std::vector<Ptr<SimpleNetDevice>>::iterator iter;
-        iter = find(m_blackListedDevices[to].begin(), m_blackListedDevices[to].end(), from);
+        auto iter = find(m_blackListedDevices[to].begin(), m_blackListedDevices[to].end(), from);
         if (iter != m_blackListedDevices[to].end())
         {
             m_blackListedDevices[to].erase(iter);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/simple-net-device.cc ns-3.40/src/network/utils/simple-net-device.cc
--- ns-3.39/src/network/utils/simple-net-device.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/simple-net-device.cc	2023-09-27 13:30:37.858839800 -0700
@@ -18,15 +18,15 @@
  */
 #include "simple-net-device.h"
 
+#include "error-model.h"
+#include "queue.h"
 #include "simple-channel.h"
 
 #include "ns3/boolean.h"
-#include "ns3/error-model.h"
 #include "ns3/log.h"
 #include "ns3/node.h"
 #include "ns3/packet.h"
 #include "ns3/pointer.h"
-#include "ns3/queue.h"
 #include "ns3/simulator.h"
 #include "ns3/string.h"
 #include "ns3/tag.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/network/utils/simple-net-device.h ns-3.40/src/network/utils/simple-net-device.h
--- ns-3.39/src/network/utils/simple-net-device.h	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/network/utils/simple-net-device.h	2023-09-27 13:30:37.858839800 -0700
@@ -19,12 +19,12 @@
 #ifndef SIMPLE_NET_DEVICE_H
 #define SIMPLE_NET_DEVICE_H
 
+#include "data-rate.h"
 #include "mac48-address.h"
+#include "queue-fwd.h"
 
-#include "ns3/data-rate.h"
 #include "ns3/event-id.h"
 #include "ns3/net-device.h"
-#include "ns3/queue-fwd.h"
 #include "ns3/traced-callback.h"
 
 #include <stdint.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/nix-vector-routing/examples/nms-p2p-nix.cc ns-3.40/src/nix-vector-routing/examples/nms-p2p-nix.cc
--- ns-3.39/src/nix-vector-routing/examples/nms-p2p-nix.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/nix-vector-routing/examples/nms-p2p-nix.cc	2023-09-27 13:30:37.858839800 -0700
@@ -193,7 +193,7 @@
 
     Array2D<NodeContainer> nodes_net0(nCN, 3);
     Array2D<NodeContainer> nodes_net1(nCN, 6);
-    NodeContainer* nodes_netLR = new NodeContainer[nCN];
+    auto nodes_netLR = new NodeContainer[nCN];
     Array2D<NodeContainer> nodes_net2(nCN, 14);
     Array3D<NodeContainer> nodes_net2LAN(nCN, 7, nLANClients);
     Array2D<NodeContainer> nodes_net3(nCN, 9);
@@ -599,7 +599,7 @@
     if (nCN > 1)
     {
         std::cout << "Forming Ring Topology..." << std::endl;
-        NodeContainer* nodes_ring = new NodeContainer[nCN];
+        auto nodes_ring = new NodeContainer[nCN];
         for (int z = 0; z < nCN - 1; ++z)
         {
             nodes_ring[z].Add(nodes_net0[z][0].Get(0));
@@ -607,7 +607,7 @@
         }
         nodes_ring[nCN - 1].Add(nodes_net0[nCN - 1][0].Get(0));
         nodes_ring[nCN - 1].Add(nodes_net0[0][0].Get(0));
-        NetDeviceContainer* ndc_ring = new NetDeviceContainer[nCN];
+        auto ndc_ring = new NetDeviceContainer[nCN];
         for (int z = 0; z < nCN; ++z)
         {
             ndc_ring[z] = p2p_2gb200ms.Install(nodes_ring[z]);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/nix-vector-routing/model/nix-vector-routing.cc ns-3.40/src/nix-vector-routing/model/nix-vector-routing.cc
--- ns-3.39/src/nix-vector-routing/model/nix-vector-routing.cc	2023-07-05 14:23:48.065428300 -0700
+++ ns-3.40/src/nix-vector-routing/model/nix-vector-routing.cc	2023-09-27 13:30:37.858839800 -0700
@@ -151,8 +151,7 @@
 {
     NS_LOG_FUNCTION_NOARGS();
 
-    NodeList::Iterator listEnd = NodeList::End();
-    for (NodeList::Iterator i = NodeList::Begin(); i != listEnd; i++)
+    for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
     {
         Ptr<Node> node = *i;
         Ptr<NixVectorRouting<T>> rp = node->GetObject<NixVectorRouting>();
@@ -248,7 +247,7 @@
 
     CheckCacheStateAndFlush();
 
-    typename NixMap_t::iterator iter = m_nixCache.find(address);
+    auto iter = m_nixCache.find(address);
     if (iter != m_nixCache.end())
     {
         NS_LOG_LOGIC("Found Nix-vector in cache.");
@@ -269,7 +268,7 @@
 
     CheckCacheStateAndFlush();
 
-    typename IpRouteMap_t::iterator iter = m_ipRouteCache.find(address);
+    auto iter = m_ipRouteCache.find(address);
     if (iter != m_ipRouteCache.end())
     {
         NS_LOG_LOGIC("Found IpRoute in cache.");
@@ -334,9 +333,7 @@
         // the index  to the nix vector.
         // the index corresponds to the neighbor index
         uint32_t offset = 0;
-        for (NetDeviceContainer::Iterator iter = netDeviceContainer.Begin();
-             iter != netDeviceContainer.End();
-             iter++)
+        for (auto iter = netDeviceContainer.Begin(); iter != netDeviceContainer.End(); iter++)
         {
             Ptr<Node> remoteNode = (*iter)->GetNode();
 
@@ -466,7 +463,7 @@
 {
     NS_LOG_FUNCTION_NOARGS();
 
-    for (NodeList::Iterator it = NodeList::Begin(); it != NodeList::End(); ++it)
+    for (auto it = NodeList::Begin(); it != NodeList::End(); ++it)
     {
         Ptr<Node> node = *it;
         Ptr<IpL3Protocol> ip = node->GetObject<IpL3Protocol>();
@@ -528,7 +525,7 @@
 
     Ptr<Node> destNode;
 
-    typename IpAddressToNodeMap::iterator iter = g_ipAddressToNodeMap.find(dest);
+    auto iter = g_ipAddressToNodeMap.find(dest);
 
     if (iter == g_ipAddressToNodeMap.end())
     {
@@ -555,7 +552,7 @@
 
     Ptr<IpInterface> ipInterface;
 
-    typename NetDeviceToIpInterfaceMap::iterator iter = g_netdeviceToIpInterfaceMap.find(netDevice);
+    auto iter = g_netdeviceToIpInterfaceMap.find(netDevice);
 
     if (iter == g_netdeviceToIpInterfaceMap.end())
     {
@@ -1021,8 +1018,7 @@
     {
         *os << std::setw(30) << "Destination";
         *os << "NixVector" << std::endl;
-        for (typename NixMap_t::const_iterator it = m_nixCache.begin(); it != m_nixCache.end();
-             it++)
+        for (auto it = m_nixCache.begin(); it != m_nixCache.end(); it++)
         {
             std::ostringstream dest;
             dest << it->first;
@@ -1045,9 +1041,7 @@
         *os << std::setw(30) << "Gateway";
         *os << std::setw(30) << "Source";
         *os << "OutputDevice" << std::endl;
-        for (typename IpRouteMap_t::const_iterator it = m_ipRouteCache.begin();
-             it != m_ipRouteCache.end();
-             it++)
+        for (auto it = m_ipRouteCache.begin(); it != m_ipRouteCache.end(); it++)
         {
             std::ostringstream dest;
             std::ostringstream gw;
@@ -1193,9 +1187,7 @@
             // and scan through them.  We push them
             // to the greyNode queue, if they aren't
             // already there.
-            for (NetDeviceContainer::Iterator iter = netDeviceContainer.Begin();
-                 iter != netDeviceContainer.End();
-                 iter++)
+            for (auto iter = netDeviceContainer.Begin(); iter != netDeviceContainer.End(); iter++)
             {
                 Ptr<Node> remoteNode = (*iter)->GetNode();
                 Ptr<IpInterface> remoteIpInterface = GetInterfaceByNetDevice(*iter);
@@ -1257,8 +1249,7 @@
                 // and scan through them.  We push them
                 // to the greyNode queue, if they aren't
                 // already there.
-                for (NetDeviceContainer::Iterator iter = netDeviceContainer.Begin();
-                     iter != netDeviceContainer.End();
+                for (auto iter = netDeviceContainer.Begin(); iter != netDeviceContainer.End();
                      iter++)
                 {
                     Ptr<Node> remoteNode = (*iter)->GetNode();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/olsr/examples/olsr-hna.cc ns-3.40/src/olsr/examples/olsr-hna.cc
--- ns-3.39/src/olsr/examples/olsr-hna.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/olsr/examples/olsr-hna.cc	2023-09-27 13:30:37.858839800 -0700
@@ -41,12 +41,12 @@
 // One way is to use olsr::RoutingProtocol::SetRoutingTableAssociation ()
 // to use which you may run:
 //
-// ./ns3 run "olsr-hna --assocMethod1=1"
+// ./ns3 run "olsr-hna --assocMethod=SetRoutingTable"
 //
 // The other way is to use olsr::RoutingProtocol::AddHostNetworkAssociation ()
 // to use which you may run:
 //
-// ./ns3 run "olsr-hna --assocMethod2=1"
+// ./ns3 run "olsr-hna --assocMethod=AddHostNetwork"
 //
 
 #include "ns3/config-store-module.h"
@@ -102,8 +102,8 @@
     uint32_t numPackets = 1;
     double interval = 1.0; // seconds
     bool verbose = false;
-    bool assocMethod1 = false;
-    bool assocMethod2 = false;
+    std::string assocMethod("SetRoutingTable");
+    bool reverse = false;
 
     CommandLine cmd(__FILE__);
 
@@ -113,8 +113,11 @@
     cmd.AddValue("numPackets", "number of packets generated", numPackets);
     cmd.AddValue("interval", "interval (seconds) between packets", interval);
     cmd.AddValue("verbose", "turn on all WifiNetDevice log components", verbose);
-    cmd.AddValue("assocMethod1", "Use SetRoutingTableAssociation () method", assocMethod1);
-    cmd.AddValue("assocMethod2", "Use AddHostNetworkAssociation () method", assocMethod2);
+    cmd.AddValue("assocMethod",
+                 "How to add the host to the HNA table (SetRoutingTable, "
+                 "AddHostNetwork)",
+                 assocMethod);
+    cmd.AddValue("reverse", "Send packets from CSMA to WiFi if set to true", reverse);
 
     cmd.Parse(argc, argv);
     // Convert to time object
@@ -210,34 +213,39 @@
     ipv4.Assign(csmaDevices);
 
     TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
-    Ptr<Socket> recvSink = Socket::CreateSocket(csmaNodes.Get(0), tid);
+    Ptr<Socket> recvSink;
+    if (!reverse)
+    {
+        recvSink = Socket::CreateSocket(csmaNodes.Get(0), tid);
+    }
+    else
+    {
+        recvSink = Socket::CreateSocket(olsrNodes.Get(0), tid);
+    }
     InetSocketAddress local = InetSocketAddress(Ipv4Address::GetAny(), 80);
     recvSink->Bind(local);
     recvSink->SetRecvCallback(MakeCallback(&ReceivePacket));
 
-    Ptr<Socket> source = Socket::CreateSocket(olsrNodes.Get(0), tid);
-    InetSocketAddress remote = InetSocketAddress(Ipv4Address("172.16.1.1"), 80);
-    source->Connect(remote);
+    Ptr<Socket> source;
+    if (!reverse)
+    {
+        source = Socket::CreateSocket(olsrNodes.Get(0), tid);
+        InetSocketAddress remote = InetSocketAddress(Ipv4Address("172.16.1.1"), 80);
+        source->Connect(remote);
+    }
+    else
+    {
+        source = Socket::CreateSocket(csmaNodes.Get(0), tid);
+        InetSocketAddress remote = InetSocketAddress(Ipv4Address("10.1.1.1"), 80);
+        source->Connect(remote);
+    }
 
     // Obtain olsr::RoutingProtocol instance of gateway node
     // (namely, node B) and add the required association
-    Ptr<Ipv4> stack = olsrNodes.Get(1)->GetObject<Ipv4>();
-    Ptr<Ipv4RoutingProtocol> rp_Gw = (stack->GetRoutingProtocol());
-    Ptr<Ipv4ListRouting> lrp_Gw = DynamicCast<Ipv4ListRouting>(rp_Gw);
+    Ptr<olsr::RoutingProtocol> olsrrp_Gw = Ipv4RoutingHelper::GetRouting<olsr::RoutingProtocol>(
+        olsrNodes.Get(1)->GetObject<Ipv4>()->GetRoutingProtocol());
 
-    Ptr<olsr::RoutingProtocol> olsrrp_Gw;
-
-    for (uint32_t i = 0; i < lrp_Gw->GetNRoutingProtocols(); i++)
-    {
-        int16_t priority;
-        Ptr<Ipv4RoutingProtocol> temp = lrp_Gw->GetRoutingProtocol(i, priority);
-        if (DynamicCast<olsr::RoutingProtocol>(temp))
-        {
-            olsrrp_Gw = DynamicCast<olsr::RoutingProtocol>(temp);
-        }
-    }
-
-    if (assocMethod1)
+    if (assocMethod == "SetRoutingTable")
     {
         // Create a special Ipv4StaticRouting instance for RoutingTableAssociation
         // Even the Ipv4StaticRouting instance added to list may be used
@@ -252,16 +260,26 @@
                                       uint32_t(1));
         olsrrp_Gw->SetRoutingTableAssociation(hnaEntries);
     }
-
-    if (assocMethod2)
+    else if (assocMethod == "AddHostNetwork")
     {
         // Specify the required associations directly.
         olsrrp_Gw->AddHostNetworkAssociation(Ipv4Address("172.16.1.0"), Ipv4Mask("255.255.255.0"));
     }
+    else
+    {
+        std::cout << "invalid HnaMethod option (" << assocMethod << ")" << std::endl;
+        exit(0);
+    }
+
+    // Add a default route to the CSMA node (to enable replies)
+    Ptr<Ipv4StaticRouting> staticRoutingProt;
+    staticRoutingProt = Ipv4RoutingHelper::GetRouting<Ipv4StaticRouting>(
+        csmaNodes.Get(0)->GetObject<Ipv4>()->GetRoutingProtocol());
+    staticRoutingProt->AddNetworkRouteTo("10.1.1.0", "255.255.255.0", "172.16.1.2", 1);
 
     // Tracing
-    wifiPhy.EnablePcap("olsr-hna", devices);
-    csma.EnablePcap("olsr-hna", csmaDevices, false);
+    wifiPhy.EnablePcap("olsr-hna-wifi", devices);
+    csma.EnablePcap("olsr-hna-csma", csmaDevices, false);
     AsciiTraceHelper ascii;
     wifiPhy.EnableAsciiAll(ascii.CreateFileStream("olsr-hna-wifi.tr"));
     csma.EnableAsciiAll(ascii.CreateFileStream("olsr-hna-csma.tr"));
@@ -274,6 +292,10 @@
                                    numPackets,
                                    interPacketInterval);
 
+    Ptr<OutputStreamWrapper> routingStream =
+        Create<OutputStreamWrapper>("olsr-hna.routes", std::ios::out);
+    Ipv4RoutingHelper::PrintRoutingTableAllAt(Seconds(15), routingStream);
+
     Simulator::Stop(Seconds(20.0));
     Simulator::Run();
     Simulator::Destroy();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/olsr/helper/olsr-helper.cc ns-3.40/src/olsr/helper/olsr-helper.cc
--- ns-3.39/src/olsr/helper/olsr-helper.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/olsr/helper/olsr-helper.cc	2023-09-27 13:30:37.858839800 -0700
@@ -47,7 +47,7 @@
 void
 OlsrHelper::ExcludeInterface(Ptr<Node> node, uint32_t interface)
 {
-    std::map<Ptr<Node>, std::set<uint32_t>>::iterator it = m_interfaceExclusions.find(node);
+    auto it = m_interfaceExclusions.find(node);
 
     if (it == m_interfaceExclusions.end())
     {
@@ -67,7 +67,7 @@
 {
     Ptr<olsr::RoutingProtocol> agent = m_agentFactory.Create<olsr::RoutingProtocol>();
 
-    std::map<Ptr<Node>, std::set<uint32_t>>::const_iterator it = m_interfaceExclusions.find(node);
+    auto it = m_interfaceExclusions.find(node);
 
     if (it != m_interfaceExclusions.end())
     {
@@ -89,7 +89,7 @@
 {
     int64_t currentStream = stream;
     Ptr<Node> node;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         node = (*i);
         Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/olsr/model/olsr-header.cc ns-3.40/src/olsr/model/olsr-header.cc
--- ns-3.39/src/olsr/model/olsr-header.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/olsr/model/olsr-header.cc	2023-09-27 13:30:37.862839700 -0700
@@ -352,8 +352,7 @@
 {
     Buffer::Iterator i = start;
 
-    for (std::vector<Ipv4Address>::const_iterator iter = this->interfaceAddresses.begin();
-         iter != this->interfaceAddresses.end();
+    for (auto iter = this->interfaceAddresses.begin(); iter != this->interfaceAddresses.end();
          iter++)
     {
         i.WriteHtonU32(iter->Get());
@@ -384,9 +383,7 @@
 MessageHeader::Hello::GetSerializedSize() const
 {
     uint32_t size = 4;
-    for (std::vector<LinkMessage>::const_iterator iter = this->linkMessages.begin();
-         iter != this->linkMessages.end();
-         iter++)
+    for (auto iter = this->linkMessages.begin(); iter != this->linkMessages.end(); iter++)
     {
         const LinkMessage& lm = *iter;
         size += 4;
@@ -432,9 +429,7 @@
     i.WriteU8(this->hTime);
     i.WriteU8(static_cast<uint8_t>(this->willingness));
 
-    for (std::vector<LinkMessage>::const_iterator iter = this->linkMessages.begin();
-         iter != this->linkMessages.end();
-         iter++)
+    for (auto iter = this->linkMessages.begin(); iter != this->linkMessages.end(); iter++)
     {
         const LinkMessage& lm = *iter;
 
@@ -447,8 +442,7 @@
         // - the end of the message).
         i.WriteHtonU16(4 + lm.neighborInterfaceAddresses.size() * IPV4_ADDRESS_SIZE);
 
-        for (std::vector<Ipv4Address>::const_iterator neigh_iter =
-                 lm.neighborInterfaceAddresses.begin();
+        for (auto neigh_iter = lm.neighborInterfaceAddresses.begin();
              neigh_iter != lm.neighborInterfaceAddresses.end();
              neigh_iter++)
         {
@@ -530,9 +524,7 @@
     i.WriteHtonU16(this->ansn);
     i.WriteHtonU16(0); // Reserved
 
-    for (std::vector<Ipv4Address>::const_iterator iter = this->neighborAddresses.begin();
-         iter != this->neighborAddresses.end();
-         iter++)
+    for (auto iter = this->neighborAddresses.begin(); iter != this->neighborAddresses.end(); iter++)
     {
         i.WriteHtonU32(iter->Get());
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/olsr/model/olsr-header.h ns-3.40/src/olsr/model/olsr-header.h
--- ns-3.39/src/olsr/model/olsr-header.h	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/olsr/model/olsr-header.h	2023-09-27 13:30:37.862839700 -0700
@@ -706,9 +706,7 @@
 operator<<(std::ostream& os, const MessageList& messages)
 {
     os << "[";
-    for (std::vector<MessageHeader>::const_iterator messageIter = messages.begin();
-         messageIter != messages.end();
-         messageIter++)
+    for (auto messageIter = messages.begin(); messageIter != messages.end(); messageIter++)
     {
         messageIter->Print(os);
         if (messageIter + 1 != messages.end())
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/olsr/model/olsr-routing-protocol.cc ns-3.40/src/olsr/model/olsr-routing-protocol.cc
--- ns-3.39/src/olsr/model/olsr-routing-protocol.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/olsr/model/olsr-routing-protocol.cc	2023-09-27 13:30:37.862839700 -0700
@@ -306,9 +306,7 @@
         m_recvSocket = nullptr;
     }
 
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::iterator iter = m_sendSockets.begin();
-         iter != m_sendSockets.end();
-         iter++)
+    for (auto iter = m_sendSockets.begin(); iter != m_sendSockets.end(); iter++)
     {
         iter->first->Close();
     }
@@ -337,12 +335,14 @@
     *os << std::setw(16) << "Interface";
     *os << "Distance" << std::endl;
 
-    for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator iter = m_table.begin();
-         iter != m_table.end();
-         iter++)
+    for (auto iter = m_table.begin(); iter != m_table.end(); iter++)
     {
-        *os << std::setw(16) << iter->first;
-        *os << std::setw(16) << iter->second.nextAddr;
+        std::ostringstream dest;
+        std::ostringstream nextHop;
+        dest << iter->first;
+        nextHop << iter->second.nextAddr;
+        *os << std::setw(16) << dest.str();
+        *os << std::setw(16) << nextHop.str();
         *os << std::setw(16);
         if (!Names::FindName(m_ipv4->GetNetDevice(iter->second.interface)).empty())
         {
@@ -364,7 +364,7 @@
     }
     else
     {
-        *os << "HNA Routing Table: empty" << std::endl;
+        *os << "HNA Routing Table: empty" << std::endl << std::endl;
     }
     // Restore the previous ostream state
     (*os).copyfmt(oldState);
@@ -546,8 +546,7 @@
 
     m_rxPacketTrace(olsrPacketHeader, messages);
 
-    for (MessageList::const_iterator messageIter = messages.begin(); messageIter != messages.end();
-         messageIter++)
+    for (auto messageIter = messages.begin(); messageIter != messages.end(); messageIter++)
     {
         const MessageHeader& messageHeader = *messageIter;
         // If ttl is less than or equal to zero, or
@@ -620,9 +619,7 @@
 
             // If the message has been considered for forwarding, it should
             // not be retransmitted again
-            for (std::vector<Ipv4Address>::const_iterator it = duplicated->ifaceList.begin();
-                 it != duplicated->ifaceList.end();
-                 it++)
+            for (auto it = duplicated->ifaceList.begin(); it != duplicated->ifaceList.end(); it++)
             {
                 if (*it == receiverIfaceAddr)
                 {
@@ -662,8 +659,7 @@
 RoutingProtocol::Degree(const NeighborTuple& tuple)
 {
     int degree = 0;
-    for (TwoHopNeighborSet::const_iterator it = m_state.GetTwoHopNeighbors().begin();
-         it != m_state.GetTwoHopNeighbors().end();
+    for (auto it = m_state.GetTwoHopNeighbors().begin(); it != m_state.GetTwoHopNeighbors().end();
          it++)
     {
         const TwoHopNeighborTuple& nb2hop_tuple = *it;
@@ -694,8 +690,7 @@
 {
     // first gather all 2-hop neighbors to be removed
     std::set<Ipv4Address> toRemove;
-    for (TwoHopNeighborSet::iterator twoHopNeigh = N2.begin(); twoHopNeigh != N2.end();
-         twoHopNeigh++)
+    for (auto twoHopNeigh = N2.begin(); twoHopNeigh != N2.end(); twoHopNeigh++)
     {
         if (twoHopNeigh->neighborMainAddr == neighborMainAddr)
         {
@@ -703,7 +698,7 @@
         }
     }
     // Now remove all matching records from N2
-    for (TwoHopNeighborSet::iterator twoHopNeigh = N2.begin(); twoHopNeigh != N2.end();)
+    for (auto twoHopNeigh = N2.begin(); twoHopNeigh != N2.end();)
     {
         if (toRemove.find(twoHopNeigh->twoHopNeighborAddr) != toRemove.end())
         {
@@ -729,8 +724,7 @@
     // N is the subset of neighbors of the node, which are
     // neighbor "of the interface I"
     NeighborSet N;
-    for (NeighborSet::const_iterator neighbor = m_state.GetNeighbors().begin();
-         neighbor != m_state.GetNeighbors().end();
+    for (auto neighbor = m_state.GetNeighbors().begin(); neighbor != m_state.GetNeighbors().end();
          neighbor++)
     {
         if (neighbor->status == NeighborTuple::STATUS_SYM) // I think that we need this check
@@ -746,7 +740,7 @@
     // (iii) all the symmetric neighbors: the nodes for which there exists a symmetric
     //       link to this node on some interface.
     TwoHopNeighborSet N2;
-    for (TwoHopNeighborSet::const_iterator twoHopNeigh = m_state.GetTwoHopNeighbors().begin();
+    for (auto twoHopNeigh = m_state.GetTwoHopNeighbors().begin();
          twoHopNeigh != m_state.GetTwoHopNeighbors().end();
          twoHopNeigh++)
     {
@@ -760,7 +754,7 @@
         //  excluding:
         // (i)   the nodes only reachable by members of N with willingness Willingness::NEVER
         bool ok = false;
-        for (NeighborSet::const_iterator neigh = N.begin(); neigh != N.end(); neigh++)
+        for (auto neigh = N.begin(); neigh != N.end(); neigh++)
         {
             if (neigh->neighborMainAddr == twoHopNeigh->neighborMainAddr)
             {
@@ -776,7 +770,7 @@
         // excluding:
         // (iii) all the symmetric neighbors: the nodes for which there exists a symmetric
         //       link to this node on some interface.
-        for (NeighborSet::const_iterator neigh = N.begin(); neigh != N.end(); neigh++)
+        for (auto neigh = N.begin(); neigh != N.end(); neigh++)
         {
             if (neigh->neighborMainAddr == twoHopNeigh->twoHopNeighborAddr)
             {
@@ -795,9 +789,9 @@
     {
         std::ostringstream os;
         os << "[";
-        for (TwoHopNeighborSet::const_iterator iter = N2.begin(); iter != N2.end(); iter++)
+        for (auto iter = N2.begin(); iter != N2.end(); iter++)
         {
-            TwoHopNeighborSet::const_iterator next = iter;
+            auto next = iter;
             next++;
             os << iter->neighborMainAddr << "->" << iter->twoHopNeighborAddr;
             if (next != N2.end())
@@ -812,7 +806,7 @@
 
     // 1. Start with an MPR set made of all members of N with
     // N_willingness equal to Willingness::ALWAYS
-    for (NeighborSet::const_iterator neighbor = N.begin(); neighbor != N.end(); neighbor++)
+    for (auto neighbor = N.begin(); neighbor != N.end(); neighbor++)
     {
         if (neighbor->willingness == Willingness::ALWAYS)
         {
@@ -829,14 +823,11 @@
     // 3. Add to the MPR set those nodes in N, which are the *only*
     // nodes to provide reachability to a node in N2.
     std::set<Ipv4Address> coveredTwoHopNeighbors;
-    for (TwoHopNeighborSet::const_iterator twoHopNeigh = N2.begin(); twoHopNeigh != N2.end();
-         twoHopNeigh++)
+    for (auto twoHopNeigh = N2.begin(); twoHopNeigh != N2.end(); twoHopNeigh++)
     {
         bool onlyOne = true;
         // try to find another neighbor that can reach twoHopNeigh->twoHopNeighborAddr
-        for (TwoHopNeighborSet::const_iterator otherTwoHopNeigh = N2.begin();
-             otherTwoHopNeigh != N2.end();
-             otherTwoHopNeigh++)
+        for (auto otherTwoHopNeigh = N2.begin(); otherTwoHopNeigh != N2.end(); otherTwoHopNeigh++)
         {
             if (otherTwoHopNeigh->twoHopNeighborAddr == twoHopNeigh->twoHopNeighborAddr &&
                 otherTwoHopNeigh->neighborMainAddr != twoHopNeigh->neighborMainAddr)
@@ -854,8 +845,7 @@
             mprSet.insert(twoHopNeigh->neighborMainAddr);
 
             // take note of all the 2-hop neighbors reachable by the newly elected MPR
-            for (TwoHopNeighborSet::const_iterator otherTwoHopNeigh = N2.begin();
-                 otherTwoHopNeigh != N2.end();
+            for (auto otherTwoHopNeigh = N2.begin(); otherTwoHopNeigh != N2.end();
                  otherTwoHopNeigh++)
             {
                 if (otherTwoHopNeigh->neighborMainAddr == twoHopNeigh->neighborMainAddr)
@@ -866,7 +856,7 @@
         }
     }
     // Remove the nodes from N2 which are now covered by a node in the MPR set.
-    for (TwoHopNeighborSet::iterator twoHopNeigh = N2.begin(); twoHopNeigh != N2.end();)
+    for (auto twoHopNeigh = N2.begin(); twoHopNeigh != N2.end();)
     {
         if (coveredTwoHopNeighbors.find(twoHopNeigh->twoHopNeighborAddr) !=
             coveredTwoHopNeighbors.end())
@@ -892,9 +882,9 @@
         {
             std::ostringstream os;
             os << "[";
-            for (TwoHopNeighborSet::const_iterator iter = N2.begin(); iter != N2.end(); iter++)
+            for (auto iter = N2.begin(); iter != N2.end(); iter++)
             {
-                TwoHopNeighborSet::const_iterator next = iter;
+                auto next = iter;
                 next++;
                 os << iter->neighborMainAddr << "->" << iter->twoHopNeighborAddr;
                 if (next != N2.end())
@@ -913,11 +903,11 @@
         // through this 1-hop neighbor
         std::map<int, std::vector<const NeighborTuple*>> reachability;
         std::set<int> rs;
-        for (NeighborSet::iterator it = N.begin(); it != N.end(); it++)
+        for (auto it = N.begin(); it != N.end(); it++)
         {
             const NeighborTuple& nb_tuple = *it;
             int r = 0;
-            for (TwoHopNeighborSet::iterator it2 = N2.begin(); it2 != N2.end(); it2++)
+            for (auto it2 = N2.begin(); it2 != N2.end(); it2++)
             {
                 const TwoHopNeighborTuple& nb2hop_tuple = *it2;
                 if (nb_tuple.neighborMainAddr == nb2hop_tuple.neighborMainAddr)
@@ -939,16 +929,14 @@
         // by a node in the MPR set.
         const NeighborTuple* max = nullptr;
         int max_r = 0;
-        for (std::set<int>::iterator it = rs.begin(); it != rs.end(); it++)
+        for (auto it = rs.begin(); it != rs.end(); it++)
         {
             int r = *it;
             if (r == 0)
             {
                 continue;
             }
-            for (std::vector<const NeighborTuple*>::iterator it2 = reachability[r].begin();
-                 it2 != reachability[r].end();
-                 it2++)
+            for (auto it2 = reachability[r].begin(); it2 != reachability[r].end(); it2++)
             {
                 const NeighborTuple* nb_tuple = *it2;
                 if (max == nullptr || nb_tuple->willingness > max->willingness)
@@ -987,9 +975,9 @@
     {
         std::ostringstream os;
         os << "[";
-        for (MprSet::const_iterator iter = mprSet.begin(); iter != mprSet.end(); iter++)
+        for (auto iter = mprSet.begin(); iter != mprSet.end(); iter++)
         {
-            MprSet::const_iterator next = iter;
+            auto next = iter;
             next++;
             os << *iter;
             if (next != mprSet.end())
@@ -1032,7 +1020,7 @@
     // 2. The new routing entries are added starting with the
     // symmetric neighbors (h=1) as the destination nodes.
     const NeighborSet& neighborSet = m_state.GetNeighbors();
-    for (NeighborSet::const_iterator it = neighborSet.begin(); it != neighborSet.end(); it++)
+    for (auto it = neighborSet.begin(); it != neighborSet.end(); it++)
     {
         const NeighborTuple& nb_tuple = *it;
         NS_LOG_DEBUG("Looking at neighbor tuple: " << nb_tuple);
@@ -1041,7 +1029,7 @@
             bool nb_main_addr = false;
             const LinkTuple* lt = nullptr;
             const LinkSet& linkSet = m_state.GetLinks();
-            for (LinkSet::const_iterator it2 = linkSet.begin(); it2 != linkSet.end(); it2++)
+            for (auto it2 = linkSet.begin(); it2 != linkSet.end(); it2++)
             {
                 const LinkTuple& link_tuple = *it2;
                 NS_LOG_DEBUG("Looking at link tuple: "
@@ -1097,9 +1085,7 @@
     //  N_neighbor_main_addr correspond to a neighbor node with
     //  willingness different of Willingness::NEVER,
     const TwoHopNeighborSet& twoHopNeighbors = m_state.GetTwoHopNeighbors();
-    for (TwoHopNeighborSet::const_iterator it = twoHopNeighbors.begin();
-         it != twoHopNeighbors.end();
-         it++)
+    for (auto it = twoHopNeighbors.begin(); it != twoHopNeighbors.end(); it++)
     {
         const TwoHopNeighborTuple& nb2hop_tuple = *it;
 
@@ -1122,9 +1108,7 @@
         // neighbor set where N_neighbor_main_addr correspond to a
         // neighbor node with willingness different of Willingness::NEVER...
         bool nb2hopOk = false;
-        for (NeighborSet::const_iterator neighbor = neighborSet.begin();
-             neighbor != neighborSet.end();
-             neighbor++)
+        for (auto neighbor = neighborSet.begin(); neighbor != neighborSet.end(); neighbor++)
         {
             if (neighbor->neighborMainAddr == nb2hop_tuple.neighborMainAddr &&
                 neighbor->willingness != Willingness::NEVER)
@@ -1178,7 +1162,7 @@
         // is equal to h, then a new route entry MUST be recorded in
         // the routing table (if it does not already exist)
         const TopologySet& topology = m_state.GetTopologySet();
-        for (TopologySet::const_iterator it = topology.begin(); it != topology.end(); it++)
+        for (auto it = topology.begin(); it != topology.end(); it++)
         {
             const TopologyTuple& topology_tuple = *it;
             NS_LOG_LOGIC("Looking at topology tuple: " << topology_tuple);
@@ -1228,7 +1212,7 @@
     // AND there is no routing entry such that:
     // R_dest_addr == I_iface_addr
     const IfaceAssocSet& ifaceAssocSet = m_state.GetIfaceAssocSet();
-    for (IfaceAssocSet::const_iterator it = ifaceAssocSet.begin(); it != ifaceAssocSet.end(); it++)
+    for (auto it = ifaceAssocSet.begin(); it != ifaceAssocSet.end(); it++)
     {
         const IfaceAssocTuple& tuple = *it;
         RoutingTableEntry entry1;
@@ -1260,8 +1244,7 @@
         m_hnaRoutingTable->RemoveRoute(0);
     }
 
-    for (AssociationSet::const_iterator it = associationSet.begin(); it != associationSet.end();
-         it++)
+    for (auto it = associationSet.begin(); it != associationSet.end(); it++)
     {
         const AssociationTuple& tuple = *it;
 
@@ -1271,7 +1254,7 @@
         bool goToNextAssociationTuple = false;
         const Associations& localHnaAssociations = m_state.GetAssociations();
         NS_LOG_DEBUG("Nb local associations: " << localHnaAssociations.size());
-        for (Associations::const_iterator assocIterator = localHnaAssociations.begin();
+        for (auto assocIterator = localHnaAssociations.begin();
              assocIterator != localHnaAssociations.end();
              assocIterator++)
         {
@@ -1348,7 +1331,7 @@
         const LinkSet& links = m_state.GetLinks();
         NS_LOG_DEBUG(Simulator::Now().As(Time::S)
                      << " ** BEGIN dump Link Set for OLSR Node " << m_mainAddress);
-        for (LinkSet::const_iterator link = links.begin(); link != links.end(); link++)
+        for (auto link = links.begin(); link != links.end(); link++)
         {
             NS_LOG_DEBUG(*link);
         }
@@ -1357,8 +1340,7 @@
         const NeighborSet& neighbors = m_state.GetNeighbors();
         NS_LOG_DEBUG(Simulator::Now().As(Time::S)
                      << " ** BEGIN dump Neighbor Set for OLSR Node " << m_mainAddress);
-        for (NeighborSet::const_iterator neighbor = neighbors.begin(); neighbor != neighbors.end();
-             neighbor++)
+        for (auto neighbor = neighbors.begin(); neighbor != neighbors.end(); neighbor++)
         {
             NS_LOG_DEBUG(*neighbor);
         }
@@ -1374,9 +1356,7 @@
         const TwoHopNeighborSet& twoHopNeighbors = m_state.GetTwoHopNeighbors();
         NS_LOG_DEBUG(Simulator::Now().As(Time::S)
                      << " ** BEGIN dump TwoHopNeighbor Set for OLSR Node " << m_mainAddress);
-        for (TwoHopNeighborSet::const_iterator tuple = twoHopNeighbors.begin();
-             tuple != twoHopNeighbors.end();
-             tuple++)
+        for (auto tuple = twoHopNeighbors.begin(); tuple != twoHopNeighbors.end(); tuple++)
         {
             NS_LOG_DEBUG(*tuple);
         }
@@ -1422,9 +1402,7 @@
 
     // 4. For each of the advertised neighbor main address received in
     // the TC message:
-    for (std::vector<Ipv4Address>::const_iterator i = tc.neighborAddresses.begin();
-         i != tc.neighborAddresses.end();
-         i++)
+    for (auto i = tc.neighborAddresses.begin(); i != tc.neighborAddresses.end(); i++)
     {
         const Ipv4Address& addr = *i;
         // 4.1. If there exist some tuple in the topology set where:
@@ -1467,7 +1445,7 @@
         const TopologySet& topology = m_state.GetTopologySet();
         NS_LOG_DEBUG(Simulator::Now().As(Time::S)
                      << " ** BEGIN dump TopologySet for OLSR Node " << m_mainAddress);
-        for (TopologySet::const_iterator tuple = topology.begin(); tuple != topology.end(); tuple++)
+        for (auto tuple = topology.begin(); tuple != topology.end(); tuple++)
         {
             NS_LOG_DEBUG(*tuple);
         }
@@ -1496,13 +1474,11 @@
     }
 
     // 2. For each interface address listed in the MID message
-    for (std::vector<Ipv4Address>::const_iterator i = mid.interfaceAddresses.begin();
-         i != mid.interfaceAddresses.end();
-         i++)
+    for (auto i = mid.interfaceAddresses.begin(); i != mid.interfaceAddresses.end(); i++)
     {
         bool updated = false;
         IfaceAssocSet& ifaceAssoc = m_state.GetIfaceAssocSetMutable();
-        for (IfaceAssocSet::iterator tuple = ifaceAssoc.begin(); tuple != ifaceAssoc.end(); tuple++)
+        for (auto tuple = ifaceAssoc.begin(); tuple != ifaceAssoc.end(); tuple++)
         {
             if (tuple->ifaceAddr == *i && tuple->mainAddr == msg.GetOriginatorAddress())
             {
@@ -1531,15 +1507,13 @@
     // TwoHopNeighborTuples, update the neighbor addresses taking into account
     // the new MID information.
     NeighborSet& neighbors = m_state.GetNeighbors();
-    for (NeighborSet::iterator neighbor = neighbors.begin(); neighbor != neighbors.end();
-         neighbor++)
+    for (auto neighbor = neighbors.begin(); neighbor != neighbors.end(); neighbor++)
     {
         neighbor->neighborMainAddr = GetMainAddress(neighbor->neighborMainAddr);
     }
 
     TwoHopNeighborSet& twoHopNeighbors = m_state.GetTwoHopNeighbors();
-    for (TwoHopNeighborSet::iterator twoHopNeighbor = twoHopNeighbors.begin();
-         twoHopNeighbor != twoHopNeighbors.end();
+    for (auto twoHopNeighbor = twoHopNeighbors.begin(); twoHopNeighbor != twoHopNeighbors.end();
          twoHopNeighbor++)
     {
         twoHopNeighbor->neighborMainAddr = GetMainAddress(twoHopNeighbor->neighborMainAddr);
@@ -1565,10 +1539,7 @@
     // 2. Otherwise, for each (network address, netmask) pair in the
     // message:
 
-    for (std::vector<olsr::MessageHeader::Hna::Association>::const_iterator it =
-             hna.associations.begin();
-         it != hna.associations.end();
-         it++)
+    for (auto it = hna.associations.begin(); it != hna.associations.end(); it++)
     {
         AssociationTuple* tuple =
             m_state.FindAssociationTuple(msg.GetOriginatorAddress(), it->address, it->mask);
@@ -1707,9 +1678,7 @@
     m_txPacketTrace(header, containedMessages);
 
     // Send it
-    for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator i = m_sendSockets.begin();
-         i != m_sendSockets.end();
-         i++)
+    for (auto i = m_sendSockets.begin(); i != m_sendSockets.end(); i++)
     {
         Ptr<Packet> pkt = packet->Copy();
         Ipv4Address bcast = i->second.GetLocal().GetSubnetDirectedBroadcast(i->second.GetMask());
@@ -1727,9 +1696,7 @@
 
     MessageList msglist;
 
-    for (std::vector<olsr::MessageHeader>::const_iterator message = m_queuedMessages.begin();
-         message != m_queuedMessages.end();
-         message++)
+    for (auto message = m_queuedMessages.begin(); message != m_queuedMessages.end(); message++)
     {
         Ptr<Packet> p = Create<Packet>();
         p->AddHeader(*message);
@@ -1774,8 +1741,7 @@
     std::vector<olsr::MessageHeader::Hello::LinkMessage>& linkMessages = hello.linkMessages;
 
     const LinkSet& links = m_state.GetLinks();
-    for (LinkSet::const_iterator link_tuple = links.begin(); link_tuple != links.end();
-         link_tuple++)
+    for (auto link_tuple = links.begin(); link_tuple != links.end(); link_tuple++)
     {
         if (!(GetMainAddress(link_tuple->localIfaceAddr) == m_mainAddress &&
               link_tuple->time >= now))
@@ -1809,7 +1775,7 @@
         else
         {
             bool ok = false;
-            for (NeighborSet::const_iterator nb_tuple = m_state.GetNeighbors().begin();
+            for (auto nb_tuple = m_state.GetNeighbors().begin();
                  nb_tuple != m_state.GetNeighbors().end();
                  nb_tuple++)
             {
@@ -1880,7 +1846,7 @@
     olsr::MessageHeader::Tc& tc = msg.GetTc();
     tc.ansn = m_ansn;
 
-    for (MprSelectorSet::const_iterator mprsel_tuple = m_state.GetMprSelectors().begin();
+    for (auto mprsel_tuple = m_state.GetMprSelectors().begin();
          mprsel_tuple != m_state.GetMprSelectors().end();
          mprsel_tuple++)
     {
@@ -1951,9 +1917,7 @@
 
     // Add all local HNA associations to the HNA message
     const Associations& localHnaAssociations = m_state.GetAssociations();
-    for (Associations::const_iterator it = localHnaAssociations.begin();
-         it != localHnaAssociations.end();
-         it++)
+    for (auto it = localHnaAssociations.begin(); it != localHnaAssociations.end(); it++)
     {
         olsr::MessageHeader::Hna::Association assoc = {it->networkAddr, it->netmask};
         associations.push_back(assoc);
@@ -1974,7 +1938,7 @@
     // Check if the (networkAddr, netmask) tuple already exist
     // in the list of local HNA associations
     const Associations& localHnaAssociations = m_state.GetAssociations();
-    for (Associations::const_iterator assocIterator = localHnaAssociations.begin();
+    for (auto assocIterator = localHnaAssociations.begin();
          assocIterator != localHnaAssociations.end();
          assocIterator++)
     {
@@ -2048,7 +2012,7 @@
 bool
 RoutingProtocol::UsesNonOlsrOutgoingInterface(const Ipv4RoutingTableEntry& route)
 {
-    std::set<uint32_t>::const_iterator ci = m_interfaceExclusions.find(route.GetInterface());
+    auto ci = m_interfaceExclusions.find(route.GetInterface());
     // The outgoing interface is a non-OLSR interface if a match is found
     // before reaching the end of the list of excluded interfaces
     return ci != m_interfaceExclusions.end();
@@ -2088,13 +2052,11 @@
     }
 
     link_tuple->asymTime = now + msg.GetVTime();
-    for (std::vector<olsr::MessageHeader::Hello::LinkMessage>::const_iterator linkMessage =
-             hello.linkMessages.begin();
-         linkMessage != hello.linkMessages.end();
+    for (auto linkMessage = hello.linkMessages.begin(); linkMessage != hello.linkMessages.end();
          linkMessage++)
     {
-        LinkType linkType = LinkType(linkMessage->linkCode & 0x03);
-        NeighborType neighborType = NeighborType((linkMessage->linkCode >> 2) & 0x03);
+        auto linkType = LinkType(linkMessage->linkCode & 0x03);
+        auto neighborType = NeighborType((linkMessage->linkCode >> 2) & 0x03);
 
         NS_LOG_DEBUG("Looking at HELLO link messages with Link Type "
                      << linkType << " and Neighbor Type " << neighborType);
@@ -2108,8 +2070,7 @@
             continue;
         }
 
-        for (std::vector<Ipv4Address>::const_iterator neighIfaceAddr =
-                 linkMessage->neighborInterfaceAddresses.begin();
+        for (auto neighIfaceAddr = linkMessage->neighborInterfaceAddresses.begin();
              neighIfaceAddr != linkMessage->neighborInterfaceAddresses.end();
              neighIfaceAddr++)
         {
@@ -2184,8 +2145,7 @@
 
     NS_LOG_DEBUG("Olsr node " << m_mainAddress << ": PopulateTwoHopNeighborSet BEGIN");
 
-    for (LinkSet::const_iterator link_tuple = m_state.GetLinks().begin();
-         link_tuple != m_state.GetLinks().end();
+    for (auto link_tuple = m_state.GetLinks().begin(); link_tuple != m_state.GetLinks().end();
          link_tuple++)
     {
         NS_LOG_LOGIC("Looking at link tuple: " << *link_tuple);
@@ -2207,17 +2167,14 @@
             continue;
         }
 
-        typedef std::vector<olsr::MessageHeader::Hello::LinkMessage> LinkMessageVec;
-        for (LinkMessageVec::const_iterator linkMessage = hello.linkMessages.begin();
-             linkMessage != hello.linkMessages.end();
+        for (auto linkMessage = hello.linkMessages.begin(); linkMessage != hello.linkMessages.end();
              linkMessage++)
         {
-            NeighborType neighborType = NeighborType((linkMessage->linkCode >> 2) & 0x3);
+            auto neighborType = NeighborType((linkMessage->linkCode >> 2) & 0x3);
             NS_LOG_DEBUG(
                 "Looking at Link Message from HELLO message: neighborType=" << neighborType);
 
-            for (std::vector<Ipv4Address>::const_iterator nb2hop_addr_iter =
-                     linkMessage->neighborInterfaceAddresses.begin();
+            for (auto nb2hop_addr_iter = linkMessage->neighborInterfaceAddresses.begin();
                  nb2hop_addr_iter != linkMessage->neighborInterfaceAddresses.end();
                  nb2hop_addr_iter++)
             {
@@ -2292,18 +2249,15 @@
 
     Time now = Simulator::Now();
 
-    typedef std::vector<olsr::MessageHeader::Hello::LinkMessage> LinkMessageVec;
-    for (LinkMessageVec::const_iterator linkMessage = hello.linkMessages.begin();
-         linkMessage != hello.linkMessages.end();
+    for (auto linkMessage = hello.linkMessages.begin(); linkMessage != hello.linkMessages.end();
          linkMessage++)
     {
-        NeighborType neighborType = NeighborType(linkMessage->linkCode >> 2);
+        auto neighborType = NeighborType(linkMessage->linkCode >> 2);
         if (neighborType == NeighborType::MPR_NEIGH)
         {
             NS_LOG_DEBUG("Processing a link message with neighbor type MPR_NEIGH");
 
-            for (std::vector<Ipv4Address>::const_iterator nb_iface_addr =
-                     linkMessage->neighborInterfaceAddresses.begin();
+            for (auto nb_iface_addr = linkMessage->neighborInterfaceAddresses.begin();
                  nb_iface_addr != linkMessage->neighborInterfaceAddresses.end();
                  nb_iface_addr++)
             {
@@ -2466,7 +2420,7 @@
         bool hasSymmetricLink = false;
 
         const LinkSet& linkSet = m_state.GetLinks();
-        for (LinkSet::const_iterator it = linkSet.begin(); it != linkSet.end(); it++)
+        for (auto it = linkSet.begin(); it != linkSet.end(); it++)
         {
             const LinkTuple& link_tuple = *it;
             if (GetMainAddress(link_tuple.neighborIfaceAddr) == nb_tuple->neighborMainAddr &&
@@ -2886,7 +2840,7 @@
 RoutingProtocol::Lookup(const Ipv4Address& dest, RoutingTableEntry& outEntry) const
 {
     // Get the iterator at "dest" position
-    std::map<Ipv4Address, RoutingTableEntry>::const_iterator it = m_table.find(dest);
+    auto it = m_table.find(dest);
     // If there is no route to "dest", return NULL
     if (it == m_table.end())
     {
@@ -2923,7 +2877,7 @@
     RoutingTableEntry entry2;
     bool found = false;
 
-    if (Lookup(header.GetDestination(), entry1) != 0)
+    if (Lookup(header.GetDestination(), entry1))
     {
         bool foundSendEntry = FindSendEntry(entry1, entry2);
         if (!foundSendEntry)
@@ -3098,9 +3052,7 @@
                                       << ": RouteInput for dest=" << header.GetDestination()
                                       << " --> NOT FOUND; ** Dumping routing table...");
 
-            for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator iter = m_table.begin();
-                 iter != m_table.end();
-                 iter++)
+            for (auto iter = m_table.begin(); iter != m_table.end(); iter++)
             {
                 NS_LOG_DEBUG("dest=" << iter->first << " --> next=" << iter->second.nextAddr
                                      << " via interface " << iter->second.interface);
@@ -3184,9 +3136,7 @@
 RoutingProtocol::GetRoutingTableEntries() const
 {
     std::vector<RoutingTableEntry> retval;
-    for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator iter = m_table.begin();
-         iter != m_table.end();
-         iter++)
+    for (auto iter = m_table.begin(); iter != m_table.end(); iter++)
     {
         retval.push_back(iter->second);
     }
@@ -3240,8 +3190,7 @@
 bool
 RoutingProtocol::IsMyOwnAddress(const Ipv4Address& a) const
 {
-    std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j;
-    for (j = m_sendSockets.begin(); j != m_sendSockets.end(); ++j)
+    for (auto j = m_sendSockets.begin(); j != m_sendSockets.end(); ++j)
     {
         Ipv4InterfaceAddress iface = j->second;
         if (a == iface.GetLocal())
@@ -3259,14 +3208,12 @@
     Time now = Simulator::Now();
     NS_LOG_DEBUG("Dumping for node with main address " << m_mainAddress);
     NS_LOG_DEBUG(" Neighbor set");
-    for (NeighborSet::const_iterator iter = m_state.GetNeighbors().begin();
-         iter != m_state.GetNeighbors().end();
-         iter++)
+    for (auto iter = m_state.GetNeighbors().begin(); iter != m_state.GetNeighbors().end(); iter++)
     {
         NS_LOG_DEBUG("  " << *iter);
     }
     NS_LOG_DEBUG(" Two-hop neighbor set");
-    for (TwoHopNeighborSet::const_iterator iter = m_state.GetTwoHopNeighbors().begin();
+    for (auto iter = m_state.GetTwoHopNeighbors().begin();
          iter != m_state.GetTwoHopNeighbors().end();
          iter++)
     {
@@ -3276,9 +3223,7 @@
         }
     }
     NS_LOG_DEBUG(" Routing table");
-    for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator iter = m_table.begin();
-         iter != m_table.end();
-         iter++)
+    for (auto iter = m_table.begin(); iter != m_table.end(); iter++)
     {
         NS_LOG_DEBUG("  dest=" << iter->first << " --> next=" << iter->second.nextAddr
                                << " via interface " << iter->second.interface);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/olsr/model/olsr-state.cc ns-3.40/src/olsr/model/olsr-state.cc
--- ns-3.39/src/olsr/model/olsr-state.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/olsr/model/olsr-state.cc	2023-09-27 13:30:37.862839700 -0700
@@ -37,7 +37,7 @@
 MprSelectorTuple*
 OlsrState::FindMprSelectorTuple(const Ipv4Address& mainAddr)
 {
-    for (MprSelectorSet::iterator it = m_mprSelectorSet.begin(); it != m_mprSelectorSet.end(); it++)
+    for (auto it = m_mprSelectorSet.begin(); it != m_mprSelectorSet.end(); it++)
     {
         if (it->mainAddr == mainAddr)
         {
@@ -50,7 +50,7 @@
 void
 OlsrState::EraseMprSelectorTuple(const MprSelectorTuple& tuple)
 {
-    for (MprSelectorSet::iterator it = m_mprSelectorSet.begin(); it != m_mprSelectorSet.end(); it++)
+    for (auto it = m_mprSelectorSet.begin(); it != m_mprSelectorSet.end(); it++)
     {
         if (*it == tuple)
         {
@@ -63,7 +63,7 @@
 void
 OlsrState::EraseMprSelectorTuples(const Ipv4Address& mainAddr)
 {
-    for (MprSelectorSet::iterator it = m_mprSelectorSet.begin(); it != m_mprSelectorSet.end();)
+    for (auto it = m_mprSelectorSet.begin(); it != m_mprSelectorSet.end();)
     {
         if (it->mainAddr == mainAddr)
         {
@@ -87,11 +87,9 @@
 {
     std::ostringstream os;
     os << "[";
-    for (MprSelectorSet::const_iterator iter = m_mprSelectorSet.begin();
-         iter != m_mprSelectorSet.end();
-         iter++)
+    for (auto iter = m_mprSelectorSet.begin(); iter != m_mprSelectorSet.end(); iter++)
     {
-        MprSelectorSet::const_iterator next = iter;
+        auto next = iter;
         next++;
         os << iter->mainAddr;
         if (next != m_mprSelectorSet.end())
@@ -108,7 +106,7 @@
 NeighborTuple*
 OlsrState::FindNeighborTuple(const Ipv4Address& mainAddr)
 {
-    for (NeighborSet::iterator it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
+    for (auto it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
     {
         if (it->neighborMainAddr == mainAddr)
         {
@@ -121,7 +119,7 @@
 const NeighborTuple*
 OlsrState::FindSymNeighborTuple(const Ipv4Address& mainAddr) const
 {
-    for (NeighborSet::const_iterator it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
+    for (auto it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
     {
         if (it->neighborMainAddr == mainAddr && it->status == NeighborTuple::STATUS_SYM)
         {
@@ -134,7 +132,7 @@
 NeighborTuple*
 OlsrState::FindNeighborTuple(const Ipv4Address& mainAddr, Willingness willingness)
 {
-    for (NeighborSet::iterator it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
+    for (auto it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
     {
         if (it->neighborMainAddr == mainAddr && it->willingness == willingness)
         {
@@ -147,7 +145,7 @@
 void
 OlsrState::EraseNeighborTuple(const NeighborTuple& tuple)
 {
-    for (NeighborSet::iterator it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
+    for (auto it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
     {
         if (*it == tuple)
         {
@@ -160,7 +158,7 @@
 void
 OlsrState::EraseNeighborTuple(const Ipv4Address& mainAddr)
 {
-    for (NeighborSet::iterator it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
+    for (auto it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
     {
         if (it->neighborMainAddr == mainAddr)
         {
@@ -173,7 +171,7 @@
 void
 OlsrState::InsertNeighborTuple(const NeighborTuple& tuple)
 {
-    for (NeighborSet::iterator it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
+    for (auto it = m_neighborSet.begin(); it != m_neighborSet.end(); it++)
     {
         if (it->neighborMainAddr == tuple.neighborMainAddr)
         {
@@ -191,9 +189,7 @@
 OlsrState::FindTwoHopNeighborTuple(const Ipv4Address& neighborMainAddr,
                                    const Ipv4Address& twoHopNeighborAddr)
 {
-    for (TwoHopNeighborSet::iterator it = m_twoHopNeighborSet.begin();
-         it != m_twoHopNeighborSet.end();
-         it++)
+    for (auto it = m_twoHopNeighborSet.begin(); it != m_twoHopNeighborSet.end(); it++)
     {
         if (it->neighborMainAddr == neighborMainAddr &&
             it->twoHopNeighborAddr == twoHopNeighborAddr)
@@ -207,9 +203,7 @@
 void
 OlsrState::EraseTwoHopNeighborTuple(const TwoHopNeighborTuple& tuple)
 {
-    for (TwoHopNeighborSet::iterator it = m_twoHopNeighborSet.begin();
-         it != m_twoHopNeighborSet.end();
-         it++)
+    for (auto it = m_twoHopNeighborSet.begin(); it != m_twoHopNeighborSet.end(); it++)
     {
         if (*it == tuple)
         {
@@ -223,8 +217,7 @@
 OlsrState::EraseTwoHopNeighborTuples(const Ipv4Address& neighborMainAddr,
                                      const Ipv4Address& twoHopNeighborAddr)
 {
-    for (TwoHopNeighborSet::iterator it = m_twoHopNeighborSet.begin();
-         it != m_twoHopNeighborSet.end();)
+    for (auto it = m_twoHopNeighborSet.begin(); it != m_twoHopNeighborSet.end();)
     {
         if (it->neighborMainAddr == neighborMainAddr &&
             it->twoHopNeighborAddr == twoHopNeighborAddr)
@@ -241,8 +234,7 @@
 void
 OlsrState::EraseTwoHopNeighborTuples(const Ipv4Address& neighborMainAddr)
 {
-    for (TwoHopNeighborSet::iterator it = m_twoHopNeighborSet.begin();
-         it != m_twoHopNeighborSet.end();)
+    for (auto it = m_twoHopNeighborSet.begin(); it != m_twoHopNeighborSet.end();)
     {
         if (it->neighborMainAddr == neighborMainAddr)
         {
@@ -266,7 +258,7 @@
 bool
 OlsrState::FindMprAddress(const Ipv4Address& addr)
 {
-    MprSet::iterator it = m_mprSet.find(addr);
+    auto it = m_mprSet.find(addr);
     return (it != m_mprSet.end());
 }
 
@@ -287,7 +279,7 @@
 DuplicateTuple*
 OlsrState::FindDuplicateTuple(const Ipv4Address& addr, uint16_t sequenceNumber)
 {
-    for (DuplicateSet::iterator it = m_duplicateSet.begin(); it != m_duplicateSet.end(); it++)
+    for (auto it = m_duplicateSet.begin(); it != m_duplicateSet.end(); it++)
     {
         if (it->address == addr && it->sequenceNumber == sequenceNumber)
         {
@@ -300,7 +292,7 @@
 void
 OlsrState::EraseDuplicateTuple(const DuplicateTuple& tuple)
 {
-    for (DuplicateSet::iterator it = m_duplicateSet.begin(); it != m_duplicateSet.end(); it++)
+    for (auto it = m_duplicateSet.begin(); it != m_duplicateSet.end(); it++)
     {
         if (*it == tuple)
         {
@@ -321,7 +313,7 @@
 LinkTuple*
 OlsrState::FindLinkTuple(const Ipv4Address& ifaceAddr)
 {
-    for (LinkSet::iterator it = m_linkSet.begin(); it != m_linkSet.end(); it++)
+    for (auto it = m_linkSet.begin(); it != m_linkSet.end(); it++)
     {
         if (it->neighborIfaceAddr == ifaceAddr)
         {
@@ -334,7 +326,7 @@
 LinkTuple*
 OlsrState::FindSymLinkTuple(const Ipv4Address& ifaceAddr, Time now)
 {
-    for (LinkSet::iterator it = m_linkSet.begin(); it != m_linkSet.end(); it++)
+    for (auto it = m_linkSet.begin(); it != m_linkSet.end(); it++)
     {
         if (it->neighborIfaceAddr == ifaceAddr)
         {
@@ -354,7 +346,7 @@
 void
 OlsrState::EraseLinkTuple(const LinkTuple& tuple)
 {
-    for (LinkSet::iterator it = m_linkSet.begin(); it != m_linkSet.end(); it++)
+    for (auto it = m_linkSet.begin(); it != m_linkSet.end(); it++)
     {
         if (*it == tuple)
         {
@@ -376,7 +368,7 @@
 TopologyTuple*
 OlsrState::FindTopologyTuple(const Ipv4Address& destAddr, const Ipv4Address& lastAddr)
 {
-    for (TopologySet::iterator it = m_topologySet.begin(); it != m_topologySet.end(); it++)
+    for (auto it = m_topologySet.begin(); it != m_topologySet.end(); it++)
     {
         if (it->destAddr == destAddr && it->lastAddr == lastAddr)
         {
@@ -389,7 +381,7 @@
 TopologyTuple*
 OlsrState::FindNewerTopologyTuple(const Ipv4Address& lastAddr, uint16_t ansn)
 {
-    for (TopologySet::iterator it = m_topologySet.begin(); it != m_topologySet.end(); it++)
+    for (auto it = m_topologySet.begin(); it != m_topologySet.end(); it++)
     {
         if (it->lastAddr == lastAddr && it->sequenceNumber > ansn)
         {
@@ -402,7 +394,7 @@
 void
 OlsrState::EraseTopologyTuple(const TopologyTuple& tuple)
 {
-    for (TopologySet::iterator it = m_topologySet.begin(); it != m_topologySet.end(); it++)
+    for (auto it = m_topologySet.begin(); it != m_topologySet.end(); it++)
     {
         if (*it == tuple)
         {
@@ -415,7 +407,7 @@
 void
 OlsrState::EraseOlderTopologyTuples(const Ipv4Address& lastAddr, uint16_t ansn)
 {
-    for (TopologySet::iterator it = m_topologySet.begin(); it != m_topologySet.end();)
+    for (auto it = m_topologySet.begin(); it != m_topologySet.end();)
     {
         if (it->lastAddr == lastAddr && it->sequenceNumber < ansn)
         {
@@ -439,7 +431,7 @@
 IfaceAssocTuple*
 OlsrState::FindIfaceAssocTuple(const Ipv4Address& ifaceAddr)
 {
-    for (IfaceAssocSet::iterator it = m_ifaceAssocSet.begin(); it != m_ifaceAssocSet.end(); it++)
+    for (auto it = m_ifaceAssocSet.begin(); it != m_ifaceAssocSet.end(); it++)
     {
         if (it->ifaceAddr == ifaceAddr)
         {
@@ -452,8 +444,7 @@
 const IfaceAssocTuple*
 OlsrState::FindIfaceAssocTuple(const Ipv4Address& ifaceAddr) const
 {
-    for (IfaceAssocSet::const_iterator it = m_ifaceAssocSet.begin(); it != m_ifaceAssocSet.end();
-         it++)
+    for (auto it = m_ifaceAssocSet.begin(); it != m_ifaceAssocSet.end(); it++)
     {
         if (it->ifaceAddr == ifaceAddr)
         {
@@ -466,7 +457,7 @@
 void
 OlsrState::EraseIfaceAssocTuple(const IfaceAssocTuple& tuple)
 {
-    for (IfaceAssocSet::iterator it = m_ifaceAssocSet.begin(); it != m_ifaceAssocSet.end(); it++)
+    for (auto it = m_ifaceAssocSet.begin(); it != m_ifaceAssocSet.end(); it++)
     {
         if (*it == tuple)
         {
@@ -486,8 +477,7 @@
 OlsrState::FindNeighborInterfaces(const Ipv4Address& neighborMainAddr) const
 {
     std::vector<Ipv4Address> retval;
-    for (IfaceAssocSet::const_iterator it = m_ifaceAssocSet.begin(); it != m_ifaceAssocSet.end();
-         it++)
+    for (auto it = m_ifaceAssocSet.begin(); it != m_ifaceAssocSet.end(); it++)
     {
         if (it->mainAddr == neighborMainAddr)
         {
@@ -504,7 +494,7 @@
                                 const Ipv4Address& networkAddr,
                                 const Ipv4Mask& netmask)
 {
-    for (AssociationSet::iterator it = m_associationSet.begin(); it != m_associationSet.end(); it++)
+    for (auto it = m_associationSet.begin(); it != m_associationSet.end(); it++)
     {
         if (it->gatewayAddr == gatewayAddr and it->networkAddr == networkAddr and
             it->netmask == netmask)
@@ -518,7 +508,7 @@
 void
 OlsrState::EraseAssociationTuple(const AssociationTuple& tuple)
 {
-    for (AssociationSet::iterator it = m_associationSet.begin(); it != m_associationSet.end(); it++)
+    for (auto it = m_associationSet.begin(); it != m_associationSet.end(); it++)
     {
         if (*it == tuple)
         {
@@ -537,7 +527,7 @@
 void
 OlsrState::EraseAssociation(const Association& tuple)
 {
-    for (Associations::iterator it = m_associations.begin(); it != m_associations.end(); it++)
+    for (auto it = m_associations.begin(); it != m_associations.end(); it++)
     {
         if (*it == tuple)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/olsr/test/hello-regression-test.cc ns-3.40/src/olsr/test/hello-regression-test.cc
--- ns-3.39/src/olsr/test/hello-regression-test.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/olsr/test/hello-regression-test.cc	2023-09-27 13:30:37.862839700 -0700
@@ -139,8 +139,7 @@
                               "One Link message on the second and third Hello.");
     }
 
-    std::vector<olsr::MessageHeader::Hello::LinkMessage>::const_iterator iter;
-    for (iter = hello.linkMessages.begin(); iter != hello.linkMessages.end(); iter++)
+    for (auto iter = hello.linkMessages.begin(); iter != hello.linkMessages.end(); iter++)
     {
         if (m_countA == 1)
         {
@@ -193,8 +192,7 @@
                               "One Link message on the second and third Hello.");
     }
 
-    std::vector<olsr::MessageHeader::Hello::LinkMessage>::const_iterator iter;
-    for (iter = hello.linkMessages.begin(); iter != hello.linkMessages.end(); iter++)
+    for (auto iter = hello.linkMessages.begin(); iter != hello.linkMessages.end(); iter++)
     {
         if (m_countA == 1)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/openflow/examples/openflow-switch.cc ns-3.40/src/openflow/examples/openflow-switch.cc
--- ns-3.39/src/openflow/examples/openflow-switch.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/openflow/examples/openflow-switch.cc	2023-09-27 13:30:37.862839700 -0700
@@ -86,7 +86,6 @@
 int
 main(int argc, char* argv[])
 {
-#ifdef NS3_OPENFLOW
     //
     // Allow the user to override any of the defaults and the above Bind() at
     // run-time, via command-line arguments
@@ -223,9 +222,6 @@
     Simulator::Run();
     Simulator::Destroy();
     NS_LOG_INFO("Done.");
-#else
-    NS_LOG_INFO("NS-3 OpenFlow is not enabled. Cannot run simulation.");
-#endif // NS3_OPENFLOW
 
     return 0;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/openflow/helper/openflow-switch-helper.cc ns-3.40/src/openflow/helper/openflow-switch-helper.cc
--- ns-3.39/src/openflow/helper/openflow-switch-helper.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/openflow/helper/openflow-switch-helper.cc	2023-09-27 13:30:37.862839700 -0700
@@ -16,7 +16,6 @@
  *
  * Author: Blake Hurd  <naimorai@gmail.com>
  */
-#ifdef NS3_OPENFLOW
 
 #include "openflow-switch-helper.h"
 
@@ -96,5 +95,3 @@
 }
 
 } // namespace ns3
-
-#endif // NS3_OPENFLOW
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/openflow/model/openflow-interface.cc ns-3.40/src/openflow/model/openflow-interface.cc
--- ns-3.39/src/openflow/model/openflow-interface.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/openflow/model/openflow-interface.cc	2023-09-27 13:30:37.862839700 -0700
@@ -14,7 +14,6 @@
  *
  * Author: Blake Hurd  <naimorai@gmail.com>
  */
-#ifdef NS3_OPENFLOW
 
 #include "openflow-interface.h"
 
@@ -159,7 +158,7 @@
 Stats::FlowStatsInit(const void* body, int body_len, void** state)
 {
     const ofp_flow_stats_request* fsr = (ofp_flow_stats_request*)body;
-    FlowStatsState* s = (FlowStatsState*)xmalloc(sizeof *s);
+    auto s = (FlowStatsState*)xmalloc(sizeof(FlowStatsState));
 
     s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id;
     memset(&s->position, 0, sizeof s->position);
@@ -171,7 +170,7 @@
 int
 Stats_FlowDumpCallback(sw_flow* flow, void* state)
 {
-    Stats::FlowStatsState* s = (Stats::FlowStatsState*)state;
+    auto s = (Stats::FlowStatsState*)state;
 
     // Fill Flow Stats
     ofp_flow_stats* ofs;
@@ -326,7 +325,7 @@
 int
 Stats::PortStatsInit(const void* body, int body_len, void** state)
 {
-    PortStatsState* s = (PortStatsState*)xmalloc(sizeof *s);
+    auto s = (PortStatsState*)xmalloc(sizeof(PortStatsState));
 
     // the body contains a list of port numbers
     s->ports = (uint32_t*)xmalloc(body_len);
@@ -879,7 +878,7 @@
         dst_addr.CopyFrom(key.flow.dl_dst);
         if (!dst_addr.IsBroadcast())
         {
-            LearnState_t::iterator st = m_learnState.find(dst_addr);
+            auto st = m_learnState.find(dst_addr);
             if (st != m_learnState.end())
             {
                 out_port = st->second.port;
@@ -916,7 +915,7 @@
         // We can learn a specific port for the source address for future use.
         Mac48Address src_addr;
         src_addr.CopyFrom(key.flow.dl_src);
-        LearnState_t::iterator st = m_learnState.find(src_addr);
+        auto st = m_learnState.find(src_addr);
         if (st == m_learnState.end()) // We haven't learned our source MAC yet.
         {
             LearnedState ls;
@@ -964,7 +963,7 @@
     int prev_port;
     size_t max_len = 0;                   // Initialize to make compiler happy
     uint16_t in_port = key->flow.in_port; // ntohs(key->flow.in_port);
-    uint8_t* p = (uint8_t*)actions;
+    auto p = (uint8_t*)actions;
 
     prev_port = -1;
 
@@ -1023,7 +1022,7 @@
 uint16_t
 ValidateActions(const sw_flow_key* key, const ofp_action_header* actions, size_t actions_len)
 {
-    uint8_t* p = (uint8_t*)actions;
+    auto p = (uint8_t*)actions;
     int err;
 
     while (actions_len >= sizeof(ofp_action_header))
@@ -1089,7 +1088,7 @@
     int prev_port;
     size_t max_len = 0; // Initialize to make compiler happy
     uint16_t in_port = ntohs(key->flow.in_port);
-    uint8_t* p = (uint8_t*)actions;
+    auto p = (uint8_t*)actions;
     uint16_t type;
     ofp_action_output* oa;
 
@@ -1131,7 +1130,7 @@
 uint16_t
 ValidateVPortActions(const ofp_action_header* actions, size_t actions_len)
 {
-    uint8_t* p = (uint8_t*)actions;
+    auto p = (uint8_t*)actions;
     int err;
 
     while (actions_len >= sizeof(ofp_action_header))
@@ -1231,5 +1230,3 @@
 } // namespace ofi
 
 } // namespace ns3
-
-#endif // NS3_OPENFLOW
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/openflow/model/openflow-switch-net-device.cc ns-3.40/src/openflow/model/openflow-switch-net-device.cc
--- ns-3.39/src/openflow/model/openflow-switch-net-device.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/openflow/model/openflow-switch-net-device.cc	2023-09-27 13:30:37.862839700 -0700
@@ -14,7 +14,6 @@
  *
  * Author: Blake Hurd  <naimorai@gmail.com>
  */
-#ifdef NS3_OPENFLOW
 
 #include "openflow-switch-net-device.h"
 
@@ -28,6 +27,19 @@
 
 NS_OBJECT_ENSURE_REGISTERED(OpenFlowSwitchNetDevice);
 
+/**
+ * Generate an ID.
+ *
+ * \return Generated ID.
+ */
+static uint64_t
+GenerateId()
+{
+    uint8_t ea[ETH_ADDR_LEN];
+    eth_addr_random(ea);
+    return eth_addr_to_uint64(ea);
+}
+
 const char*
 OpenFlowSwitchNetDevice::GetManufacturerDescription()
 {
@@ -52,14 +64,6 @@
     return "N/A";
 }
 
-static uint64_t
-GenerateId()
-{
-    uint8_t ea[ETH_ADDR_LEN];
-    eth_addr_random(ea);
-    return eth_addr_to_uint64(ea);
-}
-
 TypeId
 OpenFlowSwitchNetDevice::GetTypeId()
 {
@@ -133,7 +137,7 @@
 {
     NS_LOG_FUNCTION_NOARGS();
 
-    for (Ports_t::iterator b = m_ports.begin(), e = m_ports.end(); b != e; b++)
+    for (auto b = m_ports.begin(), e = m_ports.end(); b != e; b++)
     {
         SendPortStatus(*b, OFPPR_DELETE);
         b->netdev = nullptr;
@@ -1162,6 +1166,49 @@
 }
 
 int
+OpenFlowSwitchNetDevice::ReceivePortMod(const void* msg)
+{
+    ofp_port_mod* opm = (ofp_port_mod*)msg;
+
+    int port = opm->port_no; // ntohs(opm->port_no);
+    if (port < DP_MAX_PORTS)
+    {
+        ofi::Port& p = m_ports[port];
+
+        // Make sure the port id hasn't changed since this was sent
+        Mac48Address hw_addr = Mac48Address();
+        hw_addr.CopyFrom(opm->hw_addr);
+        if (p.netdev->GetAddress() != hw_addr)
+        {
+            return 0;
+        }
+
+        if (opm->mask)
+        {
+            uint32_t config_mask = ntohl(opm->mask);
+            p.config &= ~config_mask;
+            p.config |= ntohl(opm->config) & config_mask;
+        }
+
+        if (opm->mask & htonl(OFPPC_PORT_DOWN))
+        {
+            if ((opm->config & htonl(OFPPC_PORT_DOWN)) && (p.config & OFPPC_PORT_DOWN) == 0)
+            {
+                p.config |= OFPPC_PORT_DOWN;
+                /// \todo Possibly disable the Port's Net Device via the appropriate interface.
+            }
+            else if ((opm->config & htonl(OFPPC_PORT_DOWN)) == 0 && (p.config & OFPPC_PORT_DOWN))
+            {
+                p.config &= ~OFPPC_PORT_DOWN;
+                /// \todo Possibly enable the Port's Net Device via the appropriate interface.
+            }
+        }
+    }
+
+    return 0;
+}
+
+int
 OpenFlowSwitchNetDevice::ReceiveFeaturesRequest(const void* msg)
 {
     SendFeaturesReply();
@@ -1248,49 +1295,6 @@
     return 0;
 }
 
-int
-OpenFlowSwitchNetDevice::ReceivePortMod(const void* msg)
-{
-    ofp_port_mod* opm = (ofp_port_mod*)msg;
-
-    int port = opm->port_no; // ntohs(opm->port_no);
-    if (port < DP_MAX_PORTS)
-    {
-        ofi::Port& p = m_ports[port];
-
-        // Make sure the port id hasn't changed since this was sent
-        Mac48Address hw_addr = Mac48Address();
-        hw_addr.CopyFrom(opm->hw_addr);
-        if (p.netdev->GetAddress() != hw_addr)
-        {
-            return 0;
-        }
-
-        if (opm->mask)
-        {
-            uint32_t config_mask = ntohl(opm->mask);
-            p.config &= ~config_mask;
-            p.config |= ntohl(opm->config) & config_mask;
-        }
-
-        if (opm->mask & htonl(OFPPC_PORT_DOWN))
-        {
-            if ((opm->config & htonl(OFPPC_PORT_DOWN)) && (p.config & OFPPC_PORT_DOWN) == 0)
-            {
-                p.config |= OFPPC_PORT_DOWN;
-                /// \todo Possibly disable the Port's Net Device via the appropriate interface.
-            }
-            else if ((opm->config & htonl(OFPPC_PORT_DOWN)) == 0 && (p.config & OFPPC_PORT_DOWN))
-            {
-                p.config &= ~OFPPC_PORT_DOWN;
-                /// \todo Possibly enable the Port's Net Device via the appropriate interface.
-            }
-        }
-    }
-
-    return 0;
-}
-
 // add or remove a virtual port table entry
 int
 OpenFlowSwitchNetDevice::ReceiveVPortMod(const void* msg)
@@ -1700,5 +1704,3 @@
 }
 
 } // namespace ns3
-
-#endif // NS3_OPENFLOW
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/openflow/model/openflow-switch-net-device.h ns-3.40/src/openflow/model/openflow-switch-net-device.h
--- ns-3.39/src/openflow/model/openflow-switch-net-device.h	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/openflow/model/openflow-switch-net-device.h	2023-09-27 13:30:37.862839700 -0700
@@ -503,12 +503,12 @@
      * \param msg The OpenFlow message received.
      * \return 0 if everything's ok, otherwise an error number.
      */
+    int ReceivePortMod(const void* msg);
     int ReceiveFeaturesRequest(const void* msg);
     int ReceiveGetConfigRequest(const void* msg);
     int ReceiveSetConfig(const void* msg);
     int ReceivePacketOut(const void* msg);
     int ReceiveFlow(const void* msg);
-    int ReceivePortMod(const void* msg);
     int ReceiveStatsRequest(const void* msg);
     int ReceiveEchoRequest(const void* msg);
     int ReceiveEchoReply(const void* msg);
@@ -518,7 +518,7 @@
 
     /// Rx Callback
     NetDevice::ReceiveCallback m_rxCallback;
-    /// Promiscuopus Rx Callback
+    /// Promiscuous Rx Callback
     NetDevice::PromiscReceiveCallback m_promiscRxCallback;
 
     Mac48Address m_address;       ///< Address of this device.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/point-to-point/helper/point-to-point-helper.cc ns-3.40/src/point-to-point/helper/point-to-point-helper.cc
--- ns-3.39/src/point-to-point/helper/point-to-point-helper.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/point-to-point/helper/point-to-point-helper.cc	2023-09-27 13:30:37.862839700 -0700
@@ -82,8 +82,7 @@
     Ptr<PointToPointNetDevice> device = nd->GetObject<PointToPointNetDevice>();
     if (!device)
     {
-        NS_LOG_INFO("PointToPointHelper::EnablePcapInternal(): Device "
-                    << device << " not of type ns3::PointToPointNetDevice");
+        NS_LOG_INFO("Device " << device << " not of type ns3::PointToPointNetDevice");
         return;
     }
 
@@ -117,8 +116,7 @@
     Ptr<PointToPointNetDevice> device = nd->GetObject<PointToPointNetDevice>();
     if (!device)
     {
-        NS_LOG_INFO("PointToPointHelper::EnableAsciiInternal(): Device "
-                    << device << " not of type ns3::PointToPointNetDevice");
+        NS_LOG_INFO("Device " << device << " not of type ns3::PointToPointNetDevice");
         return;
     }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/point-to-point-layout/model/point-to-point-dumbbell.cc ns-3.40/src/point-to-point-layout/model/point-to-point-dumbbell.cc
--- ns-3.39/src/point-to-point-layout/model/point-to-point-dumbbell.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/point-to-point-layout/model/point-to-point-dumbbell.cc	2023-09-27 13:30:37.862839700 -0700
@@ -17,19 +17,19 @@
 
 // Implement an object to create a dumbbell topology.
 
-#include <cmath>
-#include <iostream>
-#include <sstream>
+#include "point-to-point-dumbbell.h"
 
-// ns3 includes
 #include "ns3/constant-position-mobility-model.h"
 #include "ns3/ipv6-address-generator.h"
 #include "ns3/log.h"
 #include "ns3/node-list.h"
-#include "ns3/point-to-point-dumbbell.h"
 #include "ns3/point-to-point-net-device.h"
 #include "ns3/vector.h"
 
+#include <cmath>
+#include <iostream>
+#include <sstream>
+
 namespace ns3
 {
 
@@ -191,7 +191,7 @@
         ndc.Add(m_leftLeafDevices.Get(i));
         ndc.Add(m_leftRouterDevices.Get(i));
         Ipv6InterfaceContainer ifc = addressHelper.Assign(ndc);
-        Ipv6InterfaceContainer::Iterator it = ifc.Begin();
+        auto it = ifc.Begin();
         m_leftLeafInterfaces6.Add((*it).first, (*it).second);
         it++;
         m_leftRouterInterfaces6.Add((*it).first, (*it).second);
@@ -207,7 +207,7 @@
         ndc.Add(m_rightLeafDevices.Get(i));
         ndc.Add(m_rightRouterDevices.Get(i));
         Ipv6InterfaceContainer ifc = addressHelper.Assign(ndc);
-        Ipv6InterfaceContainer::Iterator it = ifc.Begin();
+        auto it = ifc.Begin();
         m_rightLeafInterfaces6.Add((*it).first, (*it).second);
         it++;
         m_rightRouterInterfaces6.Add((*it).first, (*it).second);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/point-to-point-layout/model/point-to-point-grid.cc ns-3.40/src/point-to-point-layout/model/point-to-point-grid.cc
--- ns-3.39/src/point-to-point-layout/model/point-to-point-grid.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/point-to-point-layout/model/point-to-point-grid.cc	2023-09-27 13:30:37.862839700 -0700
@@ -17,7 +17,7 @@
 
 // Implement an object to create a grid topology.
 
-#include "ns3/point-to-point-grid.h"
+#include "point-to-point-grid.h"
 
 #include "ns3/constant-position-mobility-model.h"
 #include "ns3/internet-stack-helper.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/point-to-point-layout/model/point-to-point-star.cc ns-3.40/src/point-to-point-layout/model/point-to-point-star.cc
--- ns-3.39/src/point-to-point-layout/model/point-to-point-star.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/point-to-point-layout/model/point-to-point-star.cc	2023-09-27 13:30:37.862839700 -0700
@@ -15,19 +15,19 @@
 
 // Implement an object to create a star topology.
 
-#include <cmath>
-#include <iostream>
-#include <sstream>
+#include "point-to-point-star.h"
 
-// ns3 includes
 #include "ns3/constant-position-mobility-model.h"
 #include "ns3/ipv6-address-generator.h"
 #include "ns3/log.h"
 #include "ns3/node-list.h"
 #include "ns3/point-to-point-net-device.h"
-#include "ns3/point-to-point-star.h"
 #include "ns3/vector.h"
 
+#include <cmath>
+#include <iostream>
+#include <sstream>
+
 namespace ns3
 {
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/doc/propagation.rst ns-3.40/src/propagation/doc/propagation.rst
--- ns-3.39/src/propagation/doc/propagation.rst	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/propagation/doc/propagation.rst	2023-09-27 13:30:37.862839700 -0700
@@ -946,7 +946,7 @@
 
 The fast fading model described in Sec. 6.2.3 of TR 37.885 is based on the one
 specified in TR 38.901, whose implementation is provided in the ``spectrum`` module
-(see the :ref:`spectrum module documentation <sec-3gpp-fast-fading-model>`).
+(see the :ref:`spectrum module documentation <3gpp-fast-fading-model>`).
 This model is general and includes different parameters which can
 be tuned to simulate multiple propagation environments.
 To better model the channel dynamics in vehicular environments, TR 37.885
@@ -956,7 +956,7 @@
 the attribute "Scenario" of the class :cpp:class:`ThreeGppChannelModel` using the value
 "V2V-Urban" or "V2V-Highway".
 
-Additionally, TR 37.885 specifies a new equation to compute the Doppler component,
+edditionally, TR 37.885 specifies a new equation to compute the Doppler component,
 which accounts for the mobility of both nodes, as well as scattering
 from the environment.
 In particular, the scattering effect is considered by deviating the Doppler
@@ -978,7 +978,7 @@
 computed the SNR experienced during the entire simulation, with a time
 resolution of 10 ms.
 The vehicles are equipped with 2x2 antenna arrays modeled using the
-:ref:`3GPP antenna model <sec-3gpp-antenna-model>`.
+:ref:`3GPP antenna model <3gpp-antenna-model>`.
 The bearing and the downtilt angles are properly configured and the
 optimal beamforming vectors are computed at the beginning of the simulation.
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/examples/main-propagation-loss.cc ns-3.40/src/propagation/examples/main-propagation-loss.cc
--- ns-3.39/src/propagation/examples/main-propagation-loss.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/propagation/examples/main-propagation-loss.cc	2023-09-27 13:30:37.862839700 -0700
@@ -174,7 +174,7 @@
                 Simulator::Run();
             }
 
-            for (rxPowerMapType::const_iterator i = rxPowerMap.begin(); i != rxPowerMap.end(); ++i)
+            for (auto i = rxPowerMap.begin(); i != rxPowerMap.end(); ++i)
             {
                 dataset.Add(distance, i->first, (double)i->second / (double)samples);
             }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/channel-condition-model.h ns-3.40/src/propagation/model/channel-condition-model.h
--- ns-3.39/src/propagation/model/channel-condition-model.h	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/propagation/model/channel-condition-model.h	2023-09-27 13:30:37.862839700 -0700
@@ -572,7 +572,7 @@
         0}; //!< the threshold for determining what is the ratio of channels with O2I
     double m_o2iLowLossThreshold{0}; //!< the threshold for determining what is the ratio of low -
                                      //!< high O2I building penetration losses
-    double m_linkO2iConditionToAntennaHeight{
+    bool m_linkO2iConditionToAntennaHeight{
         false}; //!< the indicator that determines whether the O2I/O2O condition is determined based
                 //!< on the UE height
     Ptr<UniformRandomVariable> m_uniformVarO2i; //!< uniform random variable that is used for the
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/cost231-propagation-loss-model.cc ns-3.40/src/propagation/model/cost231-propagation-loss-model.cc
--- ns-3.39/src/propagation/model/cost231-propagation-loss-model.cc	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/propagation/model/cost231-propagation-loss-model.cc	2023-09-27 13:30:37.862839700 -0700
@@ -20,11 +20,12 @@
 
 #include "cost231-propagation-loss-model.h"
 
+#include "propagation-loss-model.h"
+
 #include "ns3/double.h"
 #include "ns3/log.h"
 #include "ns3/mobility-model.h"
 #include "ns3/pointer.h"
-#include "ns3/propagation-loss-model.h"
 
 #include <cmath>
 
@@ -155,20 +156,19 @@
         return 0.0;
     }
 
-    double frequency_MHz = m_frequency * 1e-6;
-
-    double distance_km = distance * 1e-3;
+    double logFrequencyMhz = std::log10(m_frequency * 1e-6);
+    double logDistanceKm = std::log10(distance * 1e-3);
+    double logBSAntennaHeight = std::log10(m_BSAntennaHeight);
 
-    double C_H = 0.8 + ((1.11 * std::log10(frequency_MHz)) - 0.7) * m_SSAntennaHeight -
-                 (1.56 * std::log10(frequency_MHz));
+    double C_H =
+        0.8 + ((1.11 * logFrequencyMhz) - 0.7) * m_SSAntennaHeight - (1.56 * logFrequencyMhz);
 
     // from the COST231 wiki entry
     // See also http://www.lx.it.pt/cost231/final_report.htm
     // Ch. 4, eq. 4.4.3, pg. 135
 
-    double loss_in_db =
-        46.3 + (33.9 * std::log10(frequency_MHz)) - (13.82 * std::log10(m_BSAntennaHeight)) - C_H +
-        ((44.9 - 6.55 * std::log10(m_BSAntennaHeight)) * std::log10(distance_km)) + m_shadowing;
+    double loss_in_db = 46.3 + (33.9 * logFrequencyMhz) - (13.82 * logBSAntennaHeight) - C_H +
+                        ((44.9 - 6.55 * logBSAntennaHeight) * logDistanceKm) + m_shadowing;
 
     NS_LOG_DEBUG("dist =" << distance << ", Path Loss = " << loss_in_db);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/cost231-propagation-loss-model.h ns-3.40/src/propagation/model/cost231-propagation-loss-model.h
--- ns-3.39/src/propagation/model/cost231-propagation-loss-model.h	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/propagation/model/cost231-propagation-loss-model.h	2023-09-27 13:30:37.866839600 -0700
@@ -21,8 +21,9 @@
 #ifndef COST231_PROPAGATION_LOSS_MODEL_H
 #define COST231_PROPAGATION_LOSS_MODEL_H
 
+#include "propagation-loss-model.h"
+
 #include "ns3/nstime.h"
-#include "ns3/propagation-loss-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/itu-r-1411-los-propagation-loss-model.h ns-3.40/src/propagation/model/itu-r-1411-los-propagation-loss-model.h
--- ns-3.39/src/propagation/model/itu-r-1411-los-propagation-loss-model.h	2023-07-05 14:23:48.069428200 -0700
+++ ns-3.40/src/propagation/model/itu-r-1411-los-propagation-loss-model.h	2023-09-27 13:30:37.866839600 -0700
@@ -22,7 +22,7 @@
 #ifndef ITU_R_1411_LOS_PROPAGATION_LOSS_MODEL_H
 #define ITU_R_1411_LOS_PROPAGATION_LOSS_MODEL_H
 
-#include "ns3/propagation-loss-model.h"
+#include "propagation-loss-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/itu-r-1411-nlos-over-rooftop-propagation-loss-model.h ns-3.40/src/propagation/model/itu-r-1411-nlos-over-rooftop-propagation-loss-model.h
--- ns-3.39/src/propagation/model/itu-r-1411-nlos-over-rooftop-propagation-loss-model.h	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/propagation/model/itu-r-1411-nlos-over-rooftop-propagation-loss-model.h	2023-09-27 13:30:37.866839600 -0700
@@ -22,8 +22,8 @@
 #ifndef ITU_R_1411_NLOS_OVER_ROOFTOP_PROPAGATION_LOSS_MODEL_H
 #define ITU_R_1411_NLOS_OVER_ROOFTOP_PROPAGATION_LOSS_MODEL_H
 
-#include <ns3/propagation-environment.h>
-#include <ns3/propagation-loss-model.h>
+#include "propagation-environment.h"
+#include "propagation-loss-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/jakes-propagation-loss-model.h ns-3.40/src/propagation/model/jakes-propagation-loss-model.h
--- ns-3.39/src/propagation/model/jakes-propagation-loss-model.h	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/propagation/model/jakes-propagation-loss-model.h	2023-09-27 13:30:37.866839600 -0700
@@ -19,9 +19,9 @@
 #ifndef JAKES_STATIONARY_LOSS_MODEL_H
 #define JAKES_STATIONARY_LOSS_MODEL_H
 
-#include "ns3/jakes-process.h"
-#include "ns3/propagation-cache.h"
-#include "ns3/propagation-loss-model.h"
+#include "jakes-process.h"
+#include "propagation-cache.h"
+#include "propagation-loss-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/kun-2600-mhz-propagation-loss-model.h ns-3.40/src/propagation/model/kun-2600-mhz-propagation-loss-model.h
--- ns-3.39/src/propagation/model/kun-2600-mhz-propagation-loss-model.h	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/propagation/model/kun-2600-mhz-propagation-loss-model.h	2023-09-27 13:30:37.866839600 -0700
@@ -22,7 +22,7 @@
 #ifndef KUN_2600MHZ_PROPAGATION_LOSS_MODEL_H
 #define KUN_2600MHZ_PROPAGATION_LOSS_MODEL_H
 
-#include <ns3/propagation-loss-model.h>
+#include "propagation-loss-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/okumura-hata-propagation-loss-model.cc ns-3.40/src/propagation/model/okumura-hata-propagation-loss-model.cc
--- ns-3.39/src/propagation/model/okumura-hata-propagation-loss-model.cc	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/propagation/model/okumura-hata-propagation-loss-model.cc	2023-09-27 13:30:37.866839600 -0700
@@ -25,6 +25,7 @@
 #include "ns3/log.h"
 #include "ns3/mobility-model.h"
 
+#include <algorithm>
 #include <cmath>
 
 namespace ns3
@@ -80,19 +81,28 @@
 {
     double loss = 0.0;
     double fmhz = m_frequency / 1e6;
-    double dist = a->GetDistanceFrom(b) / 1000.0;
+    double log_fMhz = std::log10(fmhz);
+    // In the Okumura Hata literature, the distance is expressed in units of kilometers
+    // but other lengths are expressed in meters
+    double distKm = a->GetDistanceFrom(b) / 1000.0;
+
+    Vector aPosition = a->GetPosition();
+    Vector bPosition = b->GetPosition();
+
+    double hb = std::max(aPosition.z, bPosition.z);
+    double hm = std::min(aPosition.z, bPosition.z);
+
+    NS_ASSERT_MSG(hb > 0 && hm > 0, "nodes' height must be greater then 0");
+
+    double log_hb = std::log10(hb);
+    double log_aHeight = 13.82 * log_hb;
+    double log_bHeight = 0.0;
+
     if (m_frequency <= 1.500e9)
     {
         // standard Okumura Hata
         // see eq. (4.4.1) in the COST 231 final report
-        double log_f = std::log10(fmhz);
-        double hb =
-            (a->GetPosition().z > b->GetPosition().z ? a->GetPosition().z : b->GetPosition().z);
-        double hm =
-            (a->GetPosition().z < b->GetPosition().z ? a->GetPosition().z : b->GetPosition().z);
-        NS_ASSERT_MSG(hb > 0 && hm > 0, "nodes' height must be greater then 0");
-        double log_aHeight = 13.82 * std::log10(hb);
-        double log_bHeight = 0.0;
+
         if (m_citySize == LargeCity)
         {
             if (fmhz < 200)
@@ -106,21 +116,21 @@
         }
         else
         {
-            log_bHeight = 0.8 + (1.1 * log_f - 0.7) * hm - 1.56 * log_f;
+            log_bHeight = 0.8 + (1.1 * log_fMhz - 0.7) * hm - 1.56 * log_fMhz;
         }
 
-        NS_LOG_INFO(this << " logf " << 26.16 * log_f << " loga " << log_aHeight << " X "
-                         << (((44.9 - (6.55 * std::log10(hb)))) * std::log10(a->GetDistanceFrom(b)))
-                         << " logb " << log_bHeight);
-        loss = 69.55 + (26.16 * log_f) - log_aHeight +
-               (((44.9 - (6.55 * std::log10(hb)))) * std::log10(dist)) - log_bHeight;
+        NS_LOG_INFO(this << " logf " << 26.16 * log_fMhz << " loga " << log_aHeight << " X "
+                         << ((44.9 - (6.55 * log_hb)) * std::log10(distKm)) << " logb "
+                         << log_bHeight);
+        loss = 69.55 + (26.16 * log_fMhz) - log_aHeight +
+               ((44.9 - (6.55 * log_hb)) * std::log10(distKm)) - log_bHeight;
         if (m_environment == SubUrbanEnvironment)
         {
             loss += -2 * (std::pow(std::log10(fmhz / 28), 2)) - 5.4;
         }
         else if (m_environment == OpenAreasEnvironment)
         {
-            loss += -4.70 * std::pow(std::log10(fmhz), 2) + 18.33 * std::log10(fmhz) - 40.94;
+            loss += -4.70 * std::pow(log_fMhz, 2) + 18.33 * log_fMhz - 40.94;
         }
     }
     else
@@ -128,28 +138,20 @@
         // COST 231 Okumura model
         // see eq. (4.4.3) in the COST 231 final report
 
-        double log_f = std::log10(fmhz);
-        double hb =
-            (a->GetPosition().z > b->GetPosition().z ? a->GetPosition().z : b->GetPosition().z);
-        double hm =
-            (a->GetPosition().z < b->GetPosition().z ? a->GetPosition().z : b->GetPosition().z);
-        NS_ASSERT_MSG(hb > 0 && hm > 0, "nodes' height must be greater then 0");
-        double log_aHeight = 13.82 * std::log10(hb);
-        double log_bHeight = 0.0;
         double C = 0.0;
 
         if (m_citySize == LargeCity)
         {
-            log_bHeight = 3.2 * std::pow((std::log10(11.75 * hm)), 2);
+            log_bHeight = 3.2 * std::pow(std::log10(11.75 * hm), 2);
             C = 3;
         }
         else
         {
-            log_bHeight = (1.1 * log_f - 0.7) * hm - (1.56 * log_f - 0.8);
+            log_bHeight = (1.1 * log_fMhz - 0.7) * hm - (1.56 * log_fMhz - 0.8);
         }
 
-        loss = 46.3 + (33.9 * log_f) - log_aHeight +
-               (((44.9 - (6.55 * std::log10(hb)))) * std::log10(dist)) - log_bHeight + C;
+        loss = 46.3 + (33.9 * log_fMhz) - log_aHeight +
+               ((44.9 - (6.55 * log_hb)) * std::log10(distKm)) - log_bHeight + C;
     }
     return loss;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/okumura-hata-propagation-loss-model.h ns-3.40/src/propagation/model/okumura-hata-propagation-loss-model.h
--- ns-3.39/src/propagation/model/okumura-hata-propagation-loss-model.h	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/propagation/model/okumura-hata-propagation-loss-model.h	2023-09-27 13:30:37.866839600 -0700
@@ -22,8 +22,8 @@
 #ifndef OKUMURA_HATA_PROPAGATION_LOSS_MODEL_H
 #define OKUMURA_HATA_PROPAGATION_LOSS_MODEL_H
 
-#include <ns3/propagation-environment.h>
-#include <ns3/propagation-loss-model.h>
+#include "propagation-environment.h"
+#include "propagation-loss-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/probabilistic-v2v-channel-condition-model.h ns-3.40/src/propagation/model/probabilistic-v2v-channel-condition-model.h
--- ns-3.39/src/propagation/model/probabilistic-v2v-channel-condition-model.h	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/propagation/model/probabilistic-v2v-channel-condition-model.h	2023-09-27 13:30:37.866839600 -0700
@@ -19,7 +19,7 @@
 #ifndef PROBABILISTIC_V2V_CHANNEL_CONDITION_MODEL_H
 #define PROBABILISTIC_V2V_CHANNEL_CONDITION_MODEL_H
 
-#include "ns3/channel-condition-model.h"
+#include "channel-condition-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/propagation-cache.h ns-3.40/src/propagation/model/propagation-cache.h
--- ns-3.39/src/propagation/model/propagation-cache.h	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/propagation/model/propagation-cache.h	2023-09-27 13:30:37.866839600 -0700
@@ -48,7 +48,7 @@
     Ptr<T> GetPathData(Ptr<const MobilityModel> a, Ptr<const MobilityModel> b, uint32_t modelUid)
     {
         PropagationPathIdentifier key = PropagationPathIdentifier(a, b, modelUid);
-        typename PathCache::iterator it = m_pathCache.find(key);
+        auto it = m_pathCache.find(key);
         if (it == m_pathCache.end())
         {
             return nullptr;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/propagation-loss-model.cc ns-3.40/src/propagation/model/propagation-loss-model.cc
--- ns-3.39/src/propagation/model/propagation-loss-model.cc	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/propagation/model/propagation-loss-model.cc	2023-09-27 13:30:37.866839600 -0700
@@ -747,7 +747,7 @@
 
     // switch between Erlang- and Gamma distributions: this is only for
     // speed. (Gamma is equal to Erlang for any positive integer m.)
-    unsigned int int_m = static_cast<unsigned int>(std::floor(m));
+    auto int_m = static_cast<unsigned int>(std::floor(m));
 
     if (int_m == m)
     {
@@ -869,7 +869,7 @@
     NS_ASSERT(ma && mb);
 
     MobilityPair p = std::make_pair(ma, mb);
-    std::map<MobilityPair, double>::iterator i = m_loss.find(p);
+    auto i = m_loss.find(p);
 
     if (i == m_loss.end())
     {
@@ -891,7 +891,7 @@
                                           Ptr<MobilityModel> a,
                                           Ptr<MobilityModel> b) const
 {
-    std::map<MobilityPair, double>::const_iterator i = m_loss.find(std::make_pair(a, b));
+    auto i = m_loss.find(std::make_pair(a, b));
 
     if (i != m_loss.end())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/three-gpp-propagation-loss-model.cc ns-3.40/src/propagation/model/three-gpp-propagation-loss-model.cc
--- ns-3.39/src/propagation/model/three-gpp-propagation-loss-model.cc	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/propagation/model/three-gpp-propagation-loss-model.cc	2023-09-27 13:30:37.866839600 -0700
@@ -18,8 +18,9 @@
 
 #include "three-gpp-propagation-loss-model.h"
 
+#include "channel-condition-model.h"
+
 #include "ns3/boolean.h"
-#include "ns3/channel-condition-model.h"
 #include "ns3/double.h"
 #include "ns3/log.h"
 #include "ns3/mobility-model.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/propagation/model/three-gpp-propagation-loss-model.h ns-3.40/src/propagation/model/three-gpp-propagation-loss-model.h
--- ns-3.39/src/propagation/model/three-gpp-propagation-loss-model.h	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/propagation/model/three-gpp-propagation-loss-model.h	2023-09-27 13:30:37.866839600 -0700
@@ -19,8 +19,8 @@
 #ifndef THREE_GPP_PROPAGATION_LOSS_MODEL_H
 #define THREE_GPP_PROPAGATION_LOSS_MODEL_H
 
-#include "ns3/channel-condition-model.h"
-#include "ns3/propagation-loss-model.h"
+#include "channel-condition-model.h"
+#include "propagation-loss-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/sixlowpan/CMakeLists.txt ns-3.40/src/sixlowpan/CMakeLists.txt
--- ns-3.39/src/sixlowpan/CMakeLists.txt	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/sixlowpan/CMakeLists.txt	2023-09-27 13:30:37.866839600 -0700
@@ -17,8 +17,6 @@
     model/sixlowpan-net-device.h
   LIBRARIES_TO_LINK
     ${libinternet}
-    ${libinternet}
-    ${libcore}
   TEST_SOURCES
     ${example_as_test_suite}
     test/mock-net-device.cc
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/sixlowpan/helper/sixlowpan-helper.cc ns-3.40/src/sixlowpan/helper/sixlowpan-helper.cc
--- ns-3.39/src/sixlowpan/helper/sixlowpan-helper.cc	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/sixlowpan/helper/sixlowpan-helper.cc	2023-09-27 13:30:37.866839600 -0700
@@ -140,7 +140,7 @@
 {
     int64_t currentStream = stream;
     Ptr<NetDevice> netDevice;
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         netDevice = (*i);
         Ptr<SixLowPanNetDevice> dev = DynamicCast<SixLowPanNetDevice>(netDevice);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/sixlowpan/model/sixlowpan-net-device.cc ns-3.40/src/sixlowpan/model/sixlowpan-net-device.cc
--- ns-3.39/src/sixlowpan/model/sixlowpan-net-device.cc	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/sixlowpan/model/sixlowpan-net-device.cc	2023-09-27 13:30:37.866839600 -0700
@@ -192,7 +192,7 @@
         m_timeoutEvent.Cancel();
     }
 
-    for (MapFragmentsI_t iter = m_fragments.begin(); iter != m_fragments.end(); iter++)
+    for (auto iter = m_fragments.begin(); iter != m_fragments.end(); iter++)
     {
         iter->second = nullptr;
     }
@@ -666,9 +666,8 @@
         // fragment
         std::list<Ptr<Packet>> fragmentList;
         DoFragmentation(packet, origPacketSize, origHdrSize, extraHdrSize, fragmentList);
-        std::list<Ptr<Packet>>::iterator it;
         bool success = true;
-        for (it = fragmentList.begin(); it != fragmentList.end(); it++)
+        for (auto it = fragmentList.begin(); it != fragmentList.end(); it++)
         {
             NS_LOG_DEBUG("SixLowPanNetDevice::Send (Fragment) " << **it);
             m_txTrace(*it, this, GetIfIndex());
@@ -2343,7 +2342,7 @@
     uint32_t packetSize = packet->GetSize();
     uint32_t compressedHeaderSize = packetSize - (origPacketSize - origHdrSize);
 
-    uint16_t tag = uint16_t(m_rng->GetValue(0, 65535));
+    auto tag = static_cast<uint16_t>(m_rng->GetValue(0, 65535));
     NS_LOG_LOGIC("random tag " << tag << " - test " << packetSize);
 
     // first fragment
@@ -2474,18 +2473,17 @@
 
     Ptr<Fragments> fragments;
 
-    MapFragments_t::iterator it = m_fragments.find(key);
+    auto it = m_fragments.find(key);
     if (it == m_fragments.end())
     {
         // erase the oldest packet.
         if (m_fragmentReassemblyListSize && (m_fragments.size() >= m_fragmentReassemblyListSize))
         {
-            FragmentsTimeoutsListI_t iter = m_timeoutEventList.begin();
+            auto iter = m_timeoutEventList.begin();
             FragmentKey_t oldestKey = std::get<1>(*iter);
 
             std::list<Ptr<Packet>> storedFragments = m_fragments[oldestKey]->GetFragments();
-            for (std::list<Ptr<Packet>>::iterator fragIter = storedFragments.begin();
-                 fragIter != storedFragments.end();
+            for (auto fragIter = storedFragments.begin(); fragIter != storedFragments.end();
                  fragIter++)
             {
                 m_dropTrace(DROP_FRAGMENT_BUFFER_FULL, *fragIter, this, GetIfIndex());
@@ -2500,7 +2498,7 @@
         m_fragments.insert(std::make_pair(key, fragments));
         uint32_t ifIndex = GetIfIndex();
 
-        FragmentsTimeoutsListI_t iter = SetTimeout(key, ifIndex);
+        auto iter = SetTimeout(key, ifIndex);
         fragments->SetTimeoutIter(iter);
     }
     else
@@ -2592,9 +2590,7 @@
 
     if (ret)
     {
-        for (std::list<std::pair<Ptr<Packet>, uint16_t>>::const_iterator it = m_fragments.begin();
-             it != m_fragments.end();
-             it++)
+        for (auto it = m_fragments.begin(); it != m_fragments.end(); it++)
         {
             // overlapping fragments should not exist
             NS_LOG_LOGIC("Checking overlaps " << lastEndOffset << " - " << it->second);
@@ -2618,7 +2614,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    std::list<std::pair<Ptr<Packet>, uint16_t>>::const_iterator it = m_fragments.begin();
+    auto it = m_fragments.begin();
 
     Ptr<Packet> p = Create<Packet>();
     uint16_t lastEndOffset = 0;
@@ -2655,8 +2651,7 @@
 SixLowPanNetDevice::Fragments::GetFragments() const
 {
     std::list<Ptr<Packet>> fragments;
-    std::list<std::pair<Ptr<Packet>, uint16_t>>::const_iterator iter;
-    for (iter = m_fragments.begin(); iter != m_fragments.end(); iter++)
+    for (auto iter = m_fragments.begin(); iter != m_fragments.end(); iter++)
     {
         fragments.push_back(iter->first);
     }
@@ -2680,11 +2675,9 @@
 {
     NS_LOG_FUNCTION(this);
 
-    MapFragments_t::iterator it = m_fragments.find(key);
+    auto it = m_fragments.find(key);
     std::list<Ptr<Packet>> storedFragments = it->second->GetFragments();
-    for (std::list<Ptr<Packet>>::iterator fragIter = storedFragments.begin();
-         fragIter != storedFragments.end();
-         fragIter++)
+    for (auto fragIter = storedFragments.begin(); fragIter != storedFragments.end(); fragIter++)
     {
         m_dropTrace(DROP_FRAGMENT_TIMEOUT, *fragIter, this, iif);
     }
@@ -2719,7 +2712,7 @@
     }
     m_timeoutEventList.emplace_back(Simulator::Now() + m_fragmentExpirationTimeout, key, iif);
 
-    SixLowPanNetDevice::FragmentsTimeoutsListI_t iter = --m_timeoutEventList.end();
+    auto iter = --m_timeoutEventList.end();
 
     return (iter);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/sixlowpan/test/example-ping-lr-wpan.reflog ns-3.40/src/sixlowpan/test/example-ping-lr-wpan.reflog
--- ns-3.39/src/sixlowpan/test/example-ping-lr-wpan.reflog	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/sixlowpan/test/example-ping-lr-wpan.reflog	1969-12-31 16:00:00.000000000 -0800
@@ -1,16 +0,0 @@
-Device 0: pseudo-Mac-48 02:00:00:00:00:01, IPv6 Address 2001:2::ff:fe00:1
-Device 1: pseudo-Mac-48 02:00:00:00:00:02, IPv6 Address 2001:2::ff:fe00:2
-PING 2001:2::ff:fe00:2 - 16 bytes of data; 64 bytes including ICMP and IPv6 headers.
-24 bytes from (2001:2::ff:fe00:2): icmp_seq=0 ttl=64 time=21.536 ms
-24 bytes from (2001:2::ff:fe00:2): icmp_seq=1 ttl=64 time=9.312 ms
-24 bytes from (2001:2::ff:fe00:2): icmp_seq=2 ttl=64 time=8.992 ms
-24 bytes from (2001:2::ff:fe00:2): icmp_seq=3 ttl=64 time=9.952 ms
-24 bytes from (2001:2::ff:fe00:2): icmp_seq=4 ttl=64 time=6.752 ms
-
---- 2001:2::ff:fe00:2 ping statistics ---
-5 packets transmitted, 5 received, 0% packet loss, time 4006ms
-rtt min/avg/max/mdev = 6/10.6/21/5.941 ms
-NDISC Cache of node 0 at time +9s
-2001:2::ff:fe00:2 dev 2 lladdr 00-06-02:00:00:00:00:02 REACHABLE
-NDISC Cache of node 1 at time +9s
-2001:2::ff:fe00:1 dev 2 lladdr 00-06-02:00:00:00:00:01 REACHABLE
\ No newline at end of file
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/sixlowpan/test/sixlowpan-example-ping-lr-wpan.reflog ns-3.40/src/sixlowpan/test/sixlowpan-example-ping-lr-wpan.reflog
--- ns-3.39/src/sixlowpan/test/sixlowpan-example-ping-lr-wpan.reflog	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/src/sixlowpan/test/sixlowpan-example-ping-lr-wpan.reflog	2023-09-27 13:30:37.866839600 -0700
@@ -0,0 +1,16 @@
+Device 0: pseudo-Mac-48 02:00:00:00:00:01, IPv6 Address 2001:2::ff:fe00:1
+Device 1: pseudo-Mac-48 02:00:00:00:00:02, IPv6 Address 2001:2::ff:fe00:2
+PING 2001:2::ff:fe00:2 - 16 bytes of data; 64 bytes including ICMP and IPv6 headers.
+24 bytes from (2001:2::ff:fe00:2): icmp_seq=0 ttl=64 time=21.536 ms
+24 bytes from (2001:2::ff:fe00:2): icmp_seq=1 ttl=64 time=9.312 ms
+24 bytes from (2001:2::ff:fe00:2): icmp_seq=2 ttl=64 time=8.992 ms
+24 bytes from (2001:2::ff:fe00:2): icmp_seq=3 ttl=64 time=9.952 ms
+24 bytes from (2001:2::ff:fe00:2): icmp_seq=4 ttl=64 time=6.752 ms
+
+--- 2001:2::ff:fe00:2 ping statistics ---
+5 packets transmitted, 5 received, 0% packet loss, time 4006ms
+rtt min/avg/max/mdev = 6/10.6/21/5.941 ms
+NDISC Cache of node 0 at time +9s
+2001:2::ff:fe00:2 dev 2 lladdr 00-06-02:00:00:00:00:02 REACHABLE
+NDISC Cache of node 1 at time +9s
+2001:2::ff:fe00:1 dev 2 lladdr 00-06-02:00:00:00:00:01 REACHABLE
\ No newline at end of file
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/sixlowpan/test/sixlowpan-examples-test-suite.cc ns-3.40/src/sixlowpan/test/sixlowpan-examples-test-suite.cc
--- ns-3.39/src/sixlowpan/test/sixlowpan-examples-test-suite.cc	2023-07-05 14:23:48.073428200 -0700
+++ ns-3.40/src/sixlowpan/test/sixlowpan-examples-test-suite.cc	2023-09-27 13:30:37.866839600 -0700
@@ -1,7 +1,7 @@
 #include "ns3/example-as-test.h"
 
 static ns3::ExampleAsTestSuite g_sixlowpanExample(
-    "example-ping-lr-wpan",
+    "sixlowpan-example-ping-lr-wpan",
     "example-ping-lr-wpan",
     NS_TEST_SOURCEDIR,
     "--disable-pcap --disable-asciitrace --enable-sixlowpan-loginfo");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/doc/spectrum.rst ns-3.40/src/spectrum/doc/spectrum.rst
--- ns-3.39/src/spectrum/doc/spectrum.rst	2023-07-05 14:23:48.077428300 -0700
+++ ns-3.40/src/spectrum/doc/spectrum.rst	2023-09-27 13:30:37.870839600 -0700
@@ -594,6 +594,8 @@
 test suite by verifying that the generated points do not exceed the given
 maximum distance radius from the origin point.
 
+.. _3gpp-fast-fading-model:
+
 3GPP TR 38.901 fast fading model
 ================================
 The framework described by TR 38.901 [TR38901]_ is a 3D statistical Spatial
@@ -1042,6 +1044,3 @@
    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.
-
-.. [TR38901] 3GPP. 2018. TR 38.901. Study on channel for frequencies from 0.5 to
-   100 GHz. V.15.0.0. (2018-06).
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/examples/adhoc-aloha-ideal-phy-matrix-propagation-loss-model.cc ns-3.40/src/spectrum/examples/adhoc-aloha-ideal-phy-matrix-propagation-loss-model.cc
--- ns-3.39/src/spectrum/examples/adhoc-aloha-ideal-phy-matrix-propagation-loss-model.cc	2023-07-05 14:23:48.077428300 -0700
+++ ns-3.40/src/spectrum/examples/adhoc-aloha-ideal-phy-matrix-propagation-loss-model.cc	2023-09-27 13:30:37.874839800 -0700
@@ -110,14 +110,9 @@
 void
 GlobalPathlossDatabase::Print()
 {
-    for (std::map<uint32_t, std::map<uint32_t, double>>::const_iterator txit =
-             m_pathlossMap.begin();
-         txit != m_pathlossMap.end();
-         ++txit)
+    for (auto txit = m_pathlossMap.begin(); txit != m_pathlossMap.end(); ++txit)
     {
-        for (std::map<uint32_t, double>::const_iterator rxit = txit->second.begin();
-             rxit != txit->second.end();
-             ++rxit)
+        for (auto rxit = txit->second.begin(); rxit != txit->second.end(); ++rxit)
         {
             std::cout << txit->first << " --> " << rxit->first << " : " << rxit->second << " dB"
                       << std::endl;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/helper/adhoc-aloha-noack-ideal-phy-helper.cc ns-3.40/src/spectrum/helper/adhoc-aloha-noack-ideal-phy-helper.cc
--- ns-3.39/src/spectrum/helper/adhoc-aloha-noack-ideal-phy-helper.cc	2023-07-05 14:23:48.077428300 -0700
+++ ns-3.40/src/spectrum/helper/adhoc-aloha-noack-ideal-phy-helper.cc	2023-09-27 13:30:37.874839800 -0700
@@ -91,7 +91,7 @@
 AdhocAlohaNoackIdealPhyHelper::Install(NodeContainer c) const
 {
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/helper/spectrum-analyzer-helper.cc ns-3.40/src/spectrum/helper/spectrum-analyzer-helper.cc
--- ns-3.39/src/spectrum/helper/spectrum-analyzer-helper.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/helper/spectrum-analyzer-helper.cc	2023-09-27 13:30:37.874839800 -0700
@@ -51,8 +51,8 @@
     std::ostream* ostream = streamWrapper->GetStream();
     if (ostream->good())
     {
-        Bands::const_iterator fi = avgPowerSpectralDensity->ConstBandsBegin();
-        Values::const_iterator vi = avgPowerSpectralDensity->ConstValuesBegin();
+        auto fi = avgPowerSpectralDensity->ConstBandsBegin();
+        auto vi = avgPowerSpectralDensity->ConstValuesBegin();
         while (fi != avgPowerSpectralDensity->ConstBandsEnd())
         {
             NS_ASSERT(vi != avgPowerSpectralDensity->ConstValuesEnd());
@@ -126,7 +126,7 @@
 {
     NS_LOG_FUNCTION(this);
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/helper/tv-spectrum-transmitter-helper.cc ns-3.40/src/spectrum/helper/tv-spectrum-transmitter-helper.cc
--- ns-3.39/src/spectrum/helper/tv-spectrum-transmitter-helper.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/helper/tv-spectrum-transmitter-helper.cc	2023-09-27 13:30:37.874839800 -0700
@@ -133,7 +133,7 @@
     NS_LOG_FUNCTION(this);
     NetDeviceContainer devCont;
     // iterate over node container to make one transmitter for each given node
-    for (NodeContainer::Iterator i = nodeCont.Begin(); i != nodeCont.End(); ++i)
+    for (auto i = nodeCont.Begin(); i != nodeCont.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<TvSpectrumTransmitter> phy = m_factory.Create()->GetObject<TvSpectrumTransmitter>();
@@ -193,7 +193,7 @@
             japanEndFrequencies[channelNumber] - japanStartFrequencies[channelNumber];
     }
     // iterate over node container to make one transmitter for each given node
-    for (NodeContainer::Iterator i = nodeCont.Begin(); i != nodeCont.End(); ++i)
+    for (auto i = nodeCont.Begin(); i != nodeCont.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<TvSpectrumTransmitter> phy = m_factory.Create()->GetObject<TvSpectrumTransmitter>();
@@ -226,7 +226,7 @@
     DoubleValue startFrequency;
     DoubleValue channelBandwidth;
     // iterate over node container to make one transmitter for each given node
-    for (NodeContainer::Iterator i = nodeCont.Begin(); i != nodeCont.End(); ++i)
+    for (auto i = nodeCont.Begin(); i != nodeCont.End(); ++i)
     {
         Ptr<Node> node = *i;
         Ptr<TvSpectrumTransmitter> phy = m_factory.Create()->GetObject<TvSpectrumTransmitter>();
@@ -265,7 +265,7 @@
     uint16_t currChannelNumber;
     int index = 0;
     // iterate over node container to make one transmitter for each given node
-    for (NodeContainer::Iterator i = nodeCont.Begin(); i != nodeCont.End(); ++i)
+    for (auto i = nodeCont.Begin(); i != nodeCont.End(); ++i)
     {
         currChannelNumber = channelNumber + index;
         if (region == REGION_NORTH_AMERICA)
@@ -461,7 +461,7 @@
         tvNode.Create(1);
         mobility.Install(tvNode);
         // set channel number for this transmitter
-        uint16_t channelNumber = (uint16_t)transmitterIndicesToCreate.front();
+        auto channelNumber = (uint16_t)transmitterIndicesToCreate.front();
         Install(tvNode, region, channelNumber); // install tv transmitter
         transmitterLocations.pop_front();       // remove created transmitter location
         transmitterIndicesToCreate.pop_front(); // remove created transmitter index
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/helper/waveform-generator-helper.cc ns-3.40/src/spectrum/helper/waveform-generator-helper.cc
--- ns-3.39/src/spectrum/helper/waveform-generator-helper.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/helper/waveform-generator-helper.cc	2023-09-27 13:30:37.874839800 -0700
@@ -82,7 +82,7 @@
 WaveformGeneratorHelper::Install(NodeContainer c) const
 {
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Ptr<Node> node = *i;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/constant-spectrum-propagation-loss.cc ns-3.40/src/spectrum/model/constant-spectrum-propagation-loss.cc
--- ns-3.39/src/spectrum/model/constant-spectrum-propagation-loss.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/constant-spectrum-propagation-loss.cc	2023-09-27 13:30:37.874839800 -0700
@@ -17,7 +17,7 @@
  * Author: Manuel Requena <manuel.requena@cttc.es>
  */
 
-#include "ns3/constant-spectrum-propagation-loss.h"
+#include "constant-spectrum-propagation-loss.h"
 
 #include "spectrum-signal-parameters.h"
 
@@ -84,8 +84,8 @@
     NS_LOG_FUNCTION(this);
 
     Ptr<SpectrumValue> rxPsd = Copy<SpectrumValue>(params->psd);
-    Values::iterator vit = rxPsd->ValuesBegin();
-    Bands::const_iterator fit = rxPsd->ConstBandsBegin();
+    auto vit = rxPsd->ValuesBegin();
+    auto fit = rxPsd->ConstBandsBegin();
 
     while (vit != rxPsd->ValuesEnd())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/constant-spectrum-propagation-loss.h ns-3.40/src/spectrum/model/constant-spectrum-propagation-loss.h
--- ns-3.39/src/spectrum/model/constant-spectrum-propagation-loss.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/constant-spectrum-propagation-loss.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,7 +20,7 @@
 #ifndef CONSTANT_SPECTRUM_PROPAGATION_LOSS_H
 #define CONSTANT_SPECTRUM_PROPAGATION_LOSS_H
 
-#include "ns3/spectrum-propagation-loss-model.h"
+#include "spectrum-propagation-loss-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/friis-spectrum-propagation-loss.cc ns-3.40/src/spectrum/model/friis-spectrum-propagation-loss.cc
--- ns-3.39/src/spectrum/model/friis-spectrum-propagation-loss.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/friis-spectrum-propagation-loss.cc	2023-09-27 13:30:37.874839800 -0700
@@ -17,9 +17,10 @@
  * Author: Nicola Baldo <nbaldo@cttc.es>
  */
 
+#include "friis-spectrum-propagation-loss.h"
+
 #include "spectrum-signal-parameters.h"
 
-#include <ns3/friis-spectrum-propagation-loss.h>
 #include <ns3/mobility-model.h>
 
 #include <cmath> // for M_PI
@@ -54,8 +55,8 @@
     Ptr<const MobilityModel> b) const
 {
     Ptr<SpectrumValue> rxPsd = Copy<SpectrumValue>(params->psd);
-    Values::iterator vit = rxPsd->ValuesBegin();
-    Bands::const_iterator fit = rxPsd->ConstBandsBegin();
+    auto vit = rxPsd->ValuesBegin();
+    auto fit = rxPsd->ConstBandsBegin();
 
     NS_ASSERT(a);
     NS_ASSERT(b);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/friis-spectrum-propagation-loss.h ns-3.40/src/spectrum/model/friis-spectrum-propagation-loss.h
--- ns-3.39/src/spectrum/model/friis-spectrum-propagation-loss.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/friis-spectrum-propagation-loss.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,7 +20,7 @@
 #ifndef FRIIS_SPECTRUM_PROPAGATION_LOSS_H
 #define FRIIS_SPECTRUM_PROPAGATION_LOSS_H
 
-#include <ns3/spectrum-propagation-loss-model.h>
+#include "spectrum-propagation-loss-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/half-duplex-ideal-phy.h ns-3.40/src/spectrum/model/half-duplex-ideal-phy.h
--- ns-3.39/src/spectrum/model/half-duplex-ideal-phy.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/half-duplex-ideal-phy.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,6 +20,12 @@
 #ifndef HALF_DUPLEX_IDEAL_PHY_H
 #define HALF_DUPLEX_IDEAL_PHY_H
 
+#include "spectrum-channel.h"
+#include "spectrum-interference.h"
+#include "spectrum-phy.h"
+#include "spectrum-signal-parameters.h"
+#include "spectrum-value.h"
+
 #include <ns3/data-rate.h>
 #include <ns3/event-id.h>
 #include <ns3/generic-phy.h>
@@ -27,11 +33,6 @@
 #include <ns3/net-device.h>
 #include <ns3/nstime.h>
 #include <ns3/packet.h>
-#include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-interference.h>
-#include <ns3/spectrum-phy.h>
-#include <ns3/spectrum-signal-parameters.h>
-#include <ns3/spectrum-value.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/half-duplex-ideal-phy-signal-parameters.h ns-3.40/src/spectrum/model/half-duplex-ideal-phy-signal-parameters.h
--- ns-3.39/src/spectrum/model/half-duplex-ideal-phy-signal-parameters.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/half-duplex-ideal-phy-signal-parameters.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,7 +20,7 @@
 #ifndef HALF_DUPLEX_IDEAL_PHY_SPECTRUM_PARAMETERS_H
 #define HALF_DUPLEX_IDEAL_PHY_SPECTRUM_PARAMETERS_H
 
-#include <ns3/spectrum-signal-parameters.h>
+#include "spectrum-signal-parameters.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/ism-spectrum-value-helper.h ns-3.40/src/spectrum/model/ism-spectrum-value-helper.h
--- ns-3.39/src/spectrum/model/ism-spectrum-value-helper.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/ism-spectrum-value-helper.h	2023-09-27 13:30:37.874839800 -0700
@@ -22,7 +22,7 @@
 #ifndef ISM_SPECTRUM_VALUE_HELPER_H
 #define ISM_SPECTRUM_VALUE_HELPER_H
 
-#include <ns3/spectrum-value.h>
+#include "spectrum-value.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/microwave-oven-spectrum-value-helper.h ns-3.40/src/spectrum/model/microwave-oven-spectrum-value-helper.h
--- ns-3.39/src/spectrum/model/microwave-oven-spectrum-value-helper.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/microwave-oven-spectrum-value-helper.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,7 +20,7 @@
 #ifndef MICROWAVE_OVEN_SPECTRUM_VALUE_HELPER_H
 #define MICROWAVE_OVEN_SPECTRUM_VALUE_HELPER_H
 
-#include <ns3/spectrum-value.h>
+#include "spectrum-value.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/multi-model-spectrum-channel.cc ns-3.40/src/spectrum/model/multi-model-spectrum-channel.cc
--- ns-3.39/src/spectrum/model/multi-model-spectrum-channel.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/multi-model-spectrum-channel.cc	2023-09-27 13:30:37.874839800 -0700
@@ -19,6 +19,11 @@
 
 #include "multi-model-spectrum-channel.h"
 
+#include "spectrum-converter.h"
+#include "spectrum-phy.h"
+#include "spectrum-propagation-loss-model.h"
+#include "spectrum-transmit-filter.h"
+
 #include <ns3/angles.h>
 #include <ns3/antenna-model.h>
 #include <ns3/double.h>
@@ -32,10 +37,6 @@
 #include <ns3/propagation-delay-model.h>
 #include <ns3/propagation-loss-model.h>
 #include <ns3/simulator.h>
-#include <ns3/spectrum-converter.h>
-#include <ns3/spectrum-phy.h>
-#include <ns3/spectrum-propagation-loss-model.h>
-#include <ns3/spectrum-transmit-filter.h>
 
 #include <algorithm>
 #include <iostream>
@@ -57,10 +58,9 @@
 std::ostream&
 operator<<(std::ostream& lhs, TxSpectrumModelInfoMap_t& rhs)
 {
-    for (TxSpectrumModelInfoMap_t::iterator it = rhs.begin(); it != rhs.end(); ++it)
+    for (auto it = rhs.begin(); it != rhs.end(); ++it)
     {
-        SpectrumConverterMap_t::iterator jt;
-        for (jt = it->second.m_spectrumConverterMap.begin();
+        for (auto jt = it->second.m_spectrumConverterMap.begin();
              jt != it->second.m_spectrumConverterMap.end();
              ++jt)
         {
@@ -116,7 +116,7 @@
     // we need to scan for all rxSpectrumModel values since we don't
     // know which spectrum model the phy had when it was previously added
     // (it's probably different than the current one)
-    for (RxSpectrumModelInfoMap_t::iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
+    for (auto rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
          rxInfoIterator != m_rxSpectrumModelInfoMap.end();
          ++rxInfoIterator)
     {
@@ -159,7 +159,7 @@
     if (inserted)
     {
         // create the necessary converters for all the TX spectrum models that we know of
-        for (TxSpectrumModelInfoMap_t::iterator txInfoIterator = m_txSpectrumModelInfoMap.begin();
+        for (auto txInfoIterator = m_txSpectrumModelInfoMap.begin();
              txInfoIterator != m_txSpectrumModelInfoMap.end();
              ++txInfoIterator)
         {
@@ -172,8 +172,7 @@
                 NS_LOG_LOGIC("Creating converter between SpectrumModelUid "
                              << txSpectrumModel->GetUid() << " and " << rxSpectrumModelUid);
                 SpectrumConverter converter(txSpectrumModel, rxSpectrumModel);
-                std::pair<SpectrumConverterMap_t::iterator, bool> ret2;
-                ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
+                auto ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
                     std::make_pair(rxSpectrumModelUid, converter));
                 NS_ASSERT(ret2.second);
             }
@@ -187,22 +186,19 @@
 {
     NS_LOG_FUNCTION(this << txSpectrumModel);
     SpectrumModelUid_t txSpectrumModelUid = txSpectrumModel->GetUid();
-    TxSpectrumModelInfoMap_t::iterator txInfoIterator =
-        m_txSpectrumModelInfoMap.find(txSpectrumModelUid);
+    auto txInfoIterator = m_txSpectrumModelInfoMap.find(txSpectrumModelUid);
 
     if (txInfoIterator == m_txSpectrumModelInfoMap.end())
     {
         // first time we see this TX SpectrumModel
         // we add it to the list
-        std::pair<TxSpectrumModelInfoMap_t::iterator, bool> ret;
-        ret = m_txSpectrumModelInfoMap.insert(
+        auto ret = m_txSpectrumModelInfoMap.insert(
             std::make_pair(txSpectrumModelUid, TxSpectrumModelInfo(txSpectrumModel)));
         NS_ASSERT(ret.second);
         txInfoIterator = ret.first;
 
         // and we create the converters for all the RX SpectrumModels that we know of
-        for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator =
-                 m_rxSpectrumModelInfoMap.begin();
+        for (auto rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
              rxInfoIterator != m_rxSpectrumModelInfoMap.end();
              ++rxInfoIterator)
         {
@@ -216,8 +212,7 @@
                              << txSpectrumModelUid << " and " << rxSpectrumModelUid);
 
                 SpectrumConverter converter(txSpectrumModel, rxSpectrumModel);
-                std::pair<SpectrumConverterMap_t::iterator, bool> ret2;
-                ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
+                auto ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
                     std::make_pair(rxSpectrumModelUid, converter));
                 NS_ASSERT(ret2.second);
             }
@@ -247,7 +242,7 @@
     NS_LOG_LOGIC("txSpectrumModelUid " << txSpectrumModelUid);
 
     //
-    TxSpectrumModelInfoMap_t::const_iterator txInfoIteratorerator =
+    auto txInfoIteratorerator =
         FindAndEventuallyAddTxSpectrumModel(txParams->psd->GetSpectrumModel());
     NS_ASSERT(txInfoIteratorerator != m_txSpectrumModelInfoMap.end());
 
@@ -257,7 +252,7 @@
     NS_LOG_LOGIC("converter map first element: "
                  << txInfoIteratorerator->second.m_spectrumConverterMap.begin()->first);
 
-    for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
+    for (auto rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
          rxInfoIterator != m_rxSpectrumModelInfoMap.end();
          ++rxInfoIterator)
     {
@@ -274,7 +269,7 @@
         {
             NS_LOG_LOGIC("converting txPowerSpectrum SpectrumModelUids "
                          << txSpectrumModelUid << " --> " << rxSpectrumModelUid);
-            SpectrumConverterMap_t::const_iterator rxConverterIterator =
+            auto rxConverterIterator =
                 txInfoIteratorerator->second.m_spectrumConverterMap.find(rxSpectrumModelUid);
             if (rxConverterIterator == txInfoIteratorerator->second.m_spectrumConverterMap.end())
             {
@@ -451,7 +446,7 @@
     // On the other hand, having slow SpectrumModel conversion would be
     // less acceptable.
     std::size_t j = 0;
-    for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
+    for (auto rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
          rxInfoIterator != m_rxSpectrumModelInfoMap.end();
          ++rxInfoIterator)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/multi-model-spectrum-channel.h ns-3.40/src/spectrum/model/multi-model-spectrum-channel.h
--- ns-3.39/src/spectrum/model/multi-model-spectrum-channel.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/multi-model-spectrum-channel.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,11 +20,12 @@
 #ifndef MULTI_MODEL_SPECTRUM_CHANNEL_H
 #define MULTI_MODEL_SPECTRUM_CHANNEL_H
 
+#include "spectrum-channel.h"
+#include "spectrum-converter.h"
+#include "spectrum-propagation-loss-model.h"
+#include "spectrum-value.h"
+
 #include <ns3/propagation-delay-model.h>
-#include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-converter.h>
-#include <ns3/spectrum-propagation-loss-model.h>
-#include <ns3/spectrum-value.h>
 
 #include <map>
 #include <set>
@@ -127,7 +128,7 @@
      * This method checks if m_rxSpectrumModelInfoMap contains an entry
      * for the given TX SpectrumModel. If such entry exists, it returns
      * an iterator pointing to it. If not, it creates a new entry in
-     * m_txSpectrumMpodelInfoMap, and returns an iterator to it.
+     * m_txSpectrumModelInfoMap, and returns an iterator to it.
      *
      * \param txSpectrumModel The TX SpectrumModel  being considered
      *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/phased-array-spectrum-propagation-loss-model.cc ns-3.40/src/spectrum/model/phased-array-spectrum-propagation-loss-model.cc
--- ns-3.39/src/spectrum/model/phased-array-spectrum-propagation-loss-model.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/phased-array-spectrum-propagation-loss-model.cc	2023-09-27 13:30:37.874839800 -0700
@@ -18,7 +18,8 @@
 
 #include "phased-array-spectrum-propagation-loss-model.h"
 
-#include "ns3/spectrum-signal-parameters.h"
+#include "spectrum-signal-parameters.h"
+
 #include <ns3/log.h>
 #include <ns3/phased-array-model.h>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/phased-array-spectrum-propagation-loss-model.h ns-3.40/src/spectrum/model/phased-array-spectrum-propagation-loss-model.h
--- ns-3.39/src/spectrum/model/phased-array-spectrum-propagation-loss-model.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/phased-array-spectrum-propagation-loss-model.h	2023-09-27 13:30:37.874839800 -0700
@@ -19,10 +19,11 @@
 #ifndef PHASED_ARRAY_SPECTRUM_PROPAGATION_LOSS_MODEL_H
 #define PHASED_ARRAY_SPECTRUM_PROPAGATION_LOSS_MODEL_H
 
+#include "spectrum-value.h"
+
 #include <ns3/mobility-model.h>
 #include <ns3/object.h>
 #include <ns3/phased-array-model.h>
-#include <ns3/spectrum-value.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/single-model-spectrum-channel.cc ns-3.40/src/spectrum/model/single-model-spectrum-channel.cc
--- ns-3.39/src/spectrum/model/single-model-spectrum-channel.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/single-model-spectrum-channel.cc	2023-09-27 13:30:37.874839800 -0700
@@ -19,6 +19,10 @@
 
 #include "single-model-spectrum-channel.h"
 
+#include "spectrum-phy.h"
+#include "spectrum-propagation-loss-model.h"
+#include "spectrum-transmit-filter.h"
+
 #include <ns3/angles.h>
 #include <ns3/antenna-model.h>
 #include <ns3/double.h>
@@ -32,9 +36,6 @@
 #include <ns3/propagation-delay-model.h>
 #include <ns3/propagation-loss-model.h>
 #include <ns3/simulator.h>
-#include <ns3/spectrum-phy.h>
-#include <ns3/spectrum-propagation-loss-model.h>
-#include <ns3/spectrum-transmit-filter.h>
 
 #include <algorithm>
 
@@ -118,9 +119,7 @@
 
     Ptr<MobilityModel> senderMobility = txParams->txPhy->GetMobility();
 
-    for (PhyList::const_iterator rxPhyIterator = m_phyList.begin();
-         rxPhyIterator != m_phyList.end();
-         ++rxPhyIterator)
+    for (auto rxPhyIterator = m_phyList.begin(); rxPhyIterator != m_phyList.end(); ++rxPhyIterator)
     {
         Ptr<NetDevice> rxNetDevice = (*rxPhyIterator)->GetDevice();
         Ptr<NetDevice> txNetDevice = txParams->txPhy->GetDevice();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/single-model-spectrum-channel.h ns-3.40/src/spectrum/model/single-model-spectrum-channel.h
--- ns-3.39/src/spectrum/model/single-model-spectrum-channel.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/single-model-spectrum-channel.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,8 +20,9 @@
 #ifndef SINGLE_MODEL_SPECTRUM_CHANNEL_H
 #define SINGLE_MODEL_SPECTRUM_CHANNEL_H
 
-#include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-model.h>
+#include "spectrum-channel.h"
+#include "spectrum-model.h"
+
 #include <ns3/traced-callback.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-analyzer.h ns-3.40/src/spectrum/model/spectrum-analyzer.h
--- ns-3.39/src/spectrum/model/spectrum-analyzer.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-analyzer.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,13 +20,14 @@
 #ifndef SPECTRUM_ANALYZER_H
 #define SPECTRUM_ANALYZER_H
 
+#include "spectrum-channel.h"
+#include "spectrum-phy.h"
+#include "spectrum-value.h"
+
 #include <ns3/mobility-model.h>
 #include <ns3/net-device.h>
 #include <ns3/nstime.h>
 #include <ns3/packet.h>
-#include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-phy.h>
-#include <ns3/spectrum-value.h>
 
 #include <fstream>
 #include <string>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-channel.h ns-3.40/src/spectrum/model/spectrum-channel.h
--- ns-3.39/src/spectrum/model/spectrum-channel.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-channel.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,17 +20,18 @@
 #ifndef SPECTRUM_CHANNEL_H
 #define SPECTRUM_CHANNEL_H
 
+#include "phased-array-spectrum-propagation-loss-model.h"
+#include "spectrum-phy.h"
+#include "spectrum-propagation-loss-model.h"
+#include "spectrum-signal-parameters.h"
+#include "spectrum-transmit-filter.h"
+
 #include <ns3/channel.h>
 #include <ns3/mobility-model.h>
 #include <ns3/nstime.h>
 #include <ns3/object.h>
-#include <ns3/phased-array-spectrum-propagation-loss-model.h>
 #include <ns3/propagation-delay-model.h>
 #include <ns3/propagation-loss-model.h>
-#include <ns3/spectrum-phy.h>
-#include <ns3/spectrum-propagation-loss-model.h>
-#include <ns3/spectrum-signal-parameters.h>
-#include <ns3/spectrum-transmit-filter.h>
 #include <ns3/traced-callback.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-converter.cc ns-3.40/src/spectrum/model/spectrum-converter.cc
--- ns-3.39/src/spectrum/model/spectrum-converter.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-converter.cc	2023-09-27 13:30:37.874839800 -0700
@@ -17,9 +17,10 @@
  * Author: Nicola Baldo <nbaldo@cttc.es>
  */
 
+#include "spectrum-converter.h"
+
 #include <ns3/assert.h>
 #include <ns3/log.h>
-#include <ns3/spectrum-converter.h>
 
 #include <algorithm>
 
@@ -40,13 +41,10 @@
     m_toSpectrumModel = toSpectrumModel;
 
     size_t rowPtr = 0;
-    for (Bands::const_iterator toit = toSpectrumModel->Begin(); toit != toSpectrumModel->End();
-         ++toit)
+    for (auto toit = toSpectrumModel->Begin(); toit != toSpectrumModel->End(); ++toit)
     {
         size_t colInd = 0;
-        for (Bands::const_iterator fromit = fromSpectrumModel->Begin();
-             fromit != fromSpectrumModel->End();
-             ++fromit)
+        for (auto fromit = fromSpectrumModel->Begin(); fromit != fromSpectrumModel->End(); ++fromit)
         {
             double c = GetCoefficient(*fromit, *toit);
             NS_LOG_LOGIC("(" << fromit->fl << "," << fromit->fh << ")"
@@ -82,12 +80,10 @@
 
     Ptr<SpectrumValue> tvvf = Create<SpectrumValue>(m_toSpectrumModel);
 
-    Values::iterator tvit = tvvf->ValuesBegin();
+    auto tvit = tvvf->ValuesBegin();
     size_t i = 0; // Index of conversion coefficient
 
-    for (std::vector<size_t>::const_iterator convIt = m_conversionRowPtr.begin();
-         convIt != m_conversionRowPtr.end();
-         ++convIt)
+    for (auto convIt = m_conversionRowPtr.begin(); convIt != m_conversionRowPtr.end(); ++convIt)
     {
         double sum = 0;
         while (i < *convIt)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-converter.h ns-3.40/src/spectrum/model/spectrum-converter.h
--- ns-3.39/src/spectrum/model/spectrum-converter.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-converter.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,7 +20,7 @@
 #ifndef SPECTRUM_CONVERTER_H
 #define SPECTRUM_CONVERTER_H
 
-#include <ns3/spectrum-value.h>
+#include "spectrum-value.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-error-model.cc ns-3.40/src/spectrum/model/spectrum-error-model.cc
--- ns-3.39/src/spectrum/model/spectrum-error-model.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-error-model.cc	2023-09-27 13:30:37.874839800 -0700
@@ -79,8 +79,8 @@
     SpectrumValue CapacityPerHertz = Log2(1 + sinr);
     double capacity = 0;
 
-    Bands::const_iterator bi = CapacityPerHertz.ConstBandsBegin();
-    Values::const_iterator vi = CapacityPerHertz.ConstValuesBegin();
+    auto bi = CapacityPerHertz.ConstBandsBegin();
+    auto vi = CapacityPerHertz.ConstValuesBegin();
 
     while (bi != CapacityPerHertz.ConstBandsEnd())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-error-model.h ns-3.40/src/spectrum/model/spectrum-error-model.h
--- ns-3.39/src/spectrum/model/spectrum-error-model.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-error-model.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,11 +20,12 @@
 #ifndef SPECTRUM_ERROR_MODEL_H
 #define SPECTRUM_ERROR_MODEL_H
 
+#include "spectrum-value.h"
+
 #include <ns3/nstime.h>
 #include <ns3/object.h>
 #include <ns3/packet.h>
 #include <ns3/ptr.h>
-#include <ns3/spectrum-value.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-interference.h ns-3.40/src/spectrum/model/spectrum-interference.h
--- ns-3.39/src/spectrum/model/spectrum-interference.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-interference.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,10 +20,11 @@
 #ifndef SPECTRUM_INTERFERENCE_H
 #define SPECTRUM_INTERFERENCE_H
 
+#include "spectrum-value.h"
+
 #include <ns3/nstime.h>
 #include <ns3/object.h>
 #include <ns3/packet.h>
-#include <ns3/spectrum-value.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-model-300kHz-300GHz-log.cc ns-3.40/src/spectrum/model/spectrum-model-300kHz-300GHz-log.cc
--- ns-3.39/src/spectrum/model/spectrum-model-300kHz-300GHz-log.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-model-300kHz-300GHz-log.cc	2023-09-27 13:30:37.874839800 -0700
@@ -17,7 +17,7 @@
  * Author: Nicola Baldo <nbaldo@cttc.es>
  */
 
-#include <ns3/spectrum-model-300kHz-300GHz-log.h>
+#include "spectrum-model-300kHz-300GHz-log.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-model-300kHz-300GHz-log.h ns-3.40/src/spectrum/model/spectrum-model-300kHz-300GHz-log.h
--- ns-3.39/src/spectrum/model/spectrum-model-300kHz-300GHz-log.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-model-300kHz-300GHz-log.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,7 +20,7 @@
 #ifndef FREQS_300KHZ_300GHZ_LOG_H
 #define FREQS_300KHZ_300GHZ_LOG_H
 
-#include <ns3/spectrum-value.h>
+#include "spectrum-value.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-model.cc ns-3.40/src/spectrum/model/spectrum-model.cc
--- ns-3.39/src/spectrum/model/spectrum-model.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-model.cc	2023-09-27 13:30:37.874839800 -0700
@@ -18,9 +18,10 @@
  * Author: Nicola Baldo <nbaldo@cttc.es>
  */
 
+#include "spectrum-model.h"
+
 #include <ns3/assert.h>
 #include <ns3/log.h>
-#include <ns3/spectrum-model.h>
 
 #include <cmath>
 #include <cstddef>
@@ -43,8 +44,7 @@
     NS_ASSERT(centerFreqs.size() > 1);
     m_uid = ++m_uidCount;
 
-    for (std::vector<double>::const_iterator it = centerFreqs.begin(); it != centerFreqs.end();
-         ++it)
+    for (auto it = centerFreqs.begin(); it != centerFreqs.end(); ++it)
     {
         BandInfo e;
         e.fc = *it;
@@ -110,9 +110,9 @@
 bool
 SpectrumModel::IsOrthogonal(const SpectrumModel& other) const
 {
-    for (Bands::const_iterator myIt = Begin(); myIt != End(); ++myIt)
+    for (auto myIt = Begin(); myIt != End(); ++myIt)
     {
-        for (Bands::const_iterator otherIt = other.Begin(); otherIt != other.End(); ++otherIt)
+        for (auto otherIt = other.Begin(); otherIt != other.End(); ++otherIt)
         {
             if (std::max(myIt->fl, otherIt->fl) < std::min(myIt->fh, otherIt->fh))
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-model-ism2400MHz-res1MHz.cc ns-3.40/src/spectrum/model/spectrum-model-ism2400MHz-res1MHz.cc
--- ns-3.39/src/spectrum/model/spectrum-model-ism2400MHz-res1MHz.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-model-ism2400MHz-res1MHz.cc	2023-09-27 13:30:37.874839800 -0700
@@ -17,7 +17,7 @@
  * Author: Nicola Baldo <nbaldo@cttc.es>
  */
 
-#include <ns3/spectrum-model-ism2400MHz-res1MHz.h>
+#include "spectrum-model-ism2400MHz-res1MHz.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-model-ism2400MHz-res1MHz.h ns-3.40/src/spectrum/model/spectrum-model-ism2400MHz-res1MHz.h
--- ns-3.39/src/spectrum/model/spectrum-model-ism2400MHz-res1MHz.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-model-ism2400MHz-res1MHz.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,7 +20,7 @@
 #ifndef FREQS_ISM2400MHZ_RES1MHZ_H
 #define FREQS_ISM2400MHZ_RES1MHZ_H
 
-#include <ns3/spectrum-value.h>
+#include "spectrum-value.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-phy.cc ns-3.40/src/spectrum/model/spectrum-phy.cc
--- ns-3.39/src/spectrum/model/spectrum-phy.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-phy.cc	2023-09-27 13:30:37.874839800 -0700
@@ -19,11 +19,12 @@
 
 #include "spectrum-phy.h"
 
+#include "spectrum-channel.h"
+#include "spectrum-value.h"
+
 #include <ns3/log.h>
 #include <ns3/mobility-model.h>
 #include <ns3/net-device.h>
-#include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-value.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-propagation-loss-model.h ns-3.40/src/spectrum/model/spectrum-propagation-loss-model.h
--- ns-3.39/src/spectrum/model/spectrum-propagation-loss-model.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-propagation-loss-model.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,9 +20,10 @@
 #ifndef SPECTRUM_PROPAGATION_LOSS_MODEL_H
 #define SPECTRUM_PROPAGATION_LOSS_MODEL_H
 
+#include "spectrum-value.h"
+
 #include <ns3/mobility-model.h>
 #include <ns3/object.h>
-#include <ns3/spectrum-value.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-signal-parameters.cc ns-3.40/src/spectrum/model/spectrum-signal-parameters.cc
--- ns-3.39/src/spectrum/model/spectrum-signal-parameters.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-signal-parameters.cc	2023-09-27 13:30:37.874839800 -0700
@@ -17,11 +17,13 @@
  * Author: Nicola Baldo <nbaldo@cttc.es>
  */
 
+#include "spectrum-signal-parameters.h"
+
+#include "spectrum-phy.h"
+#include "spectrum-value.h"
+
 #include <ns3/antenna-model.h>
 #include <ns3/log.h>
-#include <ns3/spectrum-phy.h>
-#include <ns3/spectrum-signal-parameters.h>
-#include <ns3/spectrum-value.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-value.cc ns-3.40/src/spectrum/model/spectrum-value.cc
--- ns-3.39/src/spectrum/model/spectrum-value.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-value.cc	2023-09-27 13:30:37.874839800 -0700
@@ -18,9 +18,10 @@
  * Author: Nicola Baldo <nbaldo@cttc.es>
  */
 
+#include "spectrum-value.h"
+
 #include <ns3/log.h>
 #include <ns3/math.h>
-#include <ns3/spectrum-value.h>
 
 namespace ns3
 {
@@ -100,8 +101,8 @@
 void
 SpectrumValue::Add(const SpectrumValue& x)
 {
-    Values::iterator it1 = m_values.begin();
-    Values::const_iterator it2 = x.m_values.begin();
+    auto it1 = m_values.begin();
+    auto it2 = x.m_values.begin();
 
     NS_ASSERT(m_spectrumModel == x.m_spectrumModel);
     NS_ASSERT(m_values.size() == x.m_values.size());
@@ -117,7 +118,7 @@
 void
 SpectrumValue::Add(double s)
 {
-    Values::iterator it1 = m_values.begin();
+    auto it1 = m_values.begin();
 
     while (it1 != m_values.end())
     {
@@ -129,8 +130,8 @@
 void
 SpectrumValue::Subtract(const SpectrumValue& x)
 {
-    Values::iterator it1 = m_values.begin();
-    Values::const_iterator it2 = x.m_values.begin();
+    auto it1 = m_values.begin();
+    auto it2 = x.m_values.begin();
 
     NS_ASSERT(m_spectrumModel == x.m_spectrumModel);
     NS_ASSERT(m_values.size() == x.m_values.size());
@@ -152,8 +153,8 @@
 void
 SpectrumValue::Multiply(const SpectrumValue& x)
 {
-    Values::iterator it1 = m_values.begin();
-    Values::const_iterator it2 = x.m_values.begin();
+    auto it1 = m_values.begin();
+    auto it2 = x.m_values.begin();
 
     NS_ASSERT(m_spectrumModel == x.m_spectrumModel);
     NS_ASSERT(m_values.size() == x.m_values.size());
@@ -169,7 +170,7 @@
 void
 SpectrumValue::Multiply(double s)
 {
-    Values::iterator it1 = m_values.begin();
+    auto it1 = m_values.begin();
 
     while (it1 != m_values.end())
     {
@@ -181,8 +182,8 @@
 void
 SpectrumValue::Divide(const SpectrumValue& x)
 {
-    Values::iterator it1 = m_values.begin();
-    Values::const_iterator it2 = x.m_values.begin();
+    auto it1 = m_values.begin();
+    auto it2 = x.m_values.begin();
 
     NS_ASSERT(m_spectrumModel == x.m_spectrumModel);
     NS_ASSERT(m_values.size() == x.m_values.size());
@@ -199,7 +200,7 @@
 SpectrumValue::Divide(double s)
 {
     NS_LOG_FUNCTION(this << s);
-    Values::iterator it1 = m_values.begin();
+    auto it1 = m_values.begin();
 
     while (it1 != m_values.end())
     {
@@ -211,7 +212,7 @@
 void
 SpectrumValue::ChangeSign()
 {
-    Values::iterator it1 = m_values.begin();
+    auto it1 = m_values.begin();
 
     while (it1 != m_values.end())
     {
@@ -256,7 +257,7 @@
 SpectrumValue::Pow(double exp)
 {
     NS_LOG_FUNCTION(this << exp);
-    Values::iterator it1 = m_values.begin();
+    auto it1 = m_values.begin();
 
     while (it1 != m_values.end())
     {
@@ -269,7 +270,7 @@
 SpectrumValue::Exp(double base)
 {
     NS_LOG_FUNCTION(this << base);
-    Values::iterator it1 = m_values.begin();
+    auto it1 = m_values.begin();
 
     while (it1 != m_values.end())
     {
@@ -282,7 +283,7 @@
 SpectrumValue::Log10()
 {
     NS_LOG_FUNCTION(this);
-    Values::iterator it1 = m_values.begin();
+    auto it1 = m_values.begin();
 
     while (it1 != m_values.end())
     {
@@ -295,7 +296,7 @@
 SpectrumValue::Log2()
 {
     NS_LOG_FUNCTION(this);
-    Values::iterator it1 = m_values.begin();
+    auto it1 = m_values.begin();
 
     while (it1 != m_values.end())
     {
@@ -308,7 +309,7 @@
 SpectrumValue::Log()
 {
     NS_LOG_FUNCTION(this);
-    Values::iterator it1 = m_values.begin();
+    auto it1 = m_values.begin();
 
     while (it1 != m_values.end())
     {
@@ -321,7 +322,7 @@
 Norm(const SpectrumValue& x)
 {
     double s = 0;
-    Values::const_iterator it1 = x.ConstValuesBegin();
+    auto it1 = x.ConstValuesBegin();
     while (it1 != x.ConstValuesEnd())
     {
         s += (*it1) * (*it1);
@@ -334,7 +335,7 @@
 Sum(const SpectrumValue& x)
 {
     double s = 0;
-    Values::const_iterator it1 = x.ConstValuesBegin();
+    auto it1 = x.ConstValuesBegin();
     while (it1 != x.ConstValuesEnd())
     {
         s += (*it1);
@@ -347,7 +348,7 @@
 Prod(const SpectrumValue& x)
 {
     double s = 0;
-    Values::const_iterator it1 = x.ConstValuesBegin();
+    auto it1 = x.ConstValuesBegin();
     while (it1 != x.ConstValuesEnd())
     {
         s *= (*it1);
@@ -360,8 +361,8 @@
 Integral(const SpectrumValue& arg)
 {
     double i = 0;
-    Values::const_iterator vit = arg.ConstValuesBegin();
-    Bands::const_iterator bit = arg.ConstBandsBegin();
+    auto vit = arg.ConstValuesBegin();
+    auto bit = arg.ConstBandsBegin();
     while (vit != arg.ConstValuesEnd())
     {
         NS_ASSERT(bit != arg.ConstBandsEnd());
@@ -392,7 +393,7 @@
 std::ostream&
 operator<<(std::ostream& os, const SpectrumValue& pvf)
 {
-    Values::const_iterator it1 = pvf.ConstValuesBegin();
+    auto it1 = pvf.ConstValuesBegin();
     while (it1 != pvf.ConstValuesEnd())
     {
         os << *it1 << " ";
@@ -612,7 +613,7 @@
 SpectrumValue&
 SpectrumValue::operator=(double rhs)
 {
-    Values::iterator it1 = m_values.begin();
+    auto it1 = m_values.begin();
 
     while (it1 != m_values.end())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/spectrum-value.h ns-3.40/src/spectrum/model/spectrum-value.h
--- ns-3.39/src/spectrum/model/spectrum-value.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/spectrum-value.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,9 +20,10 @@
 #ifndef SPECTRUM_VALUE_H
 #define SPECTRUM_VALUE_H
 
+#include "spectrum-model.h"
+
 #include <ns3/ptr.h>
 #include <ns3/simple-ref-count.h>
-#include <ns3/spectrum-model.h>
 
 #include <ostream>
 #include <vector>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/three-gpp-channel-model.cc ns-3.40/src/spectrum/model/three-gpp-channel-model.cc
--- ns-3.39/src/spectrum/model/three-gpp-channel-model.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/three-gpp-channel-model.cc	2023-09-27 13:30:37.874839800 -0700
@@ -2197,12 +2197,11 @@
 {
     NS_LOG_FUNCTION(this);
 
-    DoubleVector powerAttenuation;
-    uint8_t clusterNum = clusterAOA.size();
-    for (uint8_t cInd = 0; cInd < clusterNum; cInd++)
-    {
-        powerAttenuation.push_back(0); // Initial power attenuation for all clusters to be 0 dB;
-    }
+    auto clusterNum = clusterAOA.size();
+
+    // Initial power attenuation for all clusters to be 0 dB
+    DoubleVector powerAttenuation(clusterNum, 0);
+
     // step a: the number of non-self blocking blockers is stored in m_numNonSelfBlocking.
 
     // step b:Generate the size and location of each blocker
@@ -2315,7 +2314,7 @@
     }
 
     // step c: Determine the attenuation of each blocker due to blockers
-    for (uint8_t cInd = 0; cInd < clusterNum; cInd++)
+    for (std::size_t cInd = 0; cInd < clusterNum; cInd++)
     {
         NS_ASSERT_MSG(clusterAOA[cInd] >= 0 && clusterAOA[cInd] <= 360,
                       "the AOA should be the range of [0,360]");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/three-gpp-channel-model.h ns-3.40/src/spectrum/model/three-gpp-channel-model.h
--- ns-3.39/src/spectrum/model/three-gpp-channel-model.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/three-gpp-channel-model.h	2023-09-27 13:30:37.874839800 -0700
@@ -21,10 +21,11 @@
 #ifndef THREE_GPP_CHANNEL_H
 #define THREE_GPP_CHANNEL_H
 
+#include "matrix-based-channel-model.h"
+
 #include "ns3/angles.h"
 #include <ns3/boolean.h>
 #include <ns3/channel-condition-model.h>
-#include <ns3/matrix-based-channel-model.h>
 
 #include <complex.h>
 #include <unordered_map>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h ns-3.40/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h
--- ns-3.39/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h	2023-09-27 13:30:37.874839800 -0700
@@ -21,8 +21,9 @@
 #ifndef THREE_GPP_SPECTRUM_PROPAGATION_LOSS_H
 #define THREE_GPP_SPECTRUM_PROPAGATION_LOSS_H
 
-#include "ns3/matrix-based-channel-model.h"
-#include "ns3/phased-array-spectrum-propagation-loss-model.h"
+#include "matrix-based-channel-model.h"
+#include "phased-array-spectrum-propagation-loss-model.h"
+
 #include "ns3/random-variable-stream.h"
 
 #include <complex.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/trace-fading-loss-model.cc ns-3.40/src/spectrum/model/trace-fading-loss-model.cc
--- ns-3.39/src/spectrum/model/trace-fading-loss-model.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/trace-fading-loss-model.cc	2023-09-27 13:30:37.874839800 -0700
@@ -18,16 +18,17 @@
  *         Marco Miozzo <mmiozzo@cttc.es>
  */
 
+#include "trace-fading-loss-model.h"
+
 #include "spectrum-signal-parameters.h"
+#include "spectrum-value.h"
 
 #include "ns3/uinteger.h"
 #include <ns3/double.h>
 #include <ns3/log.h>
 #include <ns3/mobility-model.h>
 #include <ns3/simulator.h>
-#include <ns3/spectrum-value.h>
 #include <ns3/string.h>
-#include <ns3/trace-fading-loss-model.h>
 
 #include <fstream>
 
@@ -152,9 +153,8 @@
 {
     NS_LOG_FUNCTION(this << *params->psd << a << b);
 
-    std::map<ChannelRealizationId_t, int>::iterator itOff;
     ChannelRealizationId_t mobilityPair = std::make_pair(a, b);
-    itOff = m_windowOffsetsMap.find(mobilityPair);
+    auto itOff = m_windowOffsetsMap.find(mobilityPair);
     if (itOff != m_windowOffsetsMap.end())
     {
         if (Simulator::Now().GetSeconds() >=
@@ -162,11 +162,10 @@
         {
             // update all the offsets
             NS_LOG_INFO("Fading Windows Updated");
-            std::map<ChannelRealizationId_t, int>::iterator itOff2;
-            for (itOff2 = m_windowOffsetsMap.begin(); itOff2 != m_windowOffsetsMap.end(); itOff2++)
+            for (auto itOff2 = m_windowOffsetsMap.begin(); itOff2 != m_windowOffsetsMap.end();
+                 itOff2++)
             {
-                std::map<ChannelRealizationId_t, Ptr<UniformRandomVariable>>::iterator itVar;
-                itVar = m_startVariableMap.find((*itOff2).first);
+                auto itVar = m_startVariableMap.find((*itOff2).first);
                 (*itOff2).second = (*itVar).second->GetValue();
             }
             m_lastWindowUpdate = Simulator::Now();
@@ -198,7 +197,7 @@
     }
 
     Ptr<SpectrumValue> rxPsd = Copy<SpectrumValue>(params->psd);
-    Values::iterator vit = rxPsd->ValuesBegin();
+    auto vit = rxPsd->ValuesBegin();
 
     // Vector aSpeedVector = a->GetVelocity ();
     // Vector bSpeedVector = b->GetVelocity ();
@@ -246,8 +245,7 @@
     m_streamsAssigned = true;
     m_currentStream = stream;
     m_lastStream = stream + m_streamSetSize - 1;
-    std::map<ChannelRealizationId_t, Ptr<UniformRandomVariable>>::iterator itVar;
-    itVar = m_startVariableMap.begin();
+    auto itVar = m_startVariableMap.begin();
     // the following loop is for eventually pre-existing ChannelRealization instances
     // note that more instances are expected to be created at run time
     while (itVar != m_startVariableMap.end())
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/trace-fading-loss-model.h ns-3.40/src/spectrum/model/trace-fading-loss-model.h
--- ns-3.39/src/spectrum/model/trace-fading-loss-model.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/trace-fading-loss-model.h	2023-09-27 13:30:37.874839800 -0700
@@ -21,10 +21,11 @@
 #ifndef TRACE_FADING_LOSS_MODEL_H
 #define TRACE_FADING_LOSS_MODEL_H
 
+#include "spectrum-propagation-loss-model.h"
+
 #include "ns3/random-variable-stream.h"
 #include <ns3/nstime.h>
 #include <ns3/object.h>
-#include <ns3/spectrum-propagation-loss-model.h>
 
 #include <map>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/tv-spectrum-transmitter.cc ns-3.40/src/spectrum/model/tv-spectrum-transmitter.cc
--- ns-3.39/src/spectrum/model/tv-spectrum-transmitter.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/tv-spectrum-transmitter.cc	2023-09-27 13:30:37.874839800 -0700
@@ -246,7 +246,7 @@
     NS_ASSERT(m_channelBandwidth != 0);
     Ptr<SpectrumModel> model;
     TvSpectrumModelId key(m_startFrequency, m_channelBandwidth);
-    std::map<TvSpectrumModelId, Ptr<SpectrumModel>>::iterator iter = g_tvSpectrumModelMap.find(key);
+    auto iter = g_tvSpectrumModelMap.find(key);
     if (iter != g_tvSpectrumModelMap.end())
     {
         model = iter->second; // set SpectrumModel to previously created one
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/tv-spectrum-transmitter.h ns-3.40/src/spectrum/model/tv-spectrum-transmitter.h
--- ns-3.39/src/spectrum/model/tv-spectrum-transmitter.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/tv-spectrum-transmitter.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,13 +20,14 @@
 #ifndef TV_SPECTRUM_TRANSMITTER_H
 #define TV_SPECTRUM_TRANSMITTER_H
 
+#include "spectrum-channel.h"
+#include "spectrum-phy.h"
+#include "spectrum-signal-parameters.h"
+#include "spectrum-value.h"
+
 #include <ns3/antenna-model.h>
 #include <ns3/mobility-model.h>
 #include <ns3/net-device.h>
-#include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-phy.h>
-#include <ns3/spectrum-signal-parameters.h>
-#include <ns3/spectrum-value.h>
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/two-ray-spectrum-propagation-loss-model.h ns-3.40/src/spectrum/model/two-ray-spectrum-propagation-loss-model.h
--- ns-3.39/src/spectrum/model/two-ray-spectrum-propagation-loss-model.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/two-ray-spectrum-propagation-loss-model.h	2023-09-27 13:30:37.874839800 -0700
@@ -19,9 +19,10 @@
 #ifndef TWO_RAY_SPECTRUM_PROPAGATION_LOSS_H
 #define TWO_RAY_SPECTRUM_PROPAGATION_LOSS_H
 
+#include "phased-array-spectrum-propagation-loss-model.h"
+#include "spectrum-signal-parameters.h"
+
 #include "ns3/channel-condition-model.h"
-#include "ns3/phased-array-spectrum-propagation-loss-model.h"
-#include "ns3/spectrum-signal-parameters.h"
 
 #include <map>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/waveform-generator.h ns-3.40/src/spectrum/model/waveform-generator.h
--- ns-3.39/src/spectrum/model/waveform-generator.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/waveform-generator.h	2023-09-27 13:30:37.874839800 -0700
@@ -20,14 +20,15 @@
 #ifndef WAVEFORM_GENERATOR_H
 #define WAVEFORM_GENERATOR_H
 
+#include "spectrum-channel.h"
+#include "spectrum-phy.h"
+#include "spectrum-value.h"
+
 #include <ns3/event-id.h>
 #include <ns3/mobility-model.h>
 #include <ns3/net-device.h>
 #include <ns3/nstime.h>
 #include <ns3/packet.h>
-#include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-phy.h>
-#include <ns3/spectrum-value.h>
 #include <ns3/trace-source-accessor.h>
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/wifi-spectrum-value-helper.cc ns-3.40/src/spectrum/model/wifi-spectrum-value-helper.cc
--- ns-3.39/src/spectrum/model/wifi-spectrum-value-helper.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/wifi-spectrum-value-helper.cc	2023-09-27 13:30:37.878839700 -0700
@@ -77,8 +77,7 @@
     NS_LOG_FUNCTION(centerFrequency << channelWidth << carrierSpacing << guardBandwidth);
     Ptr<SpectrumModel> ret;
     WifiSpectrumModelId key{centerFrequency, channelWidth, carrierSpacing, guardBandwidth};
-    std::map<WifiSpectrumModelId, Ptr<SpectrumModel>>::iterator it =
-        g_wifiSpectrumModelMap.find(key);
+    auto it = g_wifiSpectrumModelMap.find(key);
     if (it != g_wifiSpectrumModelMap.end())
     {
         ret = it->second;
@@ -89,7 +88,7 @@
         double centerFrequencyHz = centerFrequency * 1e6;
         double bandwidth = (channelWidth + (2.0 * guardBandwidth)) * 1e6;
         // For OFDM, the center subcarrier is null (at center frequency)
-        uint32_t numBands = static_cast<uint32_t>((bandwidth / carrierSpacing) + 0.5);
+        auto numBands = static_cast<uint32_t>((bandwidth / carrierSpacing) + 0.5);
         NS_ASSERT(numBands > 0);
         if (numBands % 2 == 0)
         {
@@ -134,11 +133,10 @@
     uint32_t carrierSpacing = 312500;
     Ptr<SpectrumValue> c = Create<SpectrumValue>(
         GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-    Values::iterator vit = c->ValuesBegin();
-    Bands::const_iterator bit = c->ConstBandsBegin();
-    uint32_t nGuardBands =
-        static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
-    uint32_t nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
+    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;
@@ -188,9 +186,8 @@
 
     Ptr<SpectrumValue> c = Create<SpectrumValue>(
         GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-    uint32_t nGuardBands =
-        static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
-    uint32_t nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
+    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)
@@ -240,9 +237,8 @@
     uint32_t carrierSpacing = 312500;
     Ptr<SpectrumValue> c = Create<SpectrumValue>(
         GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-    uint32_t nGuardBands =
-        static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
-    uint32_t nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
+    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;
@@ -281,7 +277,7 @@
     }
 
     // Prepare spectrum mask specific variables
-    uint32_t innerSlopeWidth = static_cast<uint32_t>(
+    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);
@@ -315,9 +311,8 @@
     uint32_t carrierSpacing = 312500;
     Ptr<SpectrumValue> c = Create<SpectrumValue>(
         GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-    uint32_t nGuardBands =
-        static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
-    uint32_t nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
+    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;
@@ -347,7 +342,7 @@
     }
 
     // Prepare spectrum mask specific variables
-    uint32_t innerSlopeWidth = static_cast<uint32_t>(
+    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);
@@ -383,9 +378,8 @@
     uint32_t carrierSpacing = 78125;
     Ptr<SpectrumValue> c = Create<SpectrumValue>(
         GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-    uint32_t nGuardBands =
-        static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
-    uint32_t nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
+    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;
@@ -398,7 +392,7 @@
     uint32_t start4;
     uint32_t stop4;
     // Prepare spectrum mask specific variables
-    uint32_t innerSlopeWidth = static_cast<uint32_t>(
+    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)
@@ -468,7 +462,7 @@
     }
 
     // Create punctured bands
-    uint32_t puncturedSlopeWidth =
+    auto puncturedSlopeWidth =
         static_cast<uint32_t>((500e3 / carrierSpacing) +
                               0.5); // size in number of subcarriers of the punctured slope band
     std::vector<WifiSpectrumBandIndices> puncturedBands;
@@ -516,8 +510,8 @@
         GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
 
     // Build spectrum mask
-    Values::iterator vit = c->ValuesBegin();
-    Bands::const_iterator bit = c->ConstBandsBegin();
+    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++)
@@ -655,8 +649,8 @@
     double puncturedSlope = (-1 * minInnerBandDbr) / puncturedSlopeWidth;
 
     // Build spectrum mask
-    Values::iterator vit = c->ValuesBegin();
-    Bands::const_iterator bit = c->ConstBandsBegin();
+    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++)
@@ -780,7 +774,7 @@
     double normalizationRatio = currentTxPowerW / txPowerW;
     NS_LOG_LOGIC("Current power: " << currentTxPowerW << "W vs expected power: " << txPowerW << "W"
                                    << " -> ratio (C/E) = " << normalizationRatio);
-    Values::iterator vit = c->ValuesBegin();
+    auto vit = c->ValuesBegin();
     for (size_t i = 0; i < c->GetSpectrumModel()->GetNumBands(); i++, vit++)
     {
         *vit = (*vit) / normalizationRatio;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/model/wifi-spectrum-value-helper.h ns-3.40/src/spectrum/model/wifi-spectrum-value-helper.h
--- ns-3.39/src/spectrum/model/wifi-spectrum-value-helper.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/model/wifi-spectrum-value-helper.h	2023-09-27 13:30:37.878839700 -0700
@@ -22,7 +22,7 @@
 #ifndef WIFI_SPECTRUM_VALUE_HELPER_H
 #define WIFI_SPECTRUM_VALUE_HELPER_H
 
-#include <ns3/spectrum-value.h>
+#include "spectrum-value.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/test/spectrum-interference-test.cc ns-3.40/src/spectrum/test/spectrum-interference-test.cc
--- ns-3.39/src/spectrum/test/spectrum-interference-test.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/test/spectrum-interference-test.cc	2023-09-27 13:30:37.878839700 -0700
@@ -44,7 +44,7 @@
      * Constructor
      * \param s Spectrum value
      * \param txBytes number of bytes to transmit
-     * \param rxCorrect extected Rx bytes
+     * \param rxCorrect expected Rx bytes
      * \param name test name
      */
     SpectrumInterferenceTestCase(Ptr<SpectrumValue> s,
@@ -62,7 +62,7 @@
   private:
     Ptr<SpectrumValue> m_s;                     //!< Spectrum value
     uint32_t m_txBytes;                         //!< number of bytes to transmit
-    uint32_t m_rxCorrectKnownOutcome;           //!< expected Rx bytes
+    bool m_rxCorrectKnownOutcome;               //!< expected Rx bytes
     Ptr<const SpectrumModel> m_mySpectrumModel; //!< Spectrum model pointer
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/test/spectrum-test.h ns-3.40/src/spectrum/test/spectrum-test.h
--- ns-3.39/src/spectrum/test/spectrum-test.h	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/test/spectrum-test.h	2023-09-27 13:30:37.878839700 -0700
@@ -48,8 +48,8 @@
 #define NS_TEST_ASSERT_MSG_SPECTRUM_MODEL_EQ_TOL(actual, expected, tol, msg)                       \
     do                                                                                             \
     {                                                                                              \
-        Bands::const_iterator i = (actual).Begin();                                                \
-        Bands::const_iterator j = (expected).Begin();                                              \
+        auto i = (actual).Begin();                                                                 \
+        auto j = (expected).Begin();                                                               \
         uint32_t k = 0;                                                                            \
         while (i != (actual).End() && j != (expected).End())                                       \
         {                                                                                          \
@@ -113,8 +113,8 @@
 #define NS_TEST_ASSERT_MSG_SPECTRUM_VALUE_EQ_TOL(actual, expected, tol, msg)                       \
     do                                                                                             \
     {                                                                                              \
-        Values::const_iterator i = (actual).ConstValuesBegin();                                    \
-        Values::const_iterator j = (expected).ConstValuesBegin();                                  \
+        auto i = (actual).ConstValuesBegin();                                                      \
+        auto j = (expected).ConstValuesBegin();                                                    \
         uint32_t k = 0;                                                                            \
         while (i != (actual).ConstValuesEnd() && j != (expected).ConstValuesEnd())                 \
         {                                                                                          \
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/test/tv-spectrum-transmitter-test.cc ns-3.40/src/spectrum/test/tv-spectrum-transmitter-test.cc
--- ns-3.39/src/spectrum/test/tv-spectrum-transmitter-test.cc	2023-07-05 14:23:48.081428300 -0700
+++ ns-3.40/src/spectrum/test/tv-spectrum-transmitter-test.cc	2023-09-27 13:30:37.878839700 -0700
@@ -124,7 +124,7 @@
 
     /* Test max PSD value */
     Ptr<SpectrumValue> psd = phy->GetTxPsd();
-    Values::const_iterator psdIter = psd->ConstValuesBegin();
+    auto psdIter = psd->ConstValuesBegin();
     double maxValue = 0;
     while (psdIter != psd->ConstValuesEnd())
     {
@@ -154,8 +154,8 @@
     }
 
     /* Test frequency range */
-    Bands::const_iterator bandStart = psd->ConstBandsBegin();
-    Bands::const_iterator bandEnd = psd->ConstBandsEnd();
+    auto bandStart = psd->ConstBandsBegin();
+    auto bandEnd = psd->ConstBandsEnd();
     epsilon = TOLERANCE * std::max(1.0, std::max((*bandStart).fc, m_startFrequency));
     NS_TEST_ASSERT_MSG_EQ_TOL((*bandStart).fc,
                               m_startFrequency,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/test/two-ray-splm-test-suite.cc ns-3.40/src/spectrum/test/two-ray-splm-test-suite.cc
--- ns-3.39/src/spectrum/test/two-ray-splm-test-suite.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/spectrum/test/two-ray-splm-test-suite.cc	2023-09-27 13:30:37.878839700 -0700
@@ -153,8 +153,10 @@
     // Generate a set of values for the FTR model parameters
     for (uint8_t j = 0; j < NUM_VALUES; j++)
     {
-        sigma[j] = std::pow(2, j);
-        k[j] = std::pow(2, j);
+        double power = std::pow(2, j);
+
+        sigma[j] = power;
+        k[j] = power;
         delta[j] = double(j) / NUM_VALUES; // Delta must be in [0, 1]
     }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/spectrum/utils/two-ray-to-three-gpp-ch-calibration.py ns-3.40/src/spectrum/utils/two-ray-to-three-gpp-ch-calibration.py
--- ns-3.39/src/spectrum/utils/two-ray-to-three-gpp-ch-calibration.py	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/spectrum/utils/two-ray-to-three-gpp-ch-calibration.py	2023-09-27 13:30:37.878839700 -0700
@@ -220,7 +220,7 @@
 def compute_anderson_darling_measure(ref_ecdf: list, target_ecdf: list) -> float:
     '''!  Computes the Anderson-Darling measure for the specified reference and targets distributions.
           In particular, the Anderson-Darling measure is defined as:
-          A^2 = -N -S, where S = \sum_{i=1}^N \frac{2i - 1}{N} \left[ ln F(Y_i) + ln F(Y_{N + 1 - i}) \right].
+          \f$A^2 = -N -S\f$, where \f$S = \sum_{i=1}^N \frac{2i - 1}{N} \left[ ln F(Y_i) + ln F(Y_{N + 1 - i}) \right]\f$.
 
           See https://www.itl.nist.gov/div898/handbook/eda/section3/eda35e.htm for further details.
 
@@ -248,7 +248,7 @@
 def compute_ecdf_value(ecdf: list, data_points: float) -> np.ndarray:
     '''!  Given an ECDF and data points belonging to its domain, returns their associated EDCF value.
         @param ecdf: The ECDF, represented as a sorted list of samples.
-        @param data_point: A list of data points belonging to the same domain as the samples.
+        @param data_points: A list of data points belonging to the same domain as the samples.
         @returns The ECDF value of the domain points of the specified ECDF
     '''
 
@@ -438,9 +438,8 @@
     out_str = out_str[0:-2]
     out_str += '}\n'
 
-    f = open(out_fname, "w")
-    f.write(out_str)
-    f.close()
+    with open(out_fname, "w", encoding="utf-8") as f:
+        f.write(out_str)
 
 
 if __name__ == '__main__':
@@ -499,12 +498,10 @@
             res = joblib.Parallel(n_jobs=10)(
                 joblib.delayed(fit_ftr_to_reference)(df, params_comb, num_search_grid_params, num_refinements) for params_comb in product(scenarios, is_los, frequencies))
 
-        f = open(fit_out_fname, "w")
-        f.write("scen\tcond\tfc\tsigma\tk\tdelta\tm\n")
-        for line in res:
-            f.write(line)
-
-        f.close()
+        with open(fit_out_fname, "w", encoding="utf-8") as f:
+            f.write("scen\tcond\tfc\tsigma\tk\tdelta\tm\n")
+            for line in res:
+                f.write(line)
 
     if output_ns3_table:
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/helper/file-helper.cc ns-3.40/src/stats/helper/file-helper.cc
--- ns-3.39/src/stats/helper/file-helper.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/helper/file-helper.cc	2023-09-27 13:30:37.878839700 -0700
@@ -288,8 +288,7 @@
     NS_LOG_FUNCTION(this << probeName);
 
     // Look for the probe.
-    std::map<std::string, std::pair<Ptr<Probe>, std::string>>::const_iterator mapIterator =
-        m_probeMap.find(probeName);
+    auto mapIterator = m_probeMap.find(probeName);
 
     // Return the probe if it has been added.
     if (mapIterator != m_probeMap.end())
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/helper/gnuplot-helper.cc ns-3.40/src/stats/helper/gnuplot-helper.cc
--- ns-3.39/src/stats/helper/gnuplot-helper.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/helper/gnuplot-helper.cc	2023-09-27 13:30:37.878839700 -0700
@@ -257,8 +257,7 @@
 GnuplotHelper::GetProbe(std::string probeName) const
 {
     // Look for the probe.
-    std::map<std::string, std::pair<Ptr<Probe>, std::string>>::const_iterator mapIterator =
-        m_probeMap.find(probeName);
+    auto mapIterator = m_probeMap.find(probeName);
 
     // Return the probe if it has been added.
     if (mapIterator != m_probeMap.end())
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/average.h ns-3.40/src/stats/model/average.h
--- ns-3.39/src/stats/model/average.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/average.h	2023-09-27 13:30:37.878839700 -0700
@@ -20,7 +20,8 @@
 
 #ifndef AVERAGE_H
 #define AVERAGE_H
-#include "ns3/basic-data-calculators.h"
+
+#include "basic-data-calculators.h"
 
 #include <cmath>
 #include <limits>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/boolean-probe.cc ns-3.40/src/stats/model/boolean-probe.cc
--- ns-3.39/src/stats/model/boolean-probe.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/boolean-probe.cc	2023-09-27 13:30:37.878839700 -0700
@@ -20,7 +20,7 @@
  * Modified by: Mitch Watrous (watrous@u.washington.edu)
  */
 
-#include "ns3/boolean-probe.h"
+#include "boolean-probe.h"
 
 #include "ns3/config.h"
 #include "ns3/log.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/boolean-probe.h ns-3.40/src/stats/model/boolean-probe.h
--- ns-3.39/src/stats/model/boolean-probe.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/boolean-probe.h	2023-09-27 13:30:37.878839700 -0700
@@ -23,10 +23,11 @@
 #ifndef BOOL_PROBE_H
 #define BOOL_PROBE_H
 
+#include "probe.h"
+
 #include "ns3/boolean.h"
 #include "ns3/callback.h"
 #include "ns3/object.h"
-#include "ns3/probe.h"
 #include "ns3/simulator.h"
 #include "ns3/traced-value.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/data-output-interface.h ns-3.40/src/stats/model/data-output-interface.h
--- ns-3.39/src/stats/model/data-output-interface.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/data-output-interface.h	2023-09-27 13:30:37.878839700 -0700
@@ -20,7 +20,8 @@
 #ifndef DATA_OUTPUT_INTERFACE_H
 #define DATA_OUTPUT_INTERFACE_H
 
-#include "ns3/data-calculator.h"
+#include "data-calculator.h"
+
 #include "ns3/nstime.h"
 #include "ns3/object.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/double-probe.cc ns-3.40/src/stats/model/double-probe.cc
--- ns-3.39/src/stats/model/double-probe.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/double-probe.cc	2023-09-27 13:30:37.878839700 -0700
@@ -20,7 +20,7 @@
  * Modified by: Mitch Watrous (watrous@u.washington.edu)
  */
 
-#include "ns3/double-probe.h"
+#include "double-probe.h"
 
 #include "ns3/config.h"
 #include "ns3/log.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/double-probe.h ns-3.40/src/stats/model/double-probe.h
--- ns-3.39/src/stats/model/double-probe.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/double-probe.h	2023-09-27 13:30:37.878839700 -0700
@@ -23,10 +23,11 @@
 #ifndef DOUBLE_PROBE_H
 #define DOUBLE_PROBE_H
 
+#include "probe.h"
+
 #include "ns3/boolean.h"
 #include "ns3/callback.h"
 #include "ns3/object.h"
-#include "ns3/probe.h"
 #include "ns3/simulator.h"
 #include "ns3/traced-value.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/file-aggregator.h ns-3.40/src/stats/model/file-aggregator.h
--- ns-3.39/src/stats/model/file-aggregator.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/file-aggregator.h	2023-09-27 13:30:37.878839700 -0700
@@ -23,7 +23,7 @@
 #ifndef FILE_AGGREGATOR_H
 #define FILE_AGGREGATOR_H
 
-#include "ns3/data-collection-object.h"
+#include "data-collection-object.h"
 
 #include <fstream>
 #include <map>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/gnuplot-aggregator.h ns-3.40/src/stats/model/gnuplot-aggregator.h
--- ns-3.39/src/stats/model/gnuplot-aggregator.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/gnuplot-aggregator.h	2023-09-27 13:30:37.878839700 -0700
@@ -23,8 +23,8 @@
 #ifndef GNUPLOT_AGGREGATOR_H
 #define GNUPLOT_AGGREGATOR_H
 
-#include "ns3/data-collection-object.h"
-#include "ns3/gnuplot.h"
+#include "data-collection-object.h"
+#include "gnuplot.h"
 
 #include <map>
 #include <string>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/gnuplot.cc ns-3.40/src/stats/model/gnuplot.cc
--- ns-3.39/src/stats/model/gnuplot.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/gnuplot.cc	2023-09-27 13:30:37.878839700 -0700
@@ -293,7 +293,7 @@
 void
 Gnuplot2dDataset::Data2d::PrintDataFile(std::ostream& os, bool generateOneOutputFile) const
 {
-    for (PointSet::const_iterator i = m_pointset.begin(); i != m_pointset.end(); ++i)
+    for (auto i = m_pointset.begin(); i != m_pointset.end(); ++i)
     {
         if (i->empty)
         {
@@ -578,7 +578,7 @@
 void
 Gnuplot3dDataset::Data3d::PrintDataFile(std::ostream& os, bool generateOneOutputFile) const
 {
-    for (PointSet::const_iterator i = m_pointset.begin(); i != m_pointset.end(); ++i)
+    for (auto i = m_pointset.begin(); i != m_pointset.end(); ++i)
     {
         if (i->empty)
         {
@@ -852,7 +852,7 @@
 
     std::string command = m_datasets.begin()->m_data->GetCommand();
 
-    for (Datasets::const_iterator i = m_datasets.begin() + 1; i != m_datasets.end(); ++i)
+    for (auto i = m_datasets.begin() + 1; i != m_datasets.end(); ++i)
     {
         NS_ASSERT_MSG(command == i->m_data->GetCommand(),
                       "Cannot mix 'plot' and 'splot' GnuplotDatasets.");
@@ -863,7 +863,7 @@
     // Print all dataset expressions
 
     bool isDataEmpty;
-    for (Datasets::const_iterator i = m_datasets.begin(); i != m_datasets.end();)
+    for (auto i = m_datasets.begin(); i != m_datasets.end();)
     {
         // Only print the dataset if it's not empty.
         isDataEmpty = i->m_data->IsEmpty();
@@ -889,7 +889,7 @@
 
     // followed by the inline datafile.
 
-    for (Datasets::const_iterator i = m_datasets.begin(); i != m_datasets.end(); i++)
+    for (auto i = m_datasets.begin(); i != m_datasets.end(); i++)
     {
         i->m_data->PrintDataFile(osData, m_generateOneOutputFile);
     }
@@ -950,7 +950,7 @@
         os << "set output \"" << m_outputFilename << "\"" << std::endl;
     }
 
-    for (Plots::iterator i = m_plots.begin(); i != m_plots.end(); ++i)
+    for (auto i = m_plots.begin(); i != m_plots.end(); ++i)
     {
         i->GenerateOutput(os);
     }
@@ -974,7 +974,7 @@
         osControl << "set output \"" << m_outputFilename << "\"" << std::endl;
     }
 
-    for (Plots::iterator i = m_plots.begin(); i != m_plots.end(); ++i)
+    for (auto i = m_plots.begin(); i != m_plots.end(); ++i)
     {
         i->GenerateOutput(osControl, osData, dataFileName);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/histogram.cc ns-3.40/src/stats/model/histogram.cc
--- ns-3.39/src/stats/model/histogram.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/histogram.cc	2023-09-27 13:30:37.878839700 -0700
@@ -80,7 +80,7 @@
 void
 Histogram::AddValue(double value)
 {
-    uint32_t index = (uint32_t)std::floor(value / m_binWidth);
+    auto index = (uint32_t)std::floor(value / m_binWidth);
 
     // check if we need to resize the vector
     NS_LOG_DEBUG("AddValue: index=" << index << ", m_histogram.size()=" << m_histogram.size());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/omnet-data-output.cc ns-3.40/src/stats/model/omnet-data-output.cc
--- ns-3.39/src/stats/model/omnet-data-output.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/omnet-data-output.cc	2023-09-27 13:30:37.878839700 -0700
@@ -75,7 +75,7 @@
     bool exponentSeen = false;
     char last = '\0';
 
-    for (std::string::const_iterator it = s.begin(); it != s.end(); it++)
+    for (auto it = s.begin(); it != s.end(); it++)
     {
         if ((*it == '.') && (decimalPtSeen))
         {
@@ -120,7 +120,7 @@
     scalarFile << "attr measurement \"" << dc.GetInputLabel() << "\"" << std::endl;
     scalarFile << "attr description \"" << dc.GetDescription() << "\"" << std::endl;
 
-    for (MetadataList::iterator i = dc.MetadataBegin(); i != dc.MetadataEnd(); i++)
+    for (auto i = dc.MetadataBegin(); i != dc.MetadataEnd(); i++)
     {
         std::pair<std::string, std::string> blob = (*i);
         scalarFile << "attr \"" << blob.first << "\" \"" << blob.second << "\"" << std::endl;
@@ -131,7 +131,7 @@
     {
         scalarFile << "scalar . measurement \"" << dc.GetInputLabel() << "\"" << std::endl;
     }
-    for (MetadataList::iterator i = dc.MetadataBegin(); i != dc.MetadataEnd(); i++)
+    for (auto i = dc.MetadataBegin(); i != dc.MetadataEnd(); i++)
     {
         std::pair<std::string, std::string> blob = (*i);
         if (isNumeric(blob.second))
@@ -142,8 +142,7 @@
     }
     OmnetOutputCallback callback(&scalarFile);
 
-    for (DataCalculatorList::iterator i = dc.DataCalculatorBegin(); i != dc.DataCalculatorEnd();
-         i++)
+    for (auto i = dc.DataCalculatorBegin(); i != dc.DataCalculatorEnd(); i++)
     {
         (*i)->Output(callback);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/probe.cc ns-3.40/src/stats/model/probe.cc
--- ns-3.39/src/stats/model/probe.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/probe.cc	2023-09-27 13:30:37.878839700 -0700
@@ -18,7 +18,7 @@
  *          Tiago G. Rodrigues (tgr002@bucknell.edu)
  */
 
-#include "ns3/probe.h"
+#include "probe.h"
 
 #include "ns3/log.h"
 #include "ns3/object.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/probe.h ns-3.40/src/stats/model/probe.h
--- ns-3.39/src/stats/model/probe.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/probe.h	2023-09-27 13:30:37.878839700 -0700
@@ -21,7 +21,8 @@
 #ifndef PROBE_H
 #define PROBE_H
 
-#include "ns3/data-collection-object.h"
+#include "data-collection-object.h"
+
 #include "ns3/nstime.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/sqlite-data-output.cc ns-3.40/src/stats/model/sqlite-data-output.cc
--- ns-3.39/src/stats/model/sqlite-data-output.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/sqlite-data-output.cc	2023-09-27 13:30:37.878839700 -0700
@@ -116,7 +116,7 @@
                                    "values (?, ?, ?)");
     NS_ASSERT(res);
 
-    for (MetadataList::iterator i = dc.MetadataBegin(); i != dc.MetadataEnd(); i++)
+    for (auto i = dc.MetadataBegin(); i != dc.MetadataEnd(); i++)
     {
         std::pair<std::string, std::string> blob = (*i);
         m_sqliteOut->SpinReset(stmt);
@@ -130,8 +130,7 @@
 
     m_sqliteOut->SpinExec("BEGIN");
     SqliteOutputCallback callback(m_sqliteOut, run);
-    for (DataCalculatorList::iterator i = dc.DataCalculatorBegin(); i != dc.DataCalculatorEnd();
-         i++)
+    for (auto i = dc.DataCalculatorBegin(); i != dc.DataCalculatorEnd(); i++)
     {
         (*i)->Output(callback);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/time-probe.cc ns-3.40/src/stats/model/time-probe.cc
--- ns-3.39/src/stats/model/time-probe.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/time-probe.cc	2023-09-27 13:30:37.878839700 -0700
@@ -21,7 +21,7 @@
  *
  */
 
-#include "ns3/time-probe.h"
+#include "time-probe.h"
 
 #include "ns3/config.h"
 #include "ns3/log.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/time-probe.h ns-3.40/src/stats/model/time-probe.h
--- ns-3.39/src/stats/model/time-probe.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/time-probe.h	2023-09-27 13:30:37.878839700 -0700
@@ -23,11 +23,12 @@
 #ifndef TIME_PROBE_H
 #define TIME_PROBE_H
 
+#include "probe.h"
+
 #include "ns3/boolean.h"
 #include "ns3/callback.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
-#include "ns3/probe.h"
 #include "ns3/simulator.h"
 #include "ns3/traced-value.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/time-series-adaptor.cc ns-3.40/src/stats/model/time-series-adaptor.cc
--- ns-3.39/src/stats/model/time-series-adaptor.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/time-series-adaptor.cc	2023-09-27 13:30:37.878839700 -0700
@@ -17,7 +17,7 @@
  * Author: Mitch Watrous (watrous@u.washington.edu)
  */
 
-#include "ns3/time-series-adaptor.h"
+#include "time-series-adaptor.h"
 
 #include "ns3/log.h"
 #include "ns3/object.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/time-series-adaptor.h ns-3.40/src/stats/model/time-series-adaptor.h
--- ns-3.39/src/stats/model/time-series-adaptor.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/time-series-adaptor.h	2023-09-27 13:30:37.878839700 -0700
@@ -20,7 +20,8 @@
 #ifndef TIME_SERIES_ADAPTOR_H
 #define TIME_SERIES_ADAPTOR_H
 
-#include "ns3/data-collection-object.h"
+#include "data-collection-object.h"
+
 #include "ns3/object.h"
 #include "ns3/traced-value.h"
 #include "ns3/type-id.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/uinteger-16-probe.cc ns-3.40/src/stats/model/uinteger-16-probe.cc
--- ns-3.39/src/stats/model/uinteger-16-probe.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/uinteger-16-probe.cc	2023-09-27 13:30:37.878839700 -0700
@@ -20,7 +20,7 @@
  * Modified by: Mitch Watrous (watrous@u.washington.edu)
  */
 
-#include "ns3/uinteger-16-probe.h"
+#include "uinteger-16-probe.h"
 
 #include "ns3/config.h"
 #include "ns3/log.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/uinteger-16-probe.h ns-3.40/src/stats/model/uinteger-16-probe.h
--- ns-3.39/src/stats/model/uinteger-16-probe.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/uinteger-16-probe.h	2023-09-27 13:30:37.878839700 -0700
@@ -23,8 +23,9 @@
 #ifndef UINTEGER_16_PROBE_H
 #define UINTEGER_16_PROBE_H
 
+#include "probe.h"
+
 #include "ns3/callback.h"
-#include "ns3/probe.h"
 #include "ns3/traced-value.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/uinteger-32-probe.cc ns-3.40/src/stats/model/uinteger-32-probe.cc
--- ns-3.39/src/stats/model/uinteger-32-probe.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/uinteger-32-probe.cc	2023-09-27 13:30:37.878839700 -0700
@@ -20,7 +20,7 @@
  * Modified by: Mitch Watrous (watrous@u.washington.edu)
  */
 
-#include "ns3/uinteger-32-probe.h"
+#include "uinteger-32-probe.h"
 
 #include "ns3/config.h"
 #include "ns3/log.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/uinteger-32-probe.h ns-3.40/src/stats/model/uinteger-32-probe.h
--- ns-3.39/src/stats/model/uinteger-32-probe.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/uinteger-32-probe.h	2023-09-27 13:30:37.878839700 -0700
@@ -23,8 +23,9 @@
 #ifndef UINTEGER_32_PROBE_H
 #define UINTEGER_32_PROBE_H
 
+#include "probe.h"
+
 #include "ns3/callback.h"
-#include "ns3/probe.h"
 #include "ns3/traced-value.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/uinteger-8-probe.cc ns-3.40/src/stats/model/uinteger-8-probe.cc
--- ns-3.39/src/stats/model/uinteger-8-probe.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/uinteger-8-probe.cc	2023-09-27 13:30:37.878839700 -0700
@@ -20,7 +20,7 @@
  * Modified by: Mitch Watrous (watrous@u.washington.edu)
  */
 
-#include "ns3/uinteger-8-probe.h"
+#include "uinteger-8-probe.h"
 
 #include "ns3/config.h"
 #include "ns3/log.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/stats/model/uinteger-8-probe.h ns-3.40/src/stats/model/uinteger-8-probe.h
--- ns-3.39/src/stats/model/uinteger-8-probe.h	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/stats/model/uinteger-8-probe.h	2023-09-27 13:30:37.878839700 -0700
@@ -23,8 +23,9 @@
 #ifndef UINTEGER_8_PROBE_H
 #define UINTEGER_8_PROBE_H
 
+#include "probe.h"
+
 #include "ns3/callback.h"
-#include "ns3/probe.h"
 #include "ns3/traced-value.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/tap-bridge/model/tap-bridge.cc ns-3.40/src/tap-bridge/model/tap-bridge.cc
--- ns-3.39/src/tap-bridge/model/tap-bridge.cc	2023-07-05 14:23:48.085428200 -0700
+++ ns-3.40/src/tap-bridge/model/tap-bridge.cc	2023-09-27 13:30:37.882839700 -0700
@@ -57,7 +57,7 @@
     NS_LOG_FUNCTION(this);
 
     uint32_t bufferSize = 65536;
-    uint8_t* buf = (uint8_t*)std::malloc(bufferSize);
+    auto buf = (uint8_t*)std::malloc(bufferSize);
     NS_ABORT_MSG_IF(buf == nullptr, "malloc() failed");
 
     NS_LOG_LOGIC("Calling read on tap device fd " << m_fd);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/test/csma-system-test-suite.cc ns-3.40/src/test/csma-system-test-suite.cc
--- ns-3.39/src/test/csma-system-test-suite.cc	2023-07-05 14:23:48.089428200 -0700
+++ ns-3.40/src/test/csma-system-test-suite.cc	2023-09-27 13:30:37.882839700 -0700
@@ -870,7 +870,7 @@
     // Make packets be sent about every DefaultPacketSize / DataRate =
     // 4096 bits / (5000 bits/second) = 0.82 second.
     Config::SetDefault("ns3::Ipv4RawSocketImpl::Protocol", StringValue("2"));
-    InetSocketAddress dst = InetSocketAddress(addresses.GetAddress(3));
+    InetSocketAddress dst(addresses.GetAddress(3));
     OnOffHelper onoff = OnOffHelper("ns3::Ipv4RawSocketFactory", dst);
     onoff.SetConstantRate(DataRate(5000));
 
@@ -1004,7 +1004,7 @@
     // Make packets be sent about every DefaultPacketSize / DataRate =
     // 4096 bits / (5000 bits/second) = 0.82 second.
     Config::SetDefault("ns3::Ipv4RawSocketImpl::Protocol", StringValue("2"));
-    InetSocketAddress dst = InetSocketAddress(addresses.GetAddress(3));
+    InetSocketAddress dst(addresses.GetAddress(3));
     OnOffHelper onoff = OnOffHelper("ns3::Ipv4RawSocketFactory", dst);
     onoff.SetConstantRate(DataRate(5000));
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/test/ns3tc/pfifo-fast-queue-disc-test-suite.cc ns-3.40/src/test/ns3tc/pfifo-fast-queue-disc-test-suite.cc
--- ns-3.39/src/test/ns3tc/pfifo-fast-queue-disc-test-suite.cc	2023-07-05 14:23:48.089428200 -0700
+++ ns-3.40/src/test/ns3tc/pfifo-fast-queue-disc-test-suite.cc	2023-09-27 13:30:37.882839700 -0700
@@ -369,7 +369,7 @@
                           2,
                           "unexpected queue depth");
     p = Create<Packet>(100);
-    uint8_t* buf = new uint8_t[100];
+    auto buf = new uint8_t[100];
     uint8_t counter = 0;
     for (uint32_t i = 0; i < 100; i++)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/test/ns3tcp/ns3tcp-loss-test-suite.cc ns-3.40/src/test/ns3tcp/ns3tcp-loss-test-suite.cc
--- ns-3.39/src/test/ns3tcp/ns3tcp-loss-test-suite.cc	2023-07-05 14:23:48.089428200 -0700
+++ ns-3.40/src/test/ns3tcp/ns3tcp-loss-test-suite.cc	2023-09-27 13:30:37.882839700 -0700
@@ -246,7 +246,7 @@
 
         NS_LOG_INFO("read " << readLen << " bytes");
 
-        uint8_t* actual = new uint8_t[readLen];
+        auto actual = new uint8_t[readLen];
         received->CopyData(actual, readLen);
 
         int result = memcmp(actual, expectedBuffer, readLen);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/test/ns3tcp/ns3tcp-state-test-suite.cc ns-3.40/src/test/ns3tcp/ns3tcp-state-test-suite.cc
--- ns-3.39/src/test/ns3tcp/ns3tcp-state-test-suite.cc	2023-07-05 14:23:48.089428200 -0700
+++ ns-3.40/src/test/ns3tcp/ns3tcp-state-test-suite.cc	2023-09-27 13:30:37.882839700 -0700
@@ -252,7 +252,7 @@
 
         NS_LOG_INFO("read " << readLen << " bytes");
 
-        uint8_t* actual = new uint8_t[readLen];
+        auto actual = new uint8_t[readLen];
         received->CopyData(actual, readLen);
 
         int result = memcmp(actual, expectedBuffer, readLen);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/topology-read/examples/topology-example-sim.cc ns-3.40/src/topology-read/examples/topology-example-sim.cc
--- ns-3.39/src/topology-read/examples/topology-example-sim.cc	2023-07-05 14:23:48.089428200 -0700
+++ ns-3.40/src/topology-read/examples/topology-example-sim.cc	2023-09-27 13:30:37.886839600 -0700
@@ -122,7 +122,7 @@
     int totlinks = inFile->LinksSize();
 
     NS_LOG_INFO("creating node containers");
-    NodeContainer* nc = new NodeContainer[totlinks];
+    auto nc = new NodeContainer[totlinks];
     TopologyReader::ConstLinksIterator iter;
     int i = 0;
     for (iter = inFile->LinksBegin(); iter != inFile->LinksEnd(); iter++, i++)
@@ -131,7 +131,7 @@
     }
 
     NS_LOG_INFO("creating net device containers");
-    NetDeviceContainer* ndc = new NetDeviceContainer[totlinks];
+    auto ndc = new NetDeviceContainer[totlinks];
     PointToPointHelper p2p;
     for (int i = 0; i < totlinks; i++)
     {
@@ -143,7 +143,7 @@
 
     // it crates little subnets, one for each couple of nodes.
     NS_LOG_INFO("creating IPv4 interfaces");
-    Ipv4InterfaceContainer* ipic = new Ipv4InterfaceContainer[totlinks];
+    auto ipic = new Ipv4InterfaceContainer[totlinks];
     for (int i = 0; i < totlinks; i++)
     {
         ipic[i] = address.Assign(ndc[i]);
@@ -166,7 +166,7 @@
     // -- Send around packets to check the ttl
     // --------------------------------------------
     Config::SetDefault("ns3::Ipv4RawSocketImpl::Protocol", StringValue("2"));
-    InetSocketAddress dst = InetSocketAddress(ipv4AddrServer);
+    InetSocketAddress dst(ipv4AddrServer);
 
     OnOffHelper onoff = OnOffHelper("ns3::Ipv4RawSocketFactory", dst);
     onoff.SetConstantRate(DataRate(15000));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/topology-read/helper/topology-reader-helper.cc ns-3.40/src/topology-read/helper/topology-reader-helper.cc
--- ns-3.39/src/topology-read/helper/topology-reader-helper.cc	2023-07-05 14:23:48.089428200 -0700
+++ ns-3.40/src/topology-read/helper/topology-reader-helper.cc	2023-09-27 13:30:37.886839600 -0700
@@ -18,7 +18,7 @@
  * Author: Valerio Sartini (valesar@gmail.com)
  */
 
-#include "ns3/topology-reader-helper.h"
+#include "topology-reader-helper.h"
 
 #include "ns3/inet-topology-reader.h"
 #include "ns3/log.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/topology-read/model/rocketfuel-topology-reader.cc ns-3.40/src/topology-read/model/rocketfuel-topology-reader.cc
--- ns-3.39/src/topology-read/model/rocketfuel-topology-reader.cc	2023-07-05 14:23:48.089428200 -0700
+++ ns-3.40/src/topology-read/model/rocketfuel-topology-reader.cc	2023-09-27 13:30:37.886839600 -0700
@@ -322,19 +322,15 @@
 RocketfuelTopologyReader::RF_FileType
 RocketfuelTopologyReader::GetFileType(const std::string& line)
 {
-    int ret;
-
     // Check whether Maps file or not
     std::smatch matches;
-    ret = std::regex_match(line, matches, rocketfuel_maps_regex);
-    if (ret)
+    if (std::regex_match(line, matches, rocketfuel_maps_regex))
     {
         return RF_MAPS;
     }
 
     // Check whether Weights file or not
-    ret = std::regex_match(line, matches, rocketfuel_weights_regex);
-    if (ret)
+    if (std::regex_match(line, matches, rocketfuel_weights_regex))
     {
         return RF_WEIGHTS;
     }
@@ -362,7 +358,6 @@
 
     while (!topgen.eof())
     {
-        int ret;
         std::vector<std::string> argv;
 
         lineNumber++;
@@ -385,7 +380,7 @@
 
         if (ftype == RF_MAPS)
         {
-            ret = std::regex_match(line, matches, rocketfuel_maps_regex);
+            bool ret = std::regex_match(line, matches, rocketfuel_maps_regex);
             if (!ret || matches.empty())
             {
                 NS_LOG_WARN("match failed (maps file): %s" << line);
@@ -394,7 +389,7 @@
         }
         else if (ftype == RF_WEIGHTS)
         {
-            ret = std::regex_match(line, matches, rocketfuel_weights_regex);
+            bool ret = std::regex_match(line, matches, rocketfuel_weights_regex);
             if (!ret || matches.empty())
             {
                 NS_LOG_WARN("match failed (weights file): %s" << line);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/CMakeLists.txt ns-3.40/src/traffic-control/CMakeLists.txt
--- ns-3.39/src/traffic-control/CMakeLists.txt	2023-07-05 14:23:48.089428200 -0700
+++ ns-3.40/src/traffic-control/CMakeLists.txt	2023-09-27 13:30:37.886839600 -0700
@@ -36,8 +36,9 @@
     model/red-queue-disc.h
     model/tbf-queue-disc.h
     model/traffic-control-layer.h
-  LIBRARIES_TO_LINK ${libnetwork}
-                    ${libcore}
+  LIBRARIES_TO_LINK
+    ${libnetwork}
+    ${libcore}
   TEST_SOURCES
     test/adaptive-red-queue-disc-test-suite.cc
     test/cobalt-queue-disc-test-suite.cc
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/helper/queue-disc-container.cc ns-3.40/src/traffic-control/helper/queue-disc-container.cc
--- ns-3.39/src/traffic-control/helper/queue-disc-container.cc	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/helper/queue-disc-container.cc	2023-09-27 13:30:37.886839600 -0700
@@ -58,7 +58,7 @@
 void
 QueueDiscContainer::Add(QueueDiscContainer other)
 {
-    for (ConstIterator i = other.Begin(); i != other.End(); i++)
+    for (auto i = other.Begin(); i != other.End(); i++)
     {
         m_queueDiscs.push_back(*i);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/helper/traffic-control-helper.cc ns-3.40/src/traffic-control/helper/traffic-control-helper.cc
--- ns-3.39/src/traffic-control/helper/traffic-control-helper.cc	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/helper/traffic-control-helper.cc	2023-09-27 13:30:37.886839600 -0700
@@ -71,17 +71,13 @@
     Ptr<QueueDisc> qd = m_queueDiscFactory.Create<QueueDisc>();
 
     // create and add the internal queues
-    for (std::vector<ObjectFactory>::iterator i = m_internalQueuesFactory.begin();
-         i != m_internalQueuesFactory.end();
-         i++)
+    for (auto i = m_internalQueuesFactory.begin(); i != m_internalQueuesFactory.end(); i++)
     {
         qd->AddInternalQueue(i->Create<QueueDisc::InternalQueue>());
     }
 
     // create and add the packet filters
-    for (std::vector<ObjectFactory>::iterator i = m_packetFiltersFactory.begin();
-         i != m_packetFiltersFactory.end();
-         i++)
+    for (auto i = m_packetFiltersFactory.begin(); i != m_packetFiltersFactory.end(); i++)
     {
         qd->AddPacketFilter(i->Create<PacketFilter>());
     }
@@ -182,7 +178,7 @@
     NS_ABORT_MSG_IF(handle >= m_queueDiscFactory.size(),
                     "A queue disc with handle " << handle << " does not exist");
 
-    uint16_t childHandle = static_cast<uint16_t>(m_queueDiscFactory.size());
+    auto childHandle = static_cast<uint16_t>(m_queueDiscFactory.size());
     m_queueDiscFactory.emplace_back(factory);
     m_queueDiscFactory[handle].SetChildQueueDisc(classId, childHandle);
 
@@ -195,7 +191,7 @@
                                            ObjectFactory factory)
 {
     HandleList list;
-    for (ClassIdList::const_iterator c = classes.begin(); c != classes.end(); c++)
+    for (auto c = classes.begin(); c != classes.end(); c++)
     {
         uint16_t childHandle = DoAddChildQueueDisc(handle, *c, factory);
         list.push_back(childHandle);
@@ -254,7 +250,7 @@
 {
     QueueDiscContainer container;
 
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         container.Add(Install(*i));
     }
@@ -283,7 +279,7 @@
 void
 TrafficControlHelper::Uninstall(NetDeviceContainer c)
 {
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         Uninstall(*i);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/helper/traffic-control-helper.h ns-3.40/src/traffic-control/helper/traffic-control-helper.h
--- ns-3.39/src/traffic-control/helper/traffic-control-helper.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/helper/traffic-control-helper.h	2023-09-27 13:30:37.886839600 -0700
@@ -19,9 +19,10 @@
 #ifndef TRAFFIC_CONTROL_HELPER_H
 #define TRAFFIC_CONTROL_HELPER_H
 
+#include "queue-disc-container.h"
+
 #include "ns3/net-device-container.h"
 #include "ns3/object-factory.h"
-#include "ns3/queue-disc-container.h"
 #include "ns3/queue.h"
 
 #include <map>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/cobalt-queue-disc.cc ns-3.40/src/traffic-control/model/cobalt-queue-disc.cc
--- ns-3.39/src/traffic-control/model/cobalt-queue-disc.cc	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/cobalt-queue-disc.cc	2023-09-27 13:30:37.886839600 -0700
@@ -359,7 +359,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    while (1)
+    while (true)
     {
         Ptr<QueueDiscItem> item = GetInternalQueue(0)->Dequeue();
         if (!item)
@@ -542,7 +542,7 @@
     if (m_pDrop)
     {
         double u = m_uv->GetValue();
-        drop = drop | (u < m_pDrop);
+        drop = drop || (u < m_pDrop);
     }
 
     /* Overload the drop_next field as an activity timeout */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/cobalt-queue-disc.h ns-3.40/src/traffic-control/model/cobalt-queue-disc.h
--- ns-3.39/src/traffic-control/model/cobalt-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/cobalt-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -28,10 +28,11 @@
 #ifndef COBALT_H
 #define COBALT_H
 
+#include "queue-disc.h"
+
 #include "ns3/boolean.h"
 #include "ns3/data-rate.h"
 #include "ns3/nstime.h"
-#include "ns3/queue-disc.h"
 #include "ns3/random-variable-stream.h"
 #include "ns3/simulator.h"
 #include "ns3/string.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/codel-queue-disc.h ns-3.40/src/traffic-control/model/codel-queue-disc.h
--- ns-3.39/src/traffic-control/model/codel-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/codel-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -27,8 +27,9 @@
 #ifndef CODEL_H
 #define CODEL_H
 
+#include "queue-disc.h"
+
 #include "ns3/nstime.h"
-#include "ns3/queue-disc.h"
 #include "ns3/simulator.h"
 #include "ns3/string.h"
 #include "ns3/trace-source-accessor.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/fifo-queue-disc.h ns-3.40/src/traffic-control/model/fifo-queue-disc.h
--- ns-3.39/src/traffic-control/model/fifo-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/fifo-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -20,7 +20,7 @@
 #ifndef FIFO_QUEUE_DISC_H
 #define FIFO_QUEUE_DISC_H
 
-#include "ns3/queue-disc.h"
+#include "queue-disc.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/fq-cobalt-queue-disc.h ns-3.40/src/traffic-control/model/fq-cobalt-queue-disc.h
--- ns-3.39/src/traffic-control/model/fq-cobalt-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/fq-cobalt-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -27,8 +27,9 @@
 #ifndef FQ_COBALT_QUEUE_DISC
 #define FQ_COBALT_QUEUE_DISC
 
+#include "queue-disc.h"
+
 #include "ns3/object-factory.h"
-#include "ns3/queue-disc.h"
 
 #include <list>
 #include <map>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/fq-codel-queue-disc.h ns-3.40/src/traffic-control/model/fq-codel-queue-disc.h
--- ns-3.39/src/traffic-control/model/fq-codel-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/fq-codel-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -21,8 +21,9 @@
 #ifndef FQ_CODEL_QUEUE_DISC
 #define FQ_CODEL_QUEUE_DISC
 
+#include "queue-disc.h"
+
 #include "ns3/object-factory.h"
-#include "ns3/queue-disc.h"
 
 #include <list>
 #include <map>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/fq-pie-queue-disc.h ns-3.40/src/traffic-control/model/fq-pie-queue-disc.h
--- ns-3.39/src/traffic-control/model/fq-pie-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/fq-pie-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -26,8 +26,9 @@
 #ifndef FQ_PIE_QUEUE_DISC
 #define FQ_PIE_QUEUE_DISC
 
+#include "queue-disc.h"
+
 #include "ns3/object-factory.h"
-#include "ns3/queue-disc.h"
 
 #include <list>
 #include <map>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/mq-queue-disc.h ns-3.40/src/traffic-control/model/mq-queue-disc.h
--- ns-3.39/src/traffic-control/model/mq-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/mq-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -21,7 +21,7 @@
 #ifndef MQ_QUEUE_DISC_H
 #define MQ_QUEUE_DISC_H
 
-#include "ns3/queue-disc.h"
+#include "queue-disc.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/pfifo-fast-queue-disc.h ns-3.40/src/traffic-control/model/pfifo-fast-queue-disc.h
--- ns-3.39/src/traffic-control/model/pfifo-fast-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/pfifo-fast-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -22,7 +22,7 @@
 #ifndef PFIFO_FAST_H
 #define PFIFO_FAST_H
 
-#include "ns3/queue-disc.h"
+#include "queue-disc.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/pie-queue-disc.cc ns-3.40/src/traffic-control/model/pie-queue-disc.cc
--- ns-3.39/src/traffic-control/model/pie-queue-disc.cc	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/pie-queue-disc.cc	2023-09-27 13:30:37.886839600 -0700
@@ -437,7 +437,7 @@
         m_burstAllowance -= m_tUpdate;
     }
 
-    uint32_t burstResetLimit = static_cast<uint32_t>(BURST_RESET_TIMEOUT / m_tUpdate.GetSeconds());
+    auto burstResetLimit = static_cast<uint32_t>(BURST_RESET_TIMEOUT / m_tUpdate.GetSeconds());
     if ((qDelay.GetSeconds() < 0.5 * m_qDelayRef.GetSeconds()) &&
         (m_qDelayOld.GetSeconds() < (0.5 * m_qDelayRef.GetSeconds())) && (m_dropProb == 0) &&
         !missingInitFlag)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/pie-queue-disc.h ns-3.40/src/traffic-control/model/pie-queue-disc.h
--- ns-3.39/src/traffic-control/model/pie-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/pie-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -27,11 +27,12 @@
 #ifndef PIE_QUEUE_DISC_H
 #define PIE_QUEUE_DISC_H
 
+#include "queue-disc.h"
+
 #include "ns3/boolean.h"
 #include "ns3/data-rate.h"
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
-#include "ns3/queue-disc.h"
 #include "ns3/random-variable-stream.h"
 #include "ns3/timer.h"
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/prio-queue-disc.h ns-3.40/src/traffic-control/model/prio-queue-disc.h
--- ns-3.39/src/traffic-control/model/prio-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/prio-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -20,7 +20,7 @@
 #ifndef PRIO_QUEUE_DISC_H
 #define PRIO_QUEUE_DISC_H
 
-#include "ns3/queue-disc.h"
+#include "queue-disc.h"
 
 #include <array>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/queue-disc.cc ns-3.40/src/traffic-control/model/queue-disc.cc
--- ns-3.39/src/traffic-control/model/queue-disc.cc	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/queue-disc.cc	2023-09-27 13:30:37.886839600 -0700
@@ -178,9 +178,6 @@
 void
 QueueDisc::Stats::Print(std::ostream& os) const
 {
-    std::map<std::string, uint32_t>::const_iterator itp;
-    std::map<std::string, uint64_t>::const_iterator itb;
-
     os << std::endl
        << "Packets/Bytes received: " << nTotalReceivedPackets << " / " << nTotalReceivedBytes
        << std::endl
@@ -195,8 +192,8 @@
        << "Packets/Bytes dropped before enqueue: " << nTotalDroppedPacketsBeforeEnqueue << " / "
        << nTotalDroppedBytesBeforeEnqueue;
 
-    itp = nDroppedPacketsBeforeEnqueue.begin();
-    itb = nDroppedBytesBeforeEnqueue.begin();
+    auto itp = nDroppedPacketsBeforeEnqueue.begin();
+    auto itb = nDroppedBytesBeforeEnqueue.begin();
 
     while (itp != nDroppedPacketsBeforeEnqueue.end() && itb != nDroppedBytesBeforeEnqueue.end())
     {
@@ -403,8 +400,7 @@
     InitializeParams();
 
     // Check the configuration and initialize the parameters of the child queue discs
-    for (std::vector<Ptr<QueueDiscClass>>::iterator cl = m_classes.begin(); cl != m_classes.end();
-         cl++)
+    for (auto cl = m_classes.begin(); cl != m_classes.end(); cl++)
     {
         (*cl)->GetQueueDisc()->Initialize();
     }
@@ -673,9 +669,7 @@
     NS_LOG_FUNCTION(this << item);
 
     int32_t ret = PacketFilter::PF_NO_MATCH;
-    for (std::vector<Ptr<PacketFilter>>::iterator f = m_filters.begin();
-         f != m_filters.end() && ret == PacketFilter::PF_NO_MATCH;
-         f++)
+    for (auto f = m_filters.begin(); f != m_filters.end() && ret == PacketFilter::PF_NO_MATCH; f++)
     {
         ret = (*f)->Classify(item);
     }
@@ -733,8 +727,7 @@
     m_stats.nTotalDroppedBytesBeforeEnqueue += item->GetSize();
 
     // update the number of packets dropped for the given reason
-    std::map<std::string, uint32_t>::iterator itp =
-        m_stats.nDroppedPacketsBeforeEnqueue.find(reason);
+    auto itp = m_stats.nDroppedPacketsBeforeEnqueue.find(reason);
     if (itp != m_stats.nDroppedPacketsBeforeEnqueue.end())
     {
         itp->second++;
@@ -744,7 +737,7 @@
         m_stats.nDroppedPacketsBeforeEnqueue[reason] = 1;
     }
     // update the amount of bytes dropped for the given reason
-    std::map<std::string, uint64_t>::iterator itb = m_stats.nDroppedBytesBeforeEnqueue.find(reason);
+    auto itb = m_stats.nDroppedBytesBeforeEnqueue.find(reason);
     if (itb != m_stats.nDroppedBytesBeforeEnqueue.end())
     {
         itb->second += item->GetSize();
@@ -773,8 +766,7 @@
     m_stats.nTotalDroppedBytesAfterDequeue += item->GetSize();
 
     // update the number of packets dropped for the given reason
-    std::map<std::string, uint32_t>::iterator itp =
-        m_stats.nDroppedPacketsAfterDequeue.find(reason);
+    auto itp = m_stats.nDroppedPacketsAfterDequeue.find(reason);
     if (itp != m_stats.nDroppedPacketsAfterDequeue.end())
     {
         itp->second++;
@@ -784,7 +776,7 @@
         m_stats.nDroppedPacketsAfterDequeue[reason] = 1;
     }
     // update the amount of bytes dropped for the given reason
-    std::map<std::string, uint64_t>::iterator itb = m_stats.nDroppedBytesAfterDequeue.find(reason);
+    auto itb = m_stats.nDroppedBytesAfterDequeue.find(reason);
     if (itb != m_stats.nDroppedBytesAfterDequeue.end())
     {
         itb->second += item->GetSize();
@@ -829,7 +821,7 @@
     m_stats.nTotalMarkedBytes += item->GetSize();
 
     // update the number of packets marked for the given reason
-    std::map<std::string, uint32_t>::iterator itp = m_stats.nMarkedPackets.find(reason);
+    auto itp = m_stats.nMarkedPackets.find(reason);
     if (itp != m_stats.nMarkedPackets.end())
     {
         itp->second++;
@@ -839,7 +831,7 @@
         m_stats.nMarkedPackets[reason] = 1;
     }
     // update the amount of bytes marked for the given reason
-    std::map<std::string, uint64_t>::iterator itb = m_stats.nMarkedBytes.find(reason);
+    auto itb = m_stats.nMarkedBytes.find(reason);
     if (itb != m_stats.nMarkedBytes.end())
     {
         itb->second += item->GetSize();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/red-queue-disc.cc ns-3.40/src/traffic-control/model/red-queue-disc.cc
--- ns-3.39/src/traffic-control/model/red-queue-disc.cc	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/red-queue-disc.cc	2023-09-27 13:30:37.886839600 -0700
@@ -763,7 +763,7 @@
 RedQueueDisc::ModifyP(double p, uint32_t size)
 {
     NS_LOG_FUNCTION(this << p << size);
-    double count1 = (double)m_count;
+    auto count1 = (double)m_count;
 
     if (GetMaxSize().GetUnit() == QueueSizeUnit::BYTES)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/red-queue-disc.h ns-3.40/src/traffic-control/model/red-queue-disc.h
--- ns-3.39/src/traffic-control/model/red-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/red-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -60,10 +60,11 @@
 #ifndef RED_QUEUE_DISC_H
 #define RED_QUEUE_DISC_H
 
+#include "queue-disc.h"
+
 #include "ns3/boolean.h"
 #include "ns3/data-rate.h"
 #include "ns3/nstime.h"
-#include "ns3/queue-disc.h"
 #include "ns3/random-variable-stream.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/tbf-queue-disc.h ns-3.40/src/traffic-control/model/tbf-queue-disc.h
--- ns-3.39/src/traffic-control/model/tbf-queue-disc.h	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/tbf-queue-disc.h	2023-09-27 13:30:37.886839600 -0700
@@ -28,11 +28,12 @@
 #ifndef TBF_QUEUE_DISC_H
 #define TBF_QUEUE_DISC_H
 
+#include "queue-disc.h"
+
 #include "ns3/boolean.h"
 #include "ns3/data-rate.h"
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
-#include "ns3/queue-disc.h"
 #include "ns3/random-variable-stream.h"
 #include "ns3/trace-source-accessor.h"
 #include "ns3/traced-value.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/traffic-control/model/traffic-control-layer.cc ns-3.40/src/traffic-control/model/traffic-control-layer.cc
--- ns-3.39/src/traffic-control/model/traffic-control-layer.cc	2023-07-05 14:23:48.093428400 -0700
+++ ns-3.40/src/traffic-control/model/traffic-control-layer.cc	2023-09-27 13:30:37.886839600 -0700
@@ -18,11 +18,12 @@
 
 #include "traffic-control-layer.h"
 
+#include "queue-disc.h"
+
 #include "ns3/log.h"
 #include "ns3/net-device-queue-interface.h"
 #include "ns3/object-map.h"
 #include "ns3/packet.h"
-#include "ns3/queue-disc.h"
 #include "ns3/socket.h"
 
 #include <tuple>
@@ -142,7 +143,7 @@
         Ptr<NetDeviceQueueInterface> ndqi = dev->GetObject<NetDeviceQueueInterface>();
         NS_LOG_DEBUG("Pointer to NetDeviceQueueInterface: " << ndqi);
 
-        std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find(dev);
+        auto ndi = m_netDevices.find(dev);
 
         if (ndi != m_netDevices.end())
         {
@@ -221,7 +222,7 @@
 {
     NS_LOG_FUNCTION(this << device << qDisc);
 
-    std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find(device);
+    auto ndi = m_netDevices.find(device);
 
     if (ndi == m_netDevices.end())
     {
@@ -243,7 +244,7 @@
 {
     NS_LOG_FUNCTION(this << device);
 
-    std::map<Ptr<NetDevice>, NetDeviceInfo>::const_iterator ndi = m_netDevices.find(device);
+    auto ndi = m_netDevices.find(device);
 
     if (ndi == m_netDevices.end())
     {
@@ -264,7 +265,7 @@
 {
     NS_LOG_FUNCTION(this << device);
 
-    std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find(device);
+    auto ndi = m_netDevices.find(device);
 
     NS_ASSERT_MSG(ndi != m_netDevices.end() && ndi->second.m_rootQueueDisc,
                   "No root queue disc installed on device " << device);
@@ -336,7 +337,7 @@
 
     bool found = false;
 
-    for (ProtocolHandlerList::iterator i = m_handlers.begin(); i != m_handlers.end(); i++)
+    for (auto i = m_handlers.begin(); i != m_handlers.end(); i++)
     {
         if (!i->device || (i->device == device))
         {
@@ -364,7 +365,7 @@
     NS_LOG_DEBUG("Send packet to device " << device << " protocol number " << item->GetProtocol());
 
     Ptr<NetDeviceQueueInterface> devQueueIface;
-    std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find(device);
+    auto ndi = m_netDevices.find(device);
 
     if (ndi != m_netDevices.end())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/examples/uan-6lowpan-example.cc ns-3.40/src/uan/examples/uan-6lowpan-example.cc
--- ns-3.39/src/uan/examples/uan-6lowpan-example.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/examples/uan-6lowpan-example.cc	2023-09-27 13:30:37.890839800 -0700
@@ -131,7 +131,7 @@
     UanHelper uanHelper;
     NetDeviceContainer netDeviceContainer = uanHelper.Install(m_nodes, channel);
     EnergySourceContainer energySourceContainer;
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     while (node != m_nodes.End())
     {
         energySourceContainer.Add((*node)->GetObject<EnergySourceContainer>()->Get(0));
@@ -185,7 +185,7 @@
 void
 UanExperiment::SetupApplications()
 {
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     while (node != m_nodes.End())
     {
         m_sockets[*node] =
@@ -206,7 +206,7 @@
 {
     Ptr<UniformRandomVariable> uniformRandomVariable = CreateObject<UniformRandomVariable>();
 
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     Ipv6Address dst =
         (*node)->GetObject<Ipv6L3Protocol>()->GetInterface(1)->GetAddress(1).GetAddress();
     node++;
@@ -247,9 +247,7 @@
 void
 UanExperiment::Teardown()
 {
-    std::map<Ptr<Node>, Ptr<Socket>>::iterator socket;
-
-    for (socket = m_sockets.begin(); socket != m_sockets.end(); socket++)
+    for (auto socket = m_sockets.begin(); socket != m_sockets.end(); socket++)
     {
         socket->second->Close();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/examples/uan-cw-example.cc ns-3.40/src/uan/examples/uan-cw-example.cc
--- ns-3.39/src/uan/examples/uan-cw-example.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/examples/uan-cw-example.cc	2023-09-27 13:30:37.890839800 -0700
@@ -106,7 +106,7 @@
 Experiment::UpdatePositions(NodeContainer& nodes) const
 {
     NS_LOG_DEBUG(Now().As(Time::S) << " Updating positions");
-    NodeContainer::Iterator it = nodes.Begin();
+    auto it = nodes.Begin();
     Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable>();
     for (; it != nodes.End(); it++)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/examples/uan-ipv4-example.cc ns-3.40/src/uan/examples/uan-ipv4-example.cc
--- ns-3.39/src/uan/examples/uan-ipv4-example.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/examples/uan-ipv4-example.cc	2023-09-27 13:30:37.890839800 -0700
@@ -129,7 +129,7 @@
     UanHelper uanHelper;
     NetDeviceContainer netDeviceContainer = uanHelper.Install(m_nodes, channel);
     EnergySourceContainer energySourceContainer;
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     while (node != m_nodes.End())
     {
         energySourceContainer.Add((*node)->GetObject<EnergySourceContainer>()->Get(0));
@@ -176,7 +176,7 @@
 void
 UanExperiment::SetupApplications()
 {
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     while (node != m_nodes.End())
     {
         m_sockets[*node] =
@@ -197,7 +197,7 @@
 {
     Ptr<UniformRandomVariable> uniformRandomVariable = CreateObject<UniformRandomVariable>();
 
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     Ipv4Address dst =
         (*node)->GetObject<Ipv4L3Protocol>()->GetInterface(1)->GetAddress(0).GetLocal();
     node++;
@@ -238,9 +238,7 @@
 void
 UanExperiment::Teardown()
 {
-    std::map<Ptr<Node>, Ptr<Socket>>::iterator socket;
-
-    for (socket = m_sockets.begin(); socket != m_sockets.end(); socket++)
+    for (auto socket = m_sockets.begin(); socket != m_sockets.end(); socket++)
     {
         socket->second->Close();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/examples/uan-ipv6-example.cc ns-3.40/src/uan/examples/uan-ipv6-example.cc
--- ns-3.39/src/uan/examples/uan-ipv6-example.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/examples/uan-ipv6-example.cc	2023-09-27 13:30:37.890839800 -0700
@@ -129,7 +129,7 @@
     UanHelper uanHelper;
     NetDeviceContainer netDeviceContainer = uanHelper.Install(m_nodes, channel);
     EnergySourceContainer energySourceContainer;
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     while (node != m_nodes.End())
     {
         energySourceContainer.Add((*node)->GetObject<EnergySourceContainer>()->Get(0));
@@ -180,7 +180,7 @@
 void
 UanExperiment::SetupApplications()
 {
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     while (node != m_nodes.End())
     {
         m_sockets[*node] =
@@ -201,7 +201,7 @@
 {
     Ptr<UniformRandomVariable> uniformRandomVariable = CreateObject<UniformRandomVariable>();
 
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     Ipv6Address dst =
         (*node)->GetObject<Ipv6L3Protocol>()->GetInterface(1)->GetAddress(1).GetAddress();
     node++;
@@ -242,9 +242,7 @@
 void
 UanExperiment::Teardown()
 {
-    std::map<Ptr<Node>, Ptr<Socket>>::iterator socket;
-
-    for (socket = m_sockets.begin(); socket != m_sockets.end(); socket++)
+    for (auto socket = m_sockets.begin(); socket != m_sockets.end(); socket++)
     {
         socket->second->Close();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/examples/uan-raw-example.cc ns-3.40/src/uan/examples/uan-raw-example.cc
--- ns-3.39/src/uan/examples/uan-raw-example.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/examples/uan-raw-example.cc	2023-09-27 13:30:37.890839800 -0700
@@ -131,7 +131,7 @@
     UanHelper uanHelper;
     NetDeviceContainer netDeviceContainer = uanHelper.Install(m_nodes, channel);
     EnergySourceContainer energySourceContainer;
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     while (node != m_nodes.End())
     {
         energySourceContainer.Add((*node)->GetObject<EnergySourceContainer>()->Get(0));
@@ -165,7 +165,7 @@
 void
 UanExperiment::SetupApplications()
 {
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     PacketSocketHelper packetSocketHelper;
     while (node != m_nodes.End())
     {
@@ -187,7 +187,7 @@
 {
     Ptr<UniformRandomVariable> uniformRandomVariable = CreateObject<UniformRandomVariable>();
 
-    NodeContainer::Iterator node = m_nodes.Begin();
+    auto node = m_nodes.Begin();
     Mac8Address dst = Mac8Address::ConvertFrom((*node)->GetDevice(0)->GetAddress());
     node++;
     while (node != m_nodes.End())
@@ -230,9 +230,7 @@
 void
 UanExperiment::Teardown()
 {
-    std::map<Ptr<Node>, Ptr<Socket>>::iterator socket;
-
-    for (socket = m_sockets.begin(); socket != m_sockets.end(); socket++)
+    for (auto socket = m_sockets.begin(); socket != m_sockets.end(); socket++)
     {
         socket->second->Close();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/helper/uan-helper.cc ns-3.40/src/uan/helper/uan-helper.cc
--- ns-3.39/src/uan/helper/uan-helper.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/helper/uan-helper.cc	2023-09-27 13:30:37.890839800 -0700
@@ -113,7 +113,7 @@
 void
 UanHelper::EnableAscii(std::ostream& os, NetDeviceContainer d)
 {
-    for (NetDeviceContainer::Iterator i = d.Begin(); i != d.End(); ++i)
+    for (auto i = d.Begin(); i != d.End(); ++i)
     {
         Ptr<NetDevice> dev = *i;
         EnableAscii(os, dev->GetNode()->GetId(), dev->GetIfIndex());
@@ -124,7 +124,7 @@
 UanHelper::EnableAscii(std::ostream& os, NodeContainer n)
 {
     NetDeviceContainer devs;
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         for (uint32_t j = 0; j < node->GetNDevices(); ++j)
@@ -156,7 +156,7 @@
 UanHelper::Install(NodeContainer c, Ptr<UanChannel> channel) const
 {
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); i++)
+    for (auto i = c.Begin(); i != c.End(); i++)
     {
         Ptr<Node> node = *i;
 
@@ -193,7 +193,7 @@
 {
     int64_t currentStream = stream;
     Ptr<NetDevice> netDevice;
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         netDevice = (*i);
         Ptr<UanNetDevice> uan = DynamicCast<UanNetDevice>(netDevice);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/acoustic-modem-energy-model.cc ns-3.40/src/uan/model/acoustic-modem-energy-model.cc
--- ns-3.39/src/uan/model/acoustic-modem-energy-model.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/acoustic-modem-energy-model.cc	2023-09-27 13:30:37.890839800 -0700
@@ -19,13 +19,14 @@
 
 #include "acoustic-modem-energy-model.h"
 
+#include "uan-net-device.h"
+#include "uan-phy.h"
+
 #include "ns3/double.h"
 #include "ns3/energy-source.h"
 #include "ns3/log.h"
 #include "ns3/simulator.h"
 #include "ns3/trace-source-accessor.h"
-#include "ns3/uan-net-device.h"
-#include "ns3/uan-phy.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-channel.cc ns-3.40/src/uan/model/uan-channel.cc
--- ns-3.39/src/uan/model/uan-channel.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-channel.cc	2023-09-27 13:30:37.890839800 -0700
@@ -84,7 +84,7 @@
         return;
     }
     m_cleared = true;
-    UanDeviceList::iterator it = m_devList.begin();
+    auto it = m_devList.begin();
     for (; it != m_devList.end(); it++)
     {
         if (it->first)
@@ -150,7 +150,7 @@
     Ptr<MobilityModel> senderMobility = nullptr;
 
     NS_LOG_DEBUG("Channel scheduling");
-    for (UanDeviceList::const_iterator i = m_devList.begin(); i != m_devList.end(); i++)
+    for (auto i = m_devList.begin(); i != m_devList.end(); i++)
     {
         if (src == i->second)
         {
@@ -160,7 +160,7 @@
     }
     NS_ASSERT(senderMobility);
     uint32_t j = 0;
-    UanDeviceList::const_iterator i = m_devList.begin();
+    auto i = m_devList.begin();
     for (; i != m_devList.end(); i++)
     {
         if (src != i->second)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-channel.h ns-3.40/src/uan/model/uan-channel.h
--- ns-3.39/src/uan/model/uan-channel.h	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-channel.h	2023-09-27 13:30:37.890839800 -0700
@@ -20,11 +20,12 @@
 #ifndef UAN_CHANNEL_H
 #define UAN_CHANNEL_H
 
+#include "uan-noise-model.h"
+#include "uan-prop-model.h"
+
 #include "ns3/channel.h"
 #include "ns3/net-device.h"
 #include "ns3/packet.h"
-#include "ns3/uan-noise-model.h"
-#include "ns3/uan-prop-model.h"
 
 #include <list>
 #include <vector>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-header-rc.cc ns-3.40/src/uan/model/uan-header-rc.cc
--- ns-3.39/src/uan/model/uan-header-rc.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-header-rc.cc	2023-09-27 13:30:37.890839800 -0700
@@ -607,7 +607,7 @@
 {
     start.WriteU8(m_frameNo);
     start.WriteU8(GetNoNacks());
-    std::set<uint8_t>::iterator it = m_nackedFrames.begin();
+    auto it = m_nackedFrames.begin();
     for (; it != m_nackedFrames.end(); it++)
     {
         start.WriteU8(*it);
@@ -635,7 +635,7 @@
        << " Nacked: ";
     if (GetNoNacks() > 0)
     {
-        std::set<uint8_t>::iterator it = m_nackedFrames.begin();
+        auto it = m_nackedFrames.begin();
         os << (uint32_t)*it;
         it++;
         for (; it != m_nackedFrames.end(); it++)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-mac-cw.cc ns-3.40/src/uan/model/uan-mac-cw.cc
--- ns-3.39/src/uan/model/uan-mac-cw.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-mac-cw.cc	2023-09-27 13:30:37.890839800 -0700
@@ -19,12 +19,13 @@
 
 #include "uan-mac-cw.h"
 
+#include "uan-header-common.h"
+
 #include "ns3/attribute.h"
 #include "ns3/double.h"
 #include "ns3/log.h"
 #include "ns3/nstime.h"
 #include "ns3/trace-source-accessor.h"
-#include "ns3/uan-header-common.h"
 #include "ns3/uinteger.h"
 
 namespace ns3
@@ -150,7 +151,7 @@
             m_pktTx = packet;
             m_pktTxProt = GetTxModeIndex();
             m_state = CCABUSY;
-            uint32_t cw = (uint32_t)m_rv->GetValue(0, m_cw);
+            auto cw = (uint32_t)m_rv->GetValue(0, m_cw);
             m_savedDelayS = cw * m_slotTime;
             m_sendTime = Simulator::Now() + m_savedDelayS;
             NS_LOG_DEBUG("Time " << Now().As(Time::S) << ": Addr " << GetAddress()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-mac-cw.h ns-3.40/src/uan/model/uan-mac-cw.h
--- ns-3.39/src/uan/model/uan-mac-cw.h	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-mac-cw.h	2023-09-27 13:30:37.890839800 -0700
@@ -20,13 +20,14 @@
 #ifndef UAN_MAC_CW_H
 #define UAN_MAC_CW_H
 
+#include "uan-mac.h"
+#include "uan-phy.h"
+#include "uan-tx-mode.h"
+
 #include "ns3/mac8-address.h"
 #include "ns3/nstime.h"
 #include "ns3/random-variable-stream.h"
 #include "ns3/simulator.h"
-#include "ns3/uan-mac.h"
-#include "ns3/uan-phy.h"
-#include "ns3/uan-tx-mode.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-mac-rc.cc ns-3.40/src/uan/model/uan-mac-rc.cc
--- ns-3.39/src/uan/model/uan-mac-rc.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-mac-rc.cc	2023-09-27 13:30:37.890839800 -0700
@@ -73,8 +73,7 @@
 
 Reservation::~Reservation()
 {
-    std::list<std::pair<Ptr<Packet>, Mac8Address>>::iterator it;
-    for (it = m_pktList.begin(); it != m_pktList.end(); it++)
+    for (auto it = m_pktList.begin(); it != m_pktList.end(); it++)
     {
         it->first = Ptr<Packet>((Packet*)nullptr);
     }
@@ -185,8 +184,7 @@
         m_phy->Clear();
         m_phy = nullptr;
     }
-    std::list<std::pair<Ptr<Packet>, Mac8Address>>::iterator it;
-    for (it = m_pktQueue.begin(); it != m_pktQueue.end(); it++)
+    for (auto it = m_pktQueue.begin(); it != m_pktQueue.end(); it++)
     {
         it->first = nullptr;
     }
@@ -424,7 +422,7 @@
 {
     NS_ASSERT(m_state == RTSSENT || m_state == GWPSENT);
 
-    std::list<Reservation>::iterator it = m_resList.begin();
+    auto it = m_resList.begin();
     for (; it != m_resList.end(); it++)
     {
         if (it->GetFrameNo() == ctsh.GetFrameNo())
@@ -455,8 +453,7 @@
     Time frameDelay = Seconds(0);
 
     const std::list<std::pair<Ptr<Packet>, Mac8Address>> l = it->GetPktList();
-    std::list<std::pair<Ptr<Packet>, Mac8Address>>::const_iterator pit;
-    pit = l.begin();
+    auto pit = l.begin();
 
     for (uint8_t i = 0; i < it->GetNoFrames(); i++, pit++)
     {
@@ -544,7 +541,7 @@
     UanHeaderRcAck ah;
     ack->RemoveHeader(ah);
 
-    std::list<Reservation>::iterator it = m_resList.begin();
+    auto it = m_resList.begin();
     for (; it != m_resList.end(); it++)
     {
         if (it->GetFrameNo() == ah.GetFrameNo())
@@ -565,11 +562,10 @@
     if (ah.GetNoNacks() > 0)
     {
         const std::list<std::pair<Ptr<Packet>, Mac8Address>> l = it->GetPktList();
-        std::list<std::pair<Ptr<Packet>, Mac8Address>>::const_iterator pit;
-        pit = l.begin();
+        auto pit = l.begin();
 
         const std::set<uint8_t>& nacks = ah.GetNackedFrames();
-        std::set<uint8_t>::iterator nit = nacks.begin();
+        auto nit = nacks.begin();
         uint8_t pnum = 0;
         for (; nit != nacks.end(); nit++)
         {
@@ -617,7 +613,7 @@
     m_resList.push_back(res);
     Ptr<UanPhyDual> phyDual = m_phy->GetObject<UanPhyDual>();
     bool phy1ok = IsPhy1Ok();
-    if (phy1ok && !phyDual->IsPhy2Tx() & !m_rtsBlocked)
+    if (phy1ok && !phyDual->IsPhy2Tx() && !m_rtsBlocked)
     {
         Ptr<Packet> pkt = Create<Packet>(0);
         pkt->AddHeader(CreateRtsHeader(res));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-mac-rc-gw.cc ns-3.40/src/uan/model/uan-mac-rc-gw.cc
--- ns-3.39/src/uan/model/uan-mac-rc-gw.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-mac-rc-gw.cc	2023-09-27 13:30:37.890839800 -0700
@@ -84,7 +84,7 @@
         m_phy = nullptr;
     }
     m_propDelay.clear();
-    std::map<Mac8Address, AckData>::iterator it = m_ackData.begin();
+    auto it = m_ackData.begin();
     for (; it != m_ackData.end(); it++)
     {
         it->second.rxFrames.clear();
@@ -262,7 +262,7 @@
                 NS_LOG_DEBUG(Now().As(Time::S) << " GW storing reservation from " << ch.GetSrc()
                                                << " with length " << req.length);
                 m_requests.insert(std::make_pair(ch.GetSrc(), req));
-                std::map<Mac8Address, Time>::iterator it = m_propDelay.find(ch.GetSrc());
+                auto it = m_propDelay.find(ch.GetSrc());
                 if (it == m_propDelay.end())
                 {
                     m_sortedRes.insert(std::make_pair(m_maxDelta, ch.GetSrc()));
@@ -292,7 +292,7 @@
 void
 UanMacRcGw::StartCycle()
 {
-    uint32_t numRts = static_cast<uint32_t>(m_sortedRes.size());
+    auto numRts = static_cast<uint32_t>(m_sortedRes.size());
 
     if (numRts)
     {
@@ -309,7 +309,7 @@
     Time pDelay = Seconds(0);
     if (numRts > 0)
     {
-        std::map<Mac8Address, Request>::iterator rit = m_requests.begin();
+        auto rit = m_requests.begin();
         for (; rit != m_requests.end(); rit++)
         {
             totalBytes += (*rit).second.length;
@@ -408,7 +408,7 @@
     m_state = CTSING;
     Simulator::Schedule(nextEarliest, &UanMacRcGw::CycleStarted, this);
 
-    std::set<std::pair<Time, Mac8Address>>::iterator it = m_sortedRes.begin();
+    auto it = m_sortedRes.begin();
     Time minPdelay = (*it).first;
     Ptr<Packet> cts = Create<Packet>();
 
@@ -487,7 +487,7 @@
 
     Time ackTime = Seconds(m_ackSize * 8.0 / m_phy->GetMode(m_currentRateNum).GetDataRateBps());
 
-    std::map<Mac8Address, AckData>::iterator it = m_ackData.begin();
+    auto it = m_ackData.begin();
     for (; it != m_ackData.end(); it++)
     {
         Mac8Address dest = (*it).first;
@@ -507,7 +507,7 @@
         ch.SetType(UanMacRc::TYPE_ACK);
         UanHeaderRcAck ah;
         ah.SetFrameNo(data.frameNo);
-        std::list<uint32_t>::iterator nit = toNack.begin();
+        auto nit = toNack.begin();
         for (; nit != toNack.end(); nit++)
         {
             ah.AddNackedFrame(static_cast<uint8_t>(*nit));
@@ -598,7 +598,7 @@
 {
     uint32_t n = m_numNodes;
     std::vector<double> pds;
-    std::map<Mac8Address, Time>::iterator pdit = m_propDelay.begin();
+    auto pdit = m_propDelay.begin();
 
     for (; pdit != m_propDelay.end(); pdit++)
     {
@@ -664,7 +664,7 @@
     double sum = 0;
     for (uint32_t i = 1; i <= n - k + 1; i++)
     {
-        double nChK = static_cast<double>(NchooseK(n, k));
+        auto nChK = static_cast<double>(NchooseK(n, k));
         double p = (nChK > 0) ? (static_cast<double>(NchooseK(n - i, k - 1)) / nChK) : DBL_MAX;
         sum += p * i;
     }
@@ -674,7 +674,7 @@
 double
 UanMacRcGw::ComputePiK(uint32_t a, uint32_t n, uint32_t k)
 {
-    double nck = (double)NchooseK(n, k);
+    auto nck = (double)NchooseK(n, k);
     return nck * std::pow((std::exp((double)a / (double)n) - 1.0), (double)k) *
            std::exp(-((double)a));
 }
@@ -724,7 +724,7 @@
 {
     double tput = 0;
     uint32_t a = 1;
-    while (1)
+    while (true)
     {
         double newtput = ComputeExpS(a, m_frameSize);
         if (newtput < tput)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-noise-model-default.cc ns-3.40/src/uan/model/uan-noise-model-default.cc
--- ns-3.39/src/uan/model/uan-noise-model-default.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-noise-model-default.cc	2023-09-27 13:30:37.890839800 -0700
@@ -57,7 +57,7 @@
 }
 
 // Common acoustic noise formulas.  These can be found
-// in "Priniciples of Underwater Sound" by Robert J. Urick
+// in "Principles of Underwater Sound" by Robert J. Urick
 double
 UanNoiseModelDefault::GetNoiseDbHz(double fKhz) const
 {
@@ -71,18 +71,18 @@
     double thermalDb;
     double noiseDb;
 
-    turbDb = 17.0 - 30.0 * std::log10(fKhz);
+    double log_fKhz = std::log10(fKhz);
+
+    turbDb = 17.0 - 30.0 * log_fKhz;
     turb = std::pow(10.0, turbDb * 0.1);
 
-    shipDb =
-        40.0 + 20.0 * (m_shipping - 0.5) + 26.0 * std::log10(fKhz) - 60.0 * std::log10(fKhz + 0.03);
+    shipDb = 40.0 + 20.0 * (m_shipping - 0.5) + 26.0 * log_fKhz - 60.0 * std::log10(fKhz + 0.03);
     ship = std::pow(10.0, (shipDb * 0.1));
 
-    windDb = 50.0 + 7.5 * std::pow(m_wind, 0.5) + 20.0 * std::log10(fKhz) -
-             40.0 * std::log10(fKhz + 0.4);
+    windDb = 50.0 + 7.5 * std::pow(m_wind, 0.5) + 20.0 * log_fKhz - 40.0 * std::log10(fKhz + 0.4);
     wind = std::pow(10.0, windDb * 0.1);
 
-    thermalDb = -15 + 20 * std::log10(fKhz);
+    thermalDb = -15 + 20 * log_fKhz;
     thermal = std::pow(10, thermalDb * 0.1);
 
     noiseDb = 10 * std::log10(turb + ship + wind + thermal);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-noise-model-default.h ns-3.40/src/uan/model/uan-noise-model-default.h
--- ns-3.39/src/uan/model/uan-noise-model-default.h	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-noise-model-default.h	2023-09-27 13:30:37.890839800 -0700
@@ -20,9 +20,10 @@
 #ifndef UAN_NOISE_MODEL_DEFAULT_H
 #define UAN_NOISE_MODEL_DEFAULT_H
 
+#include "uan-noise-model.h"
+
 #include "ns3/attribute.h"
 #include "ns3/object.h"
-#include "ns3/uan-noise-model.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-phy-dual.cc ns-3.40/src/uan/model/uan-phy-dual.cc
--- ns-3.39/src/uan/model/uan-phy-dual.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-phy-dual.cc	2023-09-27 13:30:37.890839800 -0700
@@ -79,7 +79,7 @@
     }
 
     double intKp = -DbToKp(rxPowerDb); // This packet is in the arrivalList
-    UanTransducer::ArrivalList::const_iterator it = arrivalList.begin();
+    auto it = arrivalList.begin();
     for (; it != arrivalList.end(); it++)
     {
         // Only count interference if there is overlap in incoming frequency
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-phy-dual.h ns-3.40/src/uan/model/uan-phy-dual.h
--- ns-3.39/src/uan/model/uan-phy-dual.h	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-phy-dual.h	2023-09-27 13:30:37.890839800 -0700
@@ -21,7 +21,7 @@
 #ifndef UAN_PHY_DUAL_H
 #define UAN_PHY_DUAL_H
 
-#include "ns3/uan-phy.h"
+#include "uan-phy.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-phy-gen.cc ns-3.40/src/uan/model/uan-phy-gen.cc
--- ns-3.39/src/uan/model/uan-phy-gen.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-phy-gen.cc	2023-09-27 13:30:37.890839800 -0700
@@ -20,11 +20,12 @@
 
 #include "uan-phy-gen.h"
 
+#include "acoustic-modem-energy-model.h"
 #include "uan-channel.h"
 #include "uan-net-device.h"
 #include "uan-transducer.h"
+#include "uan-tx-mode.h"
 
-#include "ns3/acoustic-modem-energy-model.h"
 #include "ns3/double.h"
 #include "ns3/energy-source-container.h"
 #include "ns3/log.h"
@@ -34,7 +35,6 @@
 #include "ns3/string.h"
 #include "ns3/trace-source-accessor.h"
 #include "ns3/traced-callback.h"
-#include "ns3/uan-tx-mode.h"
 #include "ns3/uinteger.h"
 
 namespace ns3
@@ -83,7 +83,7 @@
     }
 
     double intKp = -DbToKp(rxPowerDb); // This packet is in the arrivalList
-    UanTransducer::ArrivalList::const_iterator it = arrivalList.begin();
+    auto it = arrivalList.begin();
     for (; it != arrivalList.end(); it++)
     {
         intKp += DbToKp(it->GetRxPowerDb());
@@ -143,7 +143,7 @@
     // Get maximum arrival offset
     double maxAmp = -1;
     Time maxTapDelay(0);
-    UanPdp::Iterator pit = pdp.GetBegin();
+    auto pit = pdp.GetBegin();
     for (; pit != pdp.GetEnd(); pit++)
     {
         if (std::abs(pit->GetAmp()) > maxAmp)
@@ -161,7 +161,7 @@
     //  eq. 14
     double isiUpa =
         DbToKp(rxPowerDb) * pdp.SumTapsFromMaxNc(ts + clearingTime, ts); // added DpToKp()
-    UanTransducer::ArrivalList::const_iterator it = arrivalList.begin();
+    auto it = arrivalList.begin();
     double intKp = -DbToKp(effRxPowerDb);
     for (; it != arrivalList.end(); it++)
     {
@@ -312,7 +312,7 @@
         // generic EbNo
         EbNo *= mode.GetDataRateBps() / mode.GetBandwidthHz();
 
-        double M = (double)mode.GetConstellationSize();
+        auto M = (double)mode.GetConstellationSize();
 
         // standard squared quantized QAM, even number of bits per symbol supported
         int log2sqrtM = (int)::std::log2(sqrt(M));
@@ -1086,7 +1086,7 @@
 {
     const UanTransducer::ArrivalList& arrivalList = m_transducer->GetArrivalList();
 
-    UanTransducer::ArrivalList::const_iterator it = arrivalList.begin();
+    auto it = arrivalList.begin();
 
     double interfPower = 0;
 
@@ -1116,7 +1116,7 @@
 void
 UanPhyGen::NotifyListenersRxStart()
 {
-    ListenerList::const_iterator it = m_listeners.begin();
+    auto it = m_listeners.begin();
     for (; it != m_listeners.end(); it++)
     {
         (*it)->NotifyRxStart();
@@ -1126,7 +1126,7 @@
 void
 UanPhyGen::NotifyListenersRxGood()
 {
-    ListenerList::const_iterator it = m_listeners.begin();
+    auto it = m_listeners.begin();
     for (; it != m_listeners.end(); it++)
     {
         (*it)->NotifyRxEndOk();
@@ -1136,7 +1136,7 @@
 void
 UanPhyGen::NotifyListenersRxBad()
 {
-    ListenerList::const_iterator it = m_listeners.begin();
+    auto it = m_listeners.begin();
     for (; it != m_listeners.end(); it++)
     {
         (*it)->NotifyRxEndError();
@@ -1146,7 +1146,7 @@
 void
 UanPhyGen::NotifyListenersCcaStart()
 {
-    ListenerList::const_iterator it = m_listeners.begin();
+    auto it = m_listeners.begin();
     for (; it != m_listeners.end(); it++)
     {
         (*it)->NotifyCcaStart();
@@ -1156,7 +1156,7 @@
 void
 UanPhyGen::NotifyListenersCcaEnd()
 {
-    ListenerList::const_iterator it = m_listeners.begin();
+    auto it = m_listeners.begin();
     for (; it != m_listeners.end(); it++)
     {
         (*it)->NotifyCcaEnd();
@@ -1166,7 +1166,7 @@
 void
 UanPhyGen::NotifyListenersTxStart(Time duration)
 {
-    ListenerList::const_iterator it = m_listeners.begin();
+    auto it = m_listeners.begin();
     for (; it != m_listeners.end(); it++)
     {
         (*it)->NotifyTxStart(duration);
@@ -1176,7 +1176,7 @@
 void
 UanPhyGen::NotifyListenersTxEnd()
 {
-    ListenerList::const_iterator it = m_listeners.begin();
+    auto it = m_listeners.begin();
     for (; it != m_listeners.end(); it++)
     {
         (*it)->NotifyTxEnd();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-phy.h ns-3.40/src/uan/model/uan-phy.h
--- ns-3.39/src/uan/model/uan-phy.h	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-phy.h	2023-09-27 13:30:37.890839800 -0700
@@ -21,12 +21,13 @@
 #ifndef UAN_PHY_H
 #define UAN_PHY_H
 
+#include "uan-mac.h"
+#include "uan-prop-model.h"
+#include "uan-transducer.h"
+#include "uan-tx-mode.h"
+
 #include "ns3/device-energy-model.h"
 #include "ns3/object.h"
-#include "ns3/uan-mac.h"
-#include "ns3/uan-prop-model.h"
-#include "ns3/uan-transducer.h"
-#include "ns3/uan-tx-mode.h"
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-prop-model.cc ns-3.40/src/uan/model/uan-prop-model.cc
--- ns-3.39/src/uan/model/uan-prop-model.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-prop-model.cc	2023-09-27 13:30:37.890839800 -0700
@@ -33,7 +33,7 @@
     os << pdp.GetNTaps() << '|';
     os << pdp.GetResolution().GetSeconds() << '|';
 
-    UanPdp::Iterator it = pdp.m_taps.begin();
+    auto it = pdp.m_taps.begin();
     for (; it != pdp.m_taps.end(); it++)
     {
         os << (*it).GetAmp() << '|';
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-transducer.h ns-3.40/src/uan/model/uan-transducer.h
--- ns-3.39/src/uan/model/uan-transducer.h	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-transducer.h	2023-09-27 13:30:37.890839800 -0700
@@ -20,11 +20,11 @@
 #ifndef UAN_TRANSDUCER_H
 #define UAN_TRANSDUCER_H
 
+#include "uan-prop-model.h"
 #include "uan-tx-mode.h"
 
 #include "ns3/object.h"
 #include "ns3/packet.h"
-#include "ns3/uan-prop-model.h"
 
 #include <list>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-transducer-hd.cc ns-3.40/src/uan/model/uan-transducer-hd.cc
--- ns-3.39/src/uan/model/uan-transducer-hd.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-transducer-hd.cc	2023-09-27 13:30:37.890839800 -0700
@@ -21,12 +21,12 @@
 
 #include "uan-channel.h"
 #include "uan-phy.h"
+#include "uan-prop-model.h"
 
 #include "ns3/double.h"
 #include "ns3/log.h"
 #include "ns3/pointer.h"
 #include "ns3/simulator.h"
-#include "ns3/uan-prop-model.h"
 
 namespace ns3
 {
@@ -62,7 +62,7 @@
         m_channel = nullptr;
     }
 
-    UanPhyList::iterator it = m_phyList.begin();
+    auto it = m_phyList.begin();
     for (; it != m_phyList.end(); it++)
     {
         if (*it)
@@ -71,7 +71,7 @@
             *it = nullptr;
         }
     }
-    ArrivalList::iterator ait = m_arrivalList.begin();
+    auto ait = m_arrivalList.begin();
     for (; ait != m_arrivalList.end(); ait++)
     {
         ait->GetPacket() = nullptr;
@@ -164,7 +164,7 @@
     if (m_state == RX)
     {
         NS_LOG_DEBUG("Transducer state = RX");
-        UanPhyList::const_iterator it = m_phyList.begin();
+        auto it = m_phyList.begin();
         for (; it != m_phyList.end(); it++)
         {
             NS_LOG_DEBUG("Calling StartRx");
@@ -191,7 +191,7 @@
     NS_LOG_DEBUG("Transducer transmitting:  TX delay = "
                  << delay << " seconds for packet size " << packet->GetSize()
                  << " bytes and rate = " << txMode.GetDataRateBps() << " bps");
-    UanPhyList::const_iterator it = m_phyList.begin();
+    auto it = m_phyList.begin();
     for (; it != m_phyList.end(); it++)
     {
         if (src != (*it))
@@ -245,7 +245,7 @@
 UanTransducerHd::RemoveArrival(UanPacketArrival arrival)
 {
     // Remove entry from arrival list
-    ArrivalList::iterator it = m_arrivalList.begin();
+    auto it = m_arrivalList.begin();
     for (; it != m_arrivalList.end(); it++)
     {
         if (it->GetPacket() == arrival.GetPacket())
@@ -254,7 +254,7 @@
             break;
         }
     }
-    UanPhyList::const_iterator ait = m_phyList.begin();
+    auto ait = m_phyList.begin();
     for (; ait != m_phyList.end(); ait++)
     {
         (*ait)->NotifyIntChange();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/uan/model/uan-tx-mode.cc ns-3.40/src/uan/model/uan-tx-mode.cc
--- ns-3.39/src/uan/model/uan-tx-mode.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/uan/model/uan-tx-mode.cc	2023-09-27 13:30:37.890839800 -0700
@@ -116,7 +116,7 @@
 bool
 UanTxModeFactory::NameUsed(std::string name)
 {
-    std::map<uint32_t, UanTxModeItem>::iterator it = m_modes.begin();
+    auto it = m_modes.begin();
 
     for (; it != m_modes.end(); it++)
     {
@@ -176,7 +176,7 @@
 UanTxModeFactory::UanTxModeItem&
 UanTxModeFactory::GetModeItem(std::string name)
 {
-    std::map<uint32_t, UanTxModeItem>::iterator it = m_modes.begin();
+    auto it = m_modes.begin();
     for (; it != m_modes.end(); it++)
     {
         if ((*it).second.m_name == name)
@@ -237,7 +237,7 @@
 {
     NS_ASSERT(modeNum < m_modes.size());
 
-    std::vector<UanTxMode>::iterator it = m_modes.begin();
+    auto it = m_modes.begin();
     for (uint32_t i = 0; i < modeNum; i++)
     {
         it++;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/visualizer/model/pyviz.cc ns-3.40/src/visualizer/model/pyviz.cc
--- ns-3.39/src/visualizer/model/pyviz.cc	2023-07-05 14:23:48.097428300 -0700
+++ ns-3.40/src/visualizer/model/pyviz.cc	2023-09-27 13:30:37.894839800 -0700
@@ -51,7 +51,7 @@
         }
         str = str.substr(cutAt + 1);
     }
-    if (str.length() > 0)
+    if (!str.empty())
     {
         results.push_back(str);
     }
@@ -298,8 +298,7 @@
     Time expirationTime = Simulator::Now() - Seconds(10);
 
     // Clear very old transmission records
-    for (std::map<TxRecordKey, TxRecordValue>::iterator iter = m_txRecords.begin();
-         iter != m_txRecords.end();)
+    for (auto iter = m_txRecords.begin(); iter != m_txRecords.end();)
     {
         if (iter->second.time < expirationTime)
         {
@@ -312,8 +311,7 @@
     }
 
     // Clear very old packets of interest
-    for (std::map<uint32_t, Time>::iterator iter = m_packetsOfInterest.begin();
-         iter != m_packetsOfInterest.end();)
+    for (auto iter = m_packetsOfInterest.begin(); iter != m_packetsOfInterest.end();)
     {
         if (iter->second < expirationTime)
         {
@@ -385,8 +383,7 @@
 PyViz::NetDeviceStatistics&
 PyViz::FindNetDeviceStatistics(int node, int interface)
 {
-    std::map<uint32_t, std::vector<NetDeviceStatistics>>::iterator nodeStatsIter =
-        m_nodesStatistics.find(node);
+    auto nodeStatsIter = m_nodesStatistics.find(node);
     std::vector<NetDeviceStatistics>* stats;
     if (nodeStatsIter == m_nodesStatistics.end())
     {
@@ -404,8 +401,7 @@
 bool
 PyViz::GetPacketCaptureOptions(uint32_t nodeId, const PacketCaptureOptions** outOptions) const
 {
-    std::map<uint32_t, PacketCaptureOptions>::const_iterator iter =
-        m_packetCaptureOptions.find(nodeId);
+    auto iter = m_packetCaptureOptions.find(nodeId);
     if (iter == m_packetCaptureOptions.end())
     {
         return false;
@@ -444,7 +440,7 @@
         while (metadataIterator.HasNext())
         {
             PacketMetadata::Item item = metadataIterator.Next();
-            std::set<TypeId>::iterator missingIter = missingHeaders.find(item.tid);
+            auto missingIter = missingHeaders.find(item.tid);
             if (missingIter != missingHeaders.end())
             {
                 missingHeaders.erase(missingIter);
@@ -495,7 +491,7 @@
         }
     }
 
-    std::map<Ptr<Node>, uint32_t>::iterator iter = m_packetDrops.find(node);
+    auto iter = m_packetDrops.find(node);
     if (iter == m_packetDrops.end())
     {
         m_packetDrops[node] = packet->GetSize();
@@ -698,8 +694,7 @@
 
     Ptr<Channel> channel = device->GetChannel();
 
-    std::map<TxRecordKey, TxRecordValue>::iterator recordIter =
-        m_txRecords.find(TxRecordKey(channel, uid));
+    auto recordIter = m_txRecords.find(TxRecordKey(channel, uid));
 
     if (recordIter == m_txRecords.end())
     {
@@ -722,10 +717,7 @@
     NS_LOG_DEBUG("m_transmissionSamples begin:");
     if (g_log.IsEnabled(ns3::LOG_DEBUG))
     {
-        for (std::map<TransmissionSampleKey, TransmissionSampleValue>::const_iterator iter =
-                 m_transmissionSamples.begin();
-             iter != m_transmissionSamples.end();
-             iter++)
+        for (auto iter = m_transmissionSamples.begin(); iter != m_transmissionSamples.end(); iter++)
         {
             NS_LOG_DEBUG(iter->first.transmitter
                          << "/" << iter->first.transmitter->GetId() << ", " << iter->first.receiver
@@ -736,8 +728,7 @@
     NS_LOG_DEBUG("m_transmissionSamples end.");
 #endif
 
-    std::map<TransmissionSampleKey, TransmissionSampleValue>::iterator iter =
-        m_transmissionSamples.find(key);
+    auto iter = m_transmissionSamples.find(key);
 
     if (iter == m_transmissionSamples.end())
     {
@@ -867,10 +858,7 @@
 {
     NS_LOG_DEBUG("GetTransmissionSamples BEGIN");
     TransmissionSampleList list;
-    for (std::map<TransmissionSampleKey, TransmissionSampleValue>::const_iterator iter =
-             m_transmissionSamples.begin();
-         iter != m_transmissionSamples.end();
-         iter++)
+    for (auto iter = m_transmissionSamples.begin(); iter != m_transmissionSamples.end(); iter++)
     {
         TransmissionSample sample;
         sample.transmitter = iter->first.transmitter;
@@ -890,9 +878,7 @@
 {
     NS_LOG_DEBUG("GetPacketDropSamples BEGIN");
     PacketDropSampleList list;
-    for (std::map<Ptr<Node>, uint32_t>::const_iterator iter = m_packetDrops.begin();
-         iter != m_packetDrops.end();
-         iter++)
+    for (auto iter = m_packetDrops.begin(); iter != m_packetDrops.end(); iter++)
     {
         PacketDropSample sample;
         sample.transmitter = iter->first;
@@ -915,10 +901,7 @@
 PyViz::GetNodesStatistics() const
 {
     std::vector<PyViz::NodeStatistics> retval;
-    for (std::map<uint32_t, std::vector<NetDeviceStatistics>>::const_iterator iter =
-             m_nodesStatistics.begin();
-         iter != m_nodesStatistics.end();
-         iter++)
+    for (auto iter = m_nodesStatistics.begin(); iter != m_nodesStatistics.end(); iter++)
     {
         NodeStatistics stats = {iter->first, iter->second};
         retval.push_back(stats);
@@ -931,7 +914,7 @@
 {
     NS_LOG_DEBUG("GetLastPackets: " << nodeId);
 
-    std::map<uint32_t, LastPacketsSample>::const_iterator iter = m_lastPackets.find(nodeId);
+    auto iter = m_lastPackets.find(nodeId);
     if (iter != m_lastPackets.end())
     {
         return iter->second;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/visualizer/visualizer/core.py ns-3.40/src/visualizer/visualizer/core.py
--- ns-3.39/src/visualizer/visualizer/core.py	2023-07-05 14:23:48.101428300 -0700
+++ ns-3.40/src/visualizer/visualizer/core.py	2023-09-27 13:30:37.894839800 -0700
@@ -69,7 +69,7 @@
     _import_error = None
 
 try:
-    import ipython_viewxxxxxxxxxx
+    from . import ipython_view
 except ImportError:
     ipython_view = None
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/visualizer/visualizer/ipython_view.py ns-3.40/src/visualizer/visualizer/ipython_view.py
--- ns-3.39/src/visualizer/visualizer/ipython_view.py	2023-07-05 14:23:48.101428300 -0700
+++ ns-3.40/src/visualizer/visualizer/ipython_view.py	2023-09-27 13:30:37.894839800 -0700
@@ -13,15 +13,21 @@
 # this file is a modified version of source code from the Accerciser project
 # https://wiki.gnome.org/Apps/Accerciser
 
-import gtk, gobject
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GLib
+from gi.repository import Pango
+
+from pkg_resources import parse_version
+
 import re
 import sys
 import os
-from gi.repository import Pango
-from StringIO import StringIO
-import IPython
 
-from pkg_resources import parse_version
+from io import StringIO
+from functools import reduce
 
 ## Try to import IPython
 try:
@@ -41,6 +47,12 @@
   #  history level
   ## @var complete_sep
   #  separators
+  ## @var no_input_splitter
+  # no input splitter
+  ## @var lines
+  # lines
+  ## @var indent_spaces
+  # indent spaces
   ## @var prompt
   #  prompt
   ## @var header
@@ -52,8 +64,8 @@
   ## @var raw_input
   #  raw input
   ## Constructor
-  def __init__(self,argv=None,user_ns=None,user_global_ns=None,
-               cin=None, cout=None,cerr=None, input_func=None):
+  def __init__(self, argv=[], user_ns=None, user_global_ns=None,
+               cin=None, cout=None, cerr=None, input_func=None):
     """! Initializer
 
     @param self: this object
@@ -67,45 +79,47 @@
     """
     io = IPython.utils.io
     if input_func:
-      if parse_version(IPython.release.version) >= parse_version("1.2.1"):
-        IPython.terminal.interactiveshell.raw_input_original = input_func
-      else:
-        IPython.frontend.terminal.interactiveshell.raw_input_original = input_func
-    if cin:
-      io.stdin = io.IOStream(cin)
-    if cout:
-      io.stdout = io.IOStream(cout)
-    if cerr:
-      io.stderr = io.IOStream(cerr)
+      IPython.terminal.interactiveshell.raw_input_original = input_func
+    if IPython.version_info < (8,):
+      if cin:
+        io.stdin = io.IOStream(cin)
+      if cout:
+        io.stdout = io.IOStream(cout)
+      if cerr:
+        io.stderr = io.IOStream(cerr)
+    else:
+      if cin:
+        sys.stdin = cin
+      if cout:
+        sys.stdout = cout
+      if cerr:
+        sys.stderr = cerr
 
     # This is to get rid of the blockage that occurs during
     # IPython.Shell.InteractiveShell.user_setup()
-
     io.raw_input = lambda x: None
 
     os.environ['TERM'] = 'dumb'
     excepthook = sys.excepthook
 
-    from IPython.config.loader import Config
+    from traitlets.config.loader import Config
     cfg = Config()
     cfg.InteractiveShell.colors = "Linux"
+    cfg.Completer.use_jedi = False
 
-    # InteractiveShell's __init__ overwrites io.stdout,io.stderr with
-    # sys.stdout, sys.stderr, this makes sure they are right
-    #
-    old_stdout, old_stderr = sys.stdout, sys.stderr
-    sys.stdout, sys.stderr = io.stdout.stream, io.stderr.stream
+    if IPython.version_info < (8,):
+      # InteractiveShell's __init__ overwrites io.stdout,io.stderr with
+      # sys.stdout, sys.stderr, this makes sure they are right
+      old_stdout, old_stderr = sys.stdout, sys.stderr
+      sys.stdout, sys.stderr = io.stdout.stream, io.stderr.stream
 
     # InteractiveShell inherits from SingletonConfigurable, so use instance()
     #
-    if parse_version(IPython.release.version) >= parse_version("1.2.1"):
-      self.IP = IPython.terminal.embed.InteractiveShellEmbed.instance(\
-              config=cfg, user_ns=user_ns)
-    else:
-      self.IP = IPython.frontend.terminal.embed.InteractiveShellEmbed.instance(\
+    self.IP = IPython.terminal.embed.InteractiveShellEmbed.instance(\
               config=cfg, user_ns=user_ns)
 
-    sys.stdout, sys.stderr = old_stdout, old_stderr
+    if IPython.version_info < (8,):
+      sys.stdout, sys.stderr = old_stdout, old_stderr
 
     self.IP.system = lambda cmd: self.shell(self.IP.var_expand(cmd),
                                             header='IPython system call: ')
@@ -120,11 +134,17 @@
     self.complete_sep =  re.compile('[\s\{\}\[\]\(\)]')
     self.updateNamespace({'exit':lambda:None})
     self.updateNamespace({'quit':lambda:None})
-    self.IP.readline_startup_hook(self.IP.pre_readline)
     # Workaround for updating namespace with sys.modules
     #
     self.__update_namespace()
 
+    # Avoid using input splitter when not really needed.
+    # Perhaps it could work even before 5.8.0
+    # But it definitely does not work any more with >= 7.0.0
+    self.no_input_splitter = parse_version(IPython.release.version) >= parse_version('5.8.0')
+    self.lines = []
+    self.indent_spaces = ''
+
   def __update_namespace(self):
     """!
     Update self.IP namespace for autocompletion with sys.modules
@@ -140,11 +160,17 @@
     @return none
     """
     self.history_level = 0
-    orig_stdout = sys.stdout
-    sys.stdout = IPython.utils.io.stdout
 
-    orig_stdin = sys.stdin
-    sys.stdin = IPython.utils.io.stdin;
+    if IPython.version_info < (8,):
+      # this is needed because some functions in IPython use 'print' to print
+      # output (like 'who')
+
+      orig_stdout = sys.stdout
+      sys.stdout = IPython.utils.io.stdout
+
+      orig_stdin = sys.stdin
+      sys.stdin = IPython.utils.io.stdin
+
     self.prompt = self.generatePrompt(self.iter_more)
 
     self.IP.hooks.pre_prompt_hook()
@@ -160,21 +186,26 @@
       line = self.IP.raw_input(self.prompt)
     except KeyboardInterrupt:
       self.IP.write('\nKeyboardInterrupt\n')
-      self.IP.input_splitter.reset()
+      if self.no_input_splitter:
+        self.lines = []
+      else:
+        self.IP.input_splitter.reset()
     except:
       self.IP.showtraceback()
     else:
-      self.IP.input_splitter.push(line)
-      self.iter_more = self.IP.input_splitter.push_accepts_more()
-      self.prompt = self.generatePrompt(self.iter_more)
-      if (self.IP.SyntaxTB.last_syntax_error and
-          self.IP.autoedit_syntax):
-          self.IP.edit_syntax_error()
+      if self.no_input_splitter:
+        self.lines.append(line)
+        (status, self.indent_spaces) = self.IP.check_complete('\n'.join(self.lines))
+        self.iter_more = status == 'incomplete'
+      else:
+        self.IP.input_splitter.push(line)
+        self.iter_more = self.IP.input_splitter.push_accepts_more()
       if not self.iter_more:
-          if parse_version(IPython.release.version) >= parse_version("2.0.0-dev"):
-            source_raw = self.IP.input_splitter.raw_reset()
+          if self.no_input_splitter:
+            source_raw = '\n'.join(self.lines)
+            self.lines = []
           else:
-            source_raw = self.IP.input_splitter.source_raw_reset()[1]
+            source_raw = self.IP.input_splitter.raw_reset()
           self.IP.run_cell(source_raw, store_history=True)
           self.IP.rl_do_indent = False
       else:
@@ -182,9 +213,11 @@
           #
           self.IP.rl_do_indent = True
           pass
+      self.prompt = self.generatePrompt(self.iter_more)
 
-    sys.stdout = orig_stdout
-    sys.stdin = orig_stdin
+    if IPython.version_info < (8,):
+      sys.stdout = orig_stdout
+      sys.stdin = orig_stdin
 
   def generatePrompt(self, is_continuation):
     """!
@@ -195,17 +228,10 @@
 
     """
 
-    # Backwards compatibility with ipyton-0.11
-    #
-    ver = IPython.__version__
-    if '0.11' in ver:
-        prompt = self.IP.hooks.generate_prompt(is_continuation)
+    if is_continuation:
+      prompt = '... '
     else:
-        if is_continuation:
-            prompt = self.IP.prompt_manager.render('in2')
-        else:
-            prompt = self.IP.prompt_manager.render('in')
-
+      prompt = '>>> '
     return prompt
 
 
@@ -281,7 +307,7 @@
             return str1[:i]
         return str1
       if possibilities[1]:
-        common_prefix = reduce(_commonPrefix, possibilities[1]) or line[-1]
+        common_prefix = reduce(_commonPrefix, possibilities[1]) or split_line[-1]
         completed = line[:-len(split_line[-1])]+common_prefix
       else:
         completed = line
@@ -324,7 +350,8 @@
   """
   Specialized text view for console-like workflow.
 
-  @cvar ANSI_COLORS: Mapping of terminal colors to X11 names.
+  @cvar ANSI_COLORS: Mapping of terminal control sequence values to
+                     tuples containing foreground and background color names.
   @type ANSI_COLORS: dictionary
 
   @ivar text_buffer: Widget's text buffer.
@@ -336,20 +363,35 @@
   @ivar line_start: Start of command line mark.
   @type line_start: Gtk.TextMark
   """
-  ANSI_COLORS =  {'0;30': 'Black',     '0;31': 'Red',
-                  '0;32': 'Green',     '0;33': 'Brown',
-                  '0;34': 'Blue',      '0;35': 'Purple',
-                  '0;36': 'Cyan',      '0;37': 'LightGray',
-                  '1;30': 'DarkGray',  '1;31': 'DarkRed',
-                  '1;32': 'SeaGreen',  '1;33': 'Yellow',
-                  '1;34': 'LightBlue', '1;35': 'MediumPurple',
-                  '1;36': 'LightCyan', '1;37': 'White'}
+  ANSI_COLORS = {'0;30': ('Black', None),
+                 '0;31': ('Red', None),
+                 '0;32': ('Green', None),
+                 '0;33': ('Brown', None),
+                 '0;34': ('Blue', None),
+                 '0;35': ('Purple', None),
+                 '0;36': ('Cyan', None),
+                 '0;37': ('LightGray', None),
+                 '1;30': ('DarkGray', None),
+                 '1;31': ('DarkRed', None),
+                 '1;32': ('SeaGreen', None),
+                 '1;33': ('Yellow', None),
+                 '1;34': ('LightBlue', None),
+                 '1;35': ('MediumPurple', None),
+                 '1;36': ('LightCyan', None),
+                 '1;37': ('White', None),
+                 '38;5;124;43': ('DarkRed', 'Yellow'),
+                 '38;5;241': ('Gray', None),
+                 '38;5;241;43': ('Gray', 'Yellow'),
+                 '39': ('Black', None),
+                 '39;49': ('Red', 'White'),
+                 '43': (None, 'Yellow'),
+                 '49': (None, 'White')}
 
   def __init__(self):
     """
     Initialize console view.
     """
-    GObject.GObject.__init__(self)
+    Gtk.TextView.__init__(self)
     self.modify_font(Pango.FontDescription('Mono'))
     self.set_cursor_visible(True)
     self.text_buffer = self.get_buffer()
@@ -358,7 +400,8 @@
                                              False)
     for code in self.ANSI_COLORS:
       self.text_buffer.create_tag(code,
-                                  foreground=self.ANSI_COLORS[code],
+                                  foreground=self.ANSI_COLORS[code][0],
+                                  background=self.ANSI_COLORS[code][1],
                                   weight=700)
     self.text_buffer.create_tag('0')
     self.text_buffer.create_tag('notouch', editable=False)
@@ -376,7 +419,7 @@
     @param editable: If true, added text is editable.
     @return none
     """
-    GObject.idle_add(self._write, text, editable)
+    GLib.idle_add(self._write, text, editable)
 
   def _write(self, text, editable=False):
     """!
@@ -414,7 +457,7 @@
     @param prompt: Prompt to print.
     @return none
     """
-    GObject.idle_add(self._showPrompt, prompt)
+    GLib.idle_add(self._showPrompt, prompt)
 
   def _showPrompt(self, prompt):
     """!
@@ -434,7 +477,7 @@
     @param text: Text to use as replacement.
     @return none
     """
-    GObject.idle_add(self._changeLine, text)
+    GLib.idle_add(self._changeLine, text)
 
   def _changeLine(self, text):
     """!
@@ -466,7 +509,7 @@
     @param text: Text to show.
     @return none
     """
-    GObject.idle_add(self._showReturned, text)
+    GLib.idle_add(self._showReturned, text)
 
   def _showReturned(self, text):
     """!
@@ -485,11 +528,14 @@
     if text:
       self._write('\n')
     self._showPrompt(self.prompt)
-    self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter())
+    self.text_buffer.move_mark(self.line_start, self.text_buffer.get_end_iter())
     self.text_buffer.place_cursor(self.text_buffer.get_end_iter())
 
     if self.IP.rl_do_indent:
-      indentation = self.IP.input_splitter.indent_spaces * ' '
+      if self.no_input_splitter:
+        indentation = self.indent_spaces
+      else:
+        indentation = self.IP.input_splitter.indent_spaces * ' '
       self.text_buffer.insert_at_cursor(indentation)
 
   def onKeyPress(self, widget, event):
@@ -508,9 +554,9 @@
     selection_iter = self.text_buffer.get_iter_at_mark(selection_mark)
     start_iter = self.text_buffer.get_iter_at_mark(self.line_start)
     if event.keyval == Gdk.KEY_Home:
-      if event.get_state() & Gdk.ModifierType.CONTROL_MASK or event.get_state() & Gdk.ModifierType.MOD1_MASK:
+      if event.state & Gdk.ModifierType.CONTROL_MASK or event.state & Gdk.ModifierType.MOD1_MASK:
         pass
-      elif event.get_state() & Gdk.ModifierType.SHIFT_MASK:
+      elif event.state & Gdk.ModifierType.SHIFT_MASK:
         self.text_buffer.move_mark(insert_mark, start_iter)
         return True
       else:
@@ -520,6 +566,24 @@
       insert_iter.backward_cursor_position()
       if not insert_iter.editable(True):
         return True
+    elif event.state & Gdk.ModifierType.CONTROL_MASK and event.keyval in [ord('L'), ord('l')]:
+        # clear previous output on Ctrl+L, but remember current input line + cursor position
+        cursor_offset = self.text_buffer.get_property('cursor-position')
+        cursor_pos_in_line = cursor_offset - start_iter.get_offset() + len(self.prompt)
+        current_input = self.text_buffer.get_text(start_iter, self.text_buffer.get_end_iter(), False)
+        self.text_buffer.set_text(self.prompt + current_input)
+        self.text_buffer.move_mark(self.line_start, self.text_buffer.get_iter_at_offset(len(self.prompt)))
+        self.text_buffer.place_cursor(self.text_buffer.get_iter_at_offset(cursor_pos_in_line))
+        return True
+    elif event.state & Gdk.ModifierType.CONTROL_MASK and event.keyval in [Gdk.KEY_k, Gdk.KEY_K]:
+      # clear text after input cursor on Ctrl+K
+      if insert_iter.editable(True):
+        self.text_buffer.delete(insert_iter, self.text_buffer.get_end_iter())
+      return True
+    elif event.state & Gdk.ModifierType.CONTROL_MASK and event.keyval == Gdk.KEY_C:
+      # copy selection on Ctrl+C (upper-case 'C' only)
+      self.text_buffer.copy_clipboard(Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD))
+      return True
     elif not event.string:
       pass
     elif start_iter.compare(insert_iter) <= 0 and \
@@ -569,7 +633,7 @@
     """
     ConsoleView.__init__(self)
     self.cout = StringIO()
-    IterableIPShell.__init__(self, cout=self.cout,cerr=self.cout,
+    IterableIPShell.__init__(self, cout=self.cout, cerr=self.cout,
                              input_func=self.raw_input)
     self.interrupt = False
     self.execute()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/CMakeLists.txt ns-3.40/src/wifi/CMakeLists.txt
--- ns-3.39/src/wifi/CMakeLists.txt	2023-07-05 14:23:48.101428300 -0700
+++ ns-3.40/src/wifi/CMakeLists.txt	2023-09-27 13:30:37.894839800 -0700
@@ -354,4 +354,5 @@
     test/wifi-txop-test.cc
     test/wifi-phy-cca-test.cc
     test/wifi-non-ht-dup-test.cc
+    test/wifi-phy-mu-mimo-test.cc
 )
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/doc/source/wifi-design.rst ns-3.40/src/wifi/doc/source/wifi-design.rst
--- ns-3.39/src/wifi/doc/source/wifi-design.rst	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/doc/source/wifi-design.rst	2023-09-27 13:30:37.898839700 -0700
@@ -167,8 +167,6 @@
 when the SpectrumWifiPhy is used.
 The following details pertain to the physical layer and channel models:
 
-* 802.11ax/be MU-RTS/CTS is not yet supported
-* 802.11ac/ax/be MU-MIMO is not supported, and no more than 4 antennas can be configured
 * 802.11n/ac/ax/be beamforming is not supported
 * 802.11n RIFS is not supported
 * 802.11 PCF/HCF/HCCA are not implemented
@@ -178,11 +176,11 @@
 * Cases where RTS/CTS and ACK are transmitted using HT/VHT/HE/EHT formats are not supported
 * Energy consumption model does not consider MIMO
 * 802.11ax preamble puncturing is supported by the PHY but is currently not exploited by the MAC
-* Only minimal 802.11be PHY is supported (no MAC layer yet)
+* Only minimal MU-MIMO is supported (ideal PHY assumed, no MAC layer yet)
 
 At the MAC layer, most of the main functions found in deployed Wi-Fi
-equipment for 802.11a/b/e/g/n/ac/ax are implemented, but there are scattered instances
-where some limitations in the models exist. Support for 802.11n, ac and ax is evolving.
+equipment for 802.11a/b/e/g/n/ac/ax/be are implemented, but there are scattered instances
+where some limitations in the models exist. Support for 802.11n, ac, ax and be is evolving.
 
 Some implementation choices that are not imposed by the standard are listed below:
 
@@ -751,9 +749,14 @@
 
    Multiple RF interfaces concept
 
-If the ``SpectrumWifiPhy::TrackSignalsFromInactiveInterfaces`` attribute is set to true,
+If the ``SpectrumWifiPhy::TrackSignalsFromInactiveInterfaces`` attribute is set to true (default),
 inactive RF interfaces are connected to their respective spectrum channels and the ``SpectrumWifiPhy``
-forwards received signals from these inactive RF interfaces to the ``InterferenceHelper`` without processing them.
+also receive signals from these inactive RF interfaces when they belong to a configured portion
+of the frequency range covered by the interface.
+The portion of the spectrum being monitored by an inactive interface is specified by a center frequency
+and a channel width, and is seamlessly set to equivalent of the operating channel of the spectrum PHY
+that is actively using that frequency range. The ``SpectrumWifiPhy``forwards these received signals
+from inactive interfaces to the ``InterferenceHelper`` without further processing them.
 The benefit of the latter is that more accurate PHY-CCA.indication can be generated upon channel switching
 if one or more signals started to be transmitted on the new channel before the switch occurs,
 which would be ignored otherwise. This is illustrated in Figure :ref:`fig-cca-channel-switching-multiple-interfaces`, where the parts in red are only generated when ``SpectrumWifiPhy::TrackSignalsFromInactiveInterfaces`` is set to true.
@@ -965,6 +968,16 @@
 the wifi-mac-ofdma examples), which determines the Access Category that handles the
 packet. By default, wifi MAC queues support flow control, hence upper layers do not
 forward a packet down if there is no room for it in the corresponding MAC queue.
+Wifi MAC queues do not support dynamic queue limits (byte queue limits); therefore,
+there is no backpressure into the traffic control layer until the WifiMacQueue for
+an access category is completely full (i.e., when the queue depth reaches the value
+of the MaxSize attribute, which defaults to 500 packets).
+TCP small queues (TSQ) [corbet2012]_ is a Linux feature that provides feedback from the
+Wi-Fi device to the socket layer, to control how much data is queued at the Wi-Fi
+level.  |ns3| TCP does not implement TSQ, nor does the WifiNetDevice provide that
+specific feedback (although some use of the existing trace sources may be enough to
+support it).  Regardless, experimental tests have demonstrated that TSQ interferes with
+Wi-Fi aggregation on uplink transfers [grazia2022]_.
 Packets stay in the wifi MAC queue until they are acknowledged or discarded. A packet
 may be discarded because, e.g., its lifetime expired (i.e., it stayed in the queue for too
 long) or the maximum number of retries was reached. The maximum lifetime for a packet can
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/doc/source/wifi-references.rst ns-3.40/src/wifi/doc/source/wifi-references.rst
--- ns-3.39/src/wifi/doc/source/wifi-references.rst	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/doc/source/wifi-references.rst	2023-09-27 13:30:37.898839700 -0700
@@ -64,3 +64,7 @@
 .. [magrin2021mu] \ D. Magrin, S. Avallone, S. Roy, and M. Zorzi, 'Validation of the ns-3 802.11ax OFDMA implementation', in Proceedings of WNS3 2021.
 
 .. [avallone2021wcm] \ S. Avallone, P. Imputato, G. Redieteab, C. Ghosh and S. Roy, "Will OFDMA Improve the Performance of 802.11 WiFi Networks?", in IEEE Wireless Communications Magazine, DOI: 10.1109/MWC.001.2000332, to appear.
+
+.. [corbet2012] \ J. Corbet, "TCP Small Queues", `LWN.net, July 17, 2012 <https://lwn.net/Articles/507065/>`__
+
+.. [grazia2022] \ C. Grazia, N. Patriciello, T. Hoiland-Jorgensen, M. Klapez and M. Casoni, "Aggregating Without Bloating: Hard Times for TCP on Wi-Fi", IEEE/ACM Transactions on Networking, Vol. 30, No.5, October 2022.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/doc/source/wifi-user.rst ns-3.40/src/wifi/doc/source/wifi-user.rst
--- ns-3.39/src/wifi/doc/source/wifi-user.rst	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/doc/source/wifi-user.rst	2023-09-27 13:30:37.898839700 -0700
@@ -55,7 +55,9 @@
   are needed for propagation loss calculations.
 
 The following sample code illustrates a typical configuration using mostly
-default values in the simulator, and infrastructure mode::
+default values in the simulator, and infrastructure mode:
+
+.. sourcecode:: cpp
 
   NodeContainer wifiStaNode;
   wifiStaNode.Create(10);   // Create 10 station node objects
@@ -98,7 +100,9 @@
 helper can be used to create a YansWifiChannel with a default PropagationLoss and
 PropagationDelay model.
 
-Users will typically type code such as::
+Users will typically type code such as:
+
+.. sourcecode:: cpp
 
   YansWifiChannelHelper wifiChannelHelper = YansWifiChannelHelper::Default();
   Ptr<Channel> wifiChannel = wifiChannelHelper.Create();
@@ -133,7 +137,9 @@
 The YansWifiPhyHelper class configures an object factory to create instances of
 a ``YansWifiPhy`` and adds some other objects to it, including possibly a
 supplemental ErrorRateModel and a pointer to a MobilityModel. The user code is
-typically::
+typically:
+
+.. sourcecode:: cpp
 
   YansWifiPhyHelper wifiPhyHelper;
   wifiPhyHelper.SetChannel(wifiChannel);
@@ -143,7 +149,9 @@
 calling the ``YansWifiPhyHelper::SetErrorRateModel`` method.
 
 Optionally, if pcap tracing is needed, a user may use the following
-command to enable pcap tracing::
+command to enable pcap tracing:
+
+.. sourcecode:: cpp
 
   YansWifiPhyHelper::SetPcapDataLinkType(enum SupportedPcapDataLinkTypes dlt)
 
@@ -154,14 +162,18 @@
 The Phy objects are created in the next step.
 
 In order to enable 802.11n/ac/ax MIMO, the number of antennas as well as the number of supported spatial streams need to be configured.
-For example, this code enables MIMO with 2 antennas and 2 spatial streams::
+For example, this code enables MIMO with 2 antennas and 2 spatial streams:
+
+.. sourcecode:: cpp
 
  wifiPhyHelper.Set("Antennas", UintegerValue(2));
  wifiPhyHelper.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
  wifiPhyHelper.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
 
 It is also possible to configure less streams than the number of antennas in order to benefit from diversity gain, and to define different MIMO capabilities for downlink and uplink.
-For example, this code configures a node with 3 antennas that supports 2 spatial streams in downstream and 1 spatial stream in upstream::
+For example, this code configures a node with 3 antennas that supports 2 spatial streams in downstream and 1 spatial stream in upstream:
+
+.. sourcecode:: cpp
 
  wifiPhyHelper.Set("Antennas", UintegerValue(3));
  wifiPhyHelper.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
@@ -169,7 +181,7 @@
 
 802.11n PHY layer can support both 20 (default) or 40 MHz channel width, and 802.11ac/ax PHY layer can use either 20, 40, 80 (default) or 160 MHz channel width.  See below for further documentation on setting the frequency, channel width, and channel number.
 
-::
+.. sourcecode:: cpp
 
   WifiHelper wifi;
   wifi.SetStandard(WIFI_STANDARD_80211ac);
@@ -207,13 +219,13 @@
 
 * Defining a StringValue object to set the ``ChannelSettings`` attribute
 
-::
+.. sourcecode:: cpp
 
   StringValue value("{38, 40, BAND_5GHZ, 0}"));
 
 * Defining a TupleValue object to set the ``ChannelSettings`` attribute
 
-::
+.. sourcecode:: cpp
 
   TupleValue<UintegerValue, UintegerValue, EnumValue, UintegerValue> value;
   value.Set(WifiPhy::ChannelTuple {38, 40, WIFI_PHY_BAND_5GHZ, 0});
@@ -226,13 +238,13 @@
 
 * by setting global configuration default; e.g.
 
-::
+.. sourcecode:: cpp
 
   Config::SetDefault("ns3::WifiPhy::ChannelSettings", StringValue("{38, 40, BAND_5GHZ, 0}"));
 
 * by setting an attribute value in the helper; e.g.
 
-::
+.. sourcecode:: cpp
 
   TupleValue<UintegerValue, UintegerValue, EnumValue, UintegerValue> value;
   value.Set(WifiPhy::ChannelTuple {38, 40, WIFI_PHY_BAND_5GHZ, 0});
@@ -244,7 +256,7 @@
 * by performing post-installation configuration of the option, either
   via a Ptr to the WifiPhy object, or through the Config namespace; e.g.:
 
-::
+.. sourcecode:: cpp
 
   Config::Set("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phy/$ns3::WifiPhy/ChannelSettings",
               StringValue("{38, 40, BAND_5GHZ, 0}"));
@@ -263,7 +275,7 @@
 The following values for WifiStandard are defined in
 ``src/wifi/model/wifi-standards.h``:
 
-::
+.. sourcecode:: cpp
 
   WIFI_STANDARD_80211a,
   WIFI_STANDARD_80211b,
@@ -308,7 +320,7 @@
 
 Following are a few examples to clarify these rules:
 
-::
+.. sourcecode:: cpp
 
   WifiHelper wifi;
   wifi.SetStandard(WIFI_STANDARD_80211ac);
@@ -317,7 +329,7 @@
   // channel width unspecified
   // -> it is set to 80 MHz (width of channel 58)
 
-::
+.. sourcecode:: cpp
 
   WifiHelper wifi;
   wifi.SetStandard(WIFI_STANDARD_80211n);
@@ -326,7 +338,7 @@
   // channel number unspecified
   // -> it is set to channel 38 (first 40 MHz channel in the 5GHz band)
 
-::
+.. sourcecode:: cpp
 
   WifiHelper wifi;
   wifi.SetStandard(WIFI_STANDARD_80211ax);
@@ -336,7 +348,7 @@
   // -> width set to 20 MHz (default width for 802.11ax in the 2.4 GHZ band)
   // -> channel number set to 1 (first 20 MHz channel in the 2.4 GHz band)
 
-::
+.. sourcecode:: cpp
 
   WifiHelper wifi;
   wifi.SetStandard(WIFI_STANDARD_80211a);
@@ -455,7 +467,7 @@
 If an unknown channel number (other than zero) is configured, the
 simulator will exit with an error; for instance, such as:
 
-::
+.. sourcecode:: cpp
 
   Ptr<WifiPhy> wifiPhy = ...;
   wifiPhy->SetAttribute("ChannelSettings", StringValue("{1321, 20, BAND_5GHZ, 0}"));
@@ -468,7 +480,7 @@
 of the WifiPhyStandard, the simulator will exit with an error; for instance,
 such as:
 
-::
+.. sourcecode:: cpp
 
   WifiHelper wifi;
   wifi.SetStandard(WIFI_STANDARD_80211n);
@@ -508,7 +520,9 @@
 Its API has been extended for 802.11be multi-link and EMLSR in order to
 attach multiple spectrum channels to a same PHY. For that purpose, a user
 may use the following command to attach a spectrum channel to the PHY objects
-that will be created upon a call to ``ns3::WifiHelper::Install``::
+that will be created upon a call to ``ns3::WifiHelper::Install``:
+
+.. sourcecode:: cpp
 
   SpectrumWifiPhyHelper::SetPcapDataLinkType(const Ptr<SpectrumChannel> channel,
                                              const FrequencyRange& freqRange)
@@ -528,7 +542,9 @@
 nor 802.11ac-style Very High Throughput (VHT) nor 802.11ax-style High Efficiency (HE) support enabled.
 
 For example the following user code configures a non-QoS and non-HT/non-VHT/non-HE MAC that
-will be a non-AP STA in an infrastructure network where the AP has SSID ``ns-3-ssid``::
+will be a non-AP STA in an infrastructure network where the AP has SSID ``ns-3-ssid``:
+
+.. sourcecode:: cpp
 
     WifiMacHelper wifiMacHelper;
     Ssid ssid = Ssid("ns-3-ssid");
@@ -536,7 +552,9 @@
                          "Ssid", SsidValue(ssid),
                          "ActiveProbing", BooleanValue(false));
 
-The following code shows how to create an AP with QoS enabled::
+The following code shows how to create an AP with QoS enabled:
+
+.. sourcecode:: cpp
 
   WifiMacHelper wifiMacHelper;
   wifiMacHelper.SetType("ns3::ApWifiMac",
@@ -563,7 +581,9 @@
 * block ack inactivity timeout.
 
 For example the following user code configures a MAC that will be a non-AP STA with QoS enabled and a block ack threshold for AC_BE set to 2 packets,
-in an infrastructure network where the AP has SSID ``ns-3-ssid``::
+in an infrastructure network where the AP has SSID ``ns-3-ssid``:
+
+.. sourcecode:: cpp
 
     WifiMacHelper wifiMacHelper;
     Ssid ssid = Ssid("ns-3-ssid");
@@ -582,7 +602,9 @@
 By default, MSDU aggregation feature is disabled for all ACs and MPDU aggregation is enabled for AC_VI and AC_BE, with a maximum aggregation size of 65535 bytes.
 
 For example the following user code configures a MAC that will be a non-AP STA with HT and QoS enabled, MPDU aggregation enabled for AC_VO with a maximum aggregation size of 65535 bytes, and MSDU aggregation enabled for AC_BE with a maximum aggregation size of 7935 bytes,
-in an infrastructure network where the AP has SSID ``ns-3-ssid``::
+in an infrastructure network where the AP has SSID ``ns-3-ssid``:
+
+.. sourcecode:: cpp
 
     WifiHelper wifi;
     wifi.SetStandard(WIFI_STANDARD_80211n);
@@ -597,7 +619,9 @@
 
 802.11ax APs support sending multi-user frames via DL OFDMA and UL OFDMA if a Multi-User Scheduler is
 aggregated to the wifi MAC(by default no scheduler is aggregated). WifiMacHelper enables to aggregate
-a Multi-User Scheduler to an AP and set its parameters::
+a Multi-User Scheduler to an AP and set its parameters:
+
+.. sourcecode:: cpp
 
     WifiMacHelper wifiMacHelper;
     wifiMacHelper.SetMultiUserScheduler("ns3::RrMultiUserScheduler",
@@ -606,7 +630,9 @@
 
 The Ack Manager is in charge of selecting the acknowledgment method among the three
 available methods(see section :ref:`wifi-mu-ack-sequences` ). The default ack manager
-enables to select the acknowledgment method, e.g.::
+enables to select the acknowledgment method, e.g.:
+
+.. sourcecode:: cpp
 
     Config::SetDefault("ns3::WifiDefaultAckManager::DlMuAckSequenceType",
                        EnumValue(WifiAcknowledgment::DL_MU_AGGREGATE_TF));
@@ -620,7 +646,9 @@
 Traffic Class field in case of IPv6). Details on how to set the ToS field of IPv4
 packets are given in the :ref:`Type-of-service` section of the documentation. In
 summary, users can create an address of type :cpp:class:`ns3::InetSocketAddress`
-with the desired type of service value and pass it to the application helpers::
+with the desired type of service value and pass it to the application helpers:
+
+.. sourcecode:: cpp
 
     InetSocketAddress destAddress(ipv4Address, udpPort);
     destAddress.SetTos(tos);
@@ -674,7 +702,9 @@
 CS7           111000xx      7   AC_VO
 ============  ============  ==  ===============
 
-So, for example,::
+So, for example,
+
+.. sourcecode:: cpp
 
     destAddress.SetTos(0xc0);
 
@@ -696,7 +726,9 @@
 ==========
 
 We're now ready to create WifiNetDevices. First, let's create
-a WifiHelper with default settings::
+a WifiHelper with default settings:
+
+.. sourcecode:: cpp
 
   WifiHelper wifiHelper;
 
@@ -706,7 +738,9 @@
 ``WifiHelper::SetStandard`` method with the desired standard.
 
 Now, let's use the wifiPhyHelper and wifiMacHelper created above to install WifiNetDevices
-on a set of nodes in a NodeContainer "c"::
+on a set of nodes in a NodeContainer "c":
+
+.. sourcecode:: cpp
 
   NetDeviceContainer wifiContainer = WifiHelper::Install(wifiPhyHelper, wifiMacHelper, c);
 
@@ -714,7 +748,9 @@
 WifiMac, and a WifiPhy (connected to the matching Channel).
 
 The ``WifiHelper::SetStandard`` method sets various default timing parameters as defined in the selected standard version, overwriting values that may exist or have been previously configured.
-In order to change parameters that are overwritten by ``WifiHelper::SetStandard``, this should be done post-install using ``Config::Set``::
+In order to change parameters that are overwritten by ``WifiHelper::SetStandard``, this should be done post-install using ``Config::Set``:
+
+.. sourcecode:: cpp
 
   WifiHelper wifi;
   wifi.SetStandard(WIFI_STANDARD_80211n);
@@ -746,7 +782,9 @@
 (``ConstantWifiAckPolicySelector``) or to select a different (user provided) ack
 policy selector, for each of the available Access Categories. As an example, the
 following code can be used to set the BaThreshold attribute of the default ack
-policy selector associated with BE AC to 0.5::
+policy selector associated with BE AC to 0.5:
+
+.. sourcecode:: cpp
 
   WifiHelper wifi;
   wifi.SetAckPolicySelectorForAc(AC_BE, "ns3::ConstantWifiAckPolicySelector",
@@ -754,7 +792,9 @@
 
 The WifiHelper is also used to configure OBSS PD spatial reuse for 802.11ax.
 The following lines configure a WifiHelper to support OBSS PD spatial reuse
-using the ``ConstantObssPdAlgorithm`` with a threshold set to -72 dBm::
+using the ``ConstantObssPdAlgorithm`` with a threshold set to -72 dBm:
+
+.. sourcecode:: cpp
 
   WifiHelper wifi;
   wifi.SetObssPdAlgorithm("ns3::ConstantObssPdAlgorithm",
@@ -774,7 +814,9 @@
 created for the device.  The configuration object is used to store and
 manage HT-specific attributes.
 
-802.11n/ac PHY layer can use either long (800 ns) or short (400 ns) OFDM guard intervals. To configure this parameter for a given device, the following lines of code could be used (in this example, it enables the support of a short guard interval for the first station)::
+802.11n/ac PHY layer can use either long (800 ns) or short (400 ns) OFDM guard intervals. To configure this parameter for a given device, the following lines of code could be used (in this example, it enables the support of a short guard interval for the first station):
+
+.. sourcecode:: cpp
 
  Ptr<NetDevice> nd = wifiStaDevices.Get(0);
  Ptr<WifiNetDevice> wnd = nd->GetObject<WifiNetDevice>();
@@ -782,7 +824,9 @@
  htConfiguration->SetShortGuardIntervalSupported(true);
 
 It is also possible to configure HT-specific attributes using ``Config::Set``.
-The following line of code enables the support of a short guard interval for all stations::
+The following line of code enables the support of a short guard interval for all stations:
+
+.. sourcecode:: cpp
 
  Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/ShortGuardIntervalSupported", BooleanValue(true));
 
@@ -803,7 +847,9 @@
 HE configuration object will automatically be created to manage HE-specific
 attributes for 802.11ax devices.
 
-802.11ax PHY layer can use either 3200 ns, 1600 ns or 800 ns OFDM guard intervals. To configure this parameter, the following lines of code could be used (in this example, it enables the support of 1600 ns guard interval), such as in this example code snippet::
+802.11ax PHY layer can use either 3200 ns, 1600 ns or 800 ns OFDM guard intervals. To configure this parameter, the following lines of code could be used (in this example, it enables the support of 1600 ns guard interval), such as in this example code snippet:
+
+.. sourcecode:: cpp
 
  Ptr<NetDevice> nd = wifiStaDevices.Get(0);
  Ptr<WifiNetDevice> wnd = nd->GetObject<WifiNetDevice>();
@@ -813,7 +859,9 @@
 802.11ax allows extended compressed Block ACKs containing a 256-bits bitmap, making
 possible transmissions of A-MPDUs containing up to 256 MPDUs, depending on the
 negotiated buffer size. In order to configure the buffer size of an 802.11ax device,
-the following line of code could be used::
+the following line of code could be used:
+
+.. sourcecode:: cpp
 
  heConfiguration->SetMpduBufferSize(256);
 
@@ -853,7 +901,9 @@
 We use the ``ns3::ConstantSpeedPropagationDelayModel`` as the propagation delay model and
 ``ns3::LogDistancePropagationLossModel`` with the exponent of 3.0 as the propagation loss model.
 Both devices are configured with ``ConstantRateWifiManager`` at the fixed rate of 12Mbps.
-Finally, we manually place them by using the ``ns3::ListPositionAllocator``::
+Finally, we manually place them by using the ``ns3::ListPositionAllocator``:
+
+.. sourcecode:: cpp
 
   std::string phyMode("OfdmRate12Mbps");
 
@@ -898,7 +948,9 @@
 
 This is a typical example of how a user might configure an access point and a set of clients.
 In this example, we create one access point and two clients.
-Each node is equipped with 802.11b Wi-Fi device::
+Each node is equipped with 802.11b Wi-Fi device:
+
+.. sourcecode:: cpp
 
   std::string phyMode("DsssRate1Mbps");
 
@@ -960,6 +1012,8 @@
 Multiple RF interfaces configuration
 ++++++++++++++++++++++++++++++++++++
 
+.. sourcecode:: cpp
+
   NodeContainer ap;
   ap.Create(1);
   NodeContainer sta;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/examples/reference/bianchi11ax.py ns-3.40/src/wifi/examples/reference/bianchi11ax.py
--- ns-3.39/src/wifi/examples/reference/bianchi11ax.py	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/examples/reference/bianchi11ax.py	2023-09-27 13:30:37.898839700 -0700
@@ -129,41 +129,39 @@
 k = 1
 
 difs = 1
-fo = open("bianchi_11ax_difs.txt", "w")
-for i in range(len(data_rates_20MHz)):
-    bianchi_result = bianchi_ax(data_rates_20MHz[i], ack_rates_20MHz[i], k, difs)
-    str_s = str_result(bianchi_result, i, 20)
-    fo.write(str_s)
-for i in range(len(data_rates_40MHz)):
-    bianchi_result = bianchi_ax(data_rates_40MHz[i], ack_rates_40MHz[i], k, difs)
-    str_s = str_result(bianchi_result, i, 40)
-    fo.write(str_s)
-for i in range(len(data_rates_80MHz)):
-    bianchi_result = bianchi_ax(data_rates_80MHz[i], ack_rates_80MHz[i], k, difs)
-    str_s = str_result(bianchi_result, i, 80)
-    fo.write(str_s)
-for i in range(len(data_rates_160MHz)):
-    bianchi_result = bianchi_ax(data_rates_160MHz[i], ack_rates_160MHz[i], k, difs)
-    str_s = str_result(bianchi_result, i, 160)
-    fo.write(str_s)
-fo.close()
+with open("bianchi_11ax_difs.txt", "w", encoding="utf-8") as fo:
+    for i in range(len(data_rates_20MHz)):
+        bianchi_result = bianchi_ax(data_rates_20MHz[i], ack_rates_20MHz[i], k, difs)
+        str_s = str_result(bianchi_result, i, 20)
+        fo.write(str_s)
+    for i in range(len(data_rates_40MHz)):
+        bianchi_result = bianchi_ax(data_rates_40MHz[i], ack_rates_40MHz[i], k, difs)
+        str_s = str_result(bianchi_result, i, 40)
+        fo.write(str_s)
+    for i in range(len(data_rates_80MHz)):
+        bianchi_result = bianchi_ax(data_rates_80MHz[i], ack_rates_80MHz[i], k, difs)
+        str_s = str_result(bianchi_result, i, 80)
+        fo.write(str_s)
+    for i in range(len(data_rates_160MHz)):
+        bianchi_result = bianchi_ax(data_rates_160MHz[i], ack_rates_160MHz[i], k, difs)
+        str_s = str_result(bianchi_result, i, 160)
+        fo.write(str_s)
 
 difs = 0
-fo = open("bianchi_11ax_eifs.txt", "w")
-for i in range(len(data_rates_20MHz)):
-    bianchi_result = bianchi_ax(data_rates_20MHz[i], ack_rates_20MHz[i], k, difs)
-    str_s = str_result(bianchi_result, i, 20)
-    fo.write(str_s)
-for i in range(len(data_rates_40MHz)):
-    bianchi_result = bianchi_ax(data_rates_40MHz[i], ack_rates_40MHz[i], k, difs)
-    str_s = str_result(bianchi_result, i, 40)
-    fo.write(str_s)
-for i in range(len(data_rates_80MHz)):
-    bianchi_result = bianchi_ax(data_rates_80MHz[i], ack_rates_80MHz[i], k, difs)
-    str_s = str_result(bianchi_result, i, 80)
-    fo.write(str_s)
-for i in range(len(data_rates_160MHz)):
-    bianchi_result = bianchi_ax(data_rates_160MHz[i], ack_rates_160MHz[i], k, difs)
-    str_s = str_result(bianchi_result, i, 160)
-    fo.write(str_s)
-fo.close()
+with open("bianchi_11ax_eifs.txt", "w", encoding="utf-8") as fo:
+    for i in range(len(data_rates_20MHz)):
+        bianchi_result = bianchi_ax(data_rates_20MHz[i], ack_rates_20MHz[i], k, difs)
+        str_s = str_result(bianchi_result, i, 20)
+        fo.write(str_s)
+    for i in range(len(data_rates_40MHz)):
+        bianchi_result = bianchi_ax(data_rates_40MHz[i], ack_rates_40MHz[i], k, difs)
+        str_s = str_result(bianchi_result, i, 40)
+        fo.write(str_s)
+    for i in range(len(data_rates_80MHz)):
+        bianchi_result = bianchi_ax(data_rates_80MHz[i], ack_rates_80MHz[i], k, difs)
+        str_s = str_result(bianchi_result, i, 80)
+        fo.write(str_s)
+    for i in range(len(data_rates_160MHz)):
+        bianchi_result = bianchi_ax(data_rates_160MHz[i], ack_rates_160MHz[i], k, difs)
+        str_s = str_result(bianchi_result, i, 160)
+        fo.write(str_s)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/examples/wifi-manager-example.cc ns-3.40/src/wifi/examples/wifi-manager-example.cc
--- ns-3.39/src/wifi/examples/wifi-manager-example.cc	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/examples/wifi-manager-example.cc	2023-09-27 13:30:37.898839700 -0700
@@ -211,7 +211,7 @@
     double stepSize = 1;        // dBm
     double stepTime = 1;        // seconds
     uint32_t packetSize = 1024; // bytes
-    bool broadcast = 0;
+    bool broadcast = false;
     int ap1_x = 0;
     int ap1_y = 0;
     int sta1_x = 5;
@@ -714,8 +714,8 @@
     Ptr<WifiNetDevice> wndServer = ndServer->GetObject<WifiNetDevice>();
     Ptr<WifiPhy> wifiPhyPtrClient = wndClient->GetPhy();
     Ptr<WifiPhy> wifiPhyPtrServer = wndServer->GetPhy();
-    uint8_t t_clientNss = static_cast<uint8_t>(clientNss);
-    uint8_t t_serverNss = static_cast<uint8_t>(serverNss);
+    auto t_clientNss = static_cast<uint8_t>(clientNss);
+    auto t_serverNss = static_cast<uint8_t>(serverNss);
     wifiPhyPtrClient->SetNumberOfAntennas(t_clientNss);
     wifiPhyPtrClient->SetMaxSupportedTxSpatialStreams(t_clientNss);
     wifiPhyPtrClient->SetMaxSupportedRxSpatialStreams(t_clientNss);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/helper/athstats-helper.cc ns-3.40/src/wifi/helper/athstats-helper.cc
--- ns-3.39/src/wifi/helper/athstats-helper.cc	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/helper/athstats-helper.cc	2023-09-27 13:30:37.898839700 -0700
@@ -30,6 +30,7 @@
 
 #include <fstream>
 #include <iomanip>
+#include <sstream>
 
 namespace ns3
 {
@@ -87,7 +88,7 @@
 void
 AthstatsHelper::EnableAthstats(std::string filename, NetDeviceContainer d)
 {
-    for (NetDeviceContainer::Iterator i = d.Begin(); i != d.End(); ++i)
+    for (auto i = d.Begin(); i != d.End(); ++i)
     {
         Ptr<NetDevice> dev = *i;
         EnableAthstats(filename, dev->GetNode()->GetId(), dev->GetIfIndex());
@@ -98,7 +99,7 @@
 AthstatsHelper::EnableAthstats(std::string filename, NodeContainer n)
 {
     NetDeviceContainer devs;
-    for (NodeContainer::Iterator i = n.Begin(); i != n.End(); ++i)
+    for (auto i = n.Begin(); i != n.End(); ++i)
     {
         Ptr<Node> node = *i;
         for (std::size_t j = 0; j < node->GetNDevices(); ++j)
@@ -286,36 +287,36 @@
 AthstatsWifiTraceSink::WriteStats()
 {
     NS_LOG_FUNCTION(this);
-    // The comments below refer to how each value maps to madwifi's athstats
-    // I know C strings are ugly but that's the quickest way to use exactly the same format as in
-    // madwifi
-    char str[200];
-    snprintf(
-        str,
-        200,
-        "%8u %8u %7u %7u %7u %6u %6u %6u %7u %4u %3uM\n",
-        (unsigned int)m_txCount, // /proc/net/dev transmitted packets to which we should subtract
-                                 // management frames
-        (unsigned int)
-            m_rxCount,   // /proc/net/dev received packets but subtracts management frames from it
-        (unsigned int)0, // ast_tx_altrate
-        (unsigned int)m_shortRetryCount,    // ast_tx_shortretry
-        (unsigned int)m_longRetryCount,     // ast_tx_longretry
-        (unsigned int)m_exceededRetryCount, // ast_tx_xretries
-        (unsigned int)m_phyRxErrorCount,    // ast_rx_crcerr
-        (unsigned int)0,                    // ast_rx_badcrypt
-        (unsigned int)0,                    // ast_rx_phyerr
-        (unsigned int)0,                    // ast_rx_rssi
-        (unsigned int)0                     // rate
-    );
 
-    if (m_writer)
+    if (!m_writer)
     {
-        *m_writer << str;
-
-        ResetCounters();
-        Simulator::Schedule(m_interval, &AthstatsWifiTraceSink::WriteStats, this);
+        return;
     }
+
+    // The comments below refer to how each value maps to madwifi's athstats.
+    // Format: "%8lu %8lu %7u %7u %7u %6u %6u %6u %7u %4u %3uM"
+    std::stringstream ss;
+
+    // /proc/net/dev transmitted packets to which we should subtract management frames
+    ss << std::setw(8) << m_txCount << " ";
+
+    // /proc/net/dev received packets but subtracts management frames from it
+    ss << std::setw(8) << m_rxCount << " ";
+
+    ss << std::setw(7) << 0 << " ";                    // ast_tx_altrate
+    ss << std::setw(7) << m_shortRetryCount << " ";    // ast_tx_shortretry
+    ss << std::setw(7) << m_longRetryCount << " ";     // ast_tx_longretry
+    ss << std::setw(6) << m_exceededRetryCount << " "; // ast_tx_xretries
+    ss << std::setw(6) << m_phyRxErrorCount << " ";    // ast_rx_crcerr
+    ss << std::setw(6) << 0 << " ";                    // ast_rx_badcrypt
+    ss << std::setw(7) << 0 << " ";                    // ast_rx_phyerr
+    ss << std::setw(4) << 0 << " ";                    // ast_rx_rssi
+    ss << std::setw(3) << 0 << "M";                    // rate
+
+    *m_writer << ss.str() << std::endl;
+
+    ResetCounters();
+    Simulator::Schedule(m_interval, &AthstatsWifiTraceSink::WriteStats, this);
 }
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/helper/spectrum-wifi-helper.cc ns-3.40/src/wifi/helper/spectrum-wifi-helper.cc
--- ns-3.39/src/wifi/helper/spectrum-wifi-helper.cc	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/helper/spectrum-wifi-helper.cc	2023-09-27 13:30:37.898839700 -0700
@@ -42,8 +42,8 @@
 SpectrumWifiPhyHelper::SpectrumWifiPhyHelper(uint8_t nLinks)
     : WifiPhyHelper(nLinks)
 {
-    NS_ABORT_IF(m_phy.size() != nLinks);
-    for (auto& phy : m_phy)
+    NS_ABORT_IF(m_phys.size() != nLinks);
+    for (auto& phy : m_phys)
     {
         phy.SetTypeId("ns3::SpectrumWifiPhy");
     }
@@ -54,16 +54,13 @@
 void
 SpectrumWifiPhyHelper::SetChannel(const Ptr<SpectrumChannel> channel)
 {
-    m_channels[WHOLE_WIFI_SPECTRUM] = channel;
-    AddWifiBandwidthFilter(channel);
+    AddChannel(channel);
 }
 
 void
 SpectrumWifiPhyHelper::SetChannel(const std::string& channelName)
 {
-    Ptr<SpectrumChannel> channel = Names::Find<SpectrumChannel>(channelName);
-    m_channels[WHOLE_WIFI_SPECTRUM] = channel;
-    AddWifiBandwidthFilter(channel);
+    AddChannel(channelName);
 }
 
 void
@@ -79,7 +76,6 @@
 {
     Ptr<SpectrumChannel> channel = Names::Find<SpectrumChannel>(channelName);
     AddChannel(channel, freqRange);
-    AddWifiBandwidthFilter(channel);
 }
 
 void
@@ -108,17 +104,36 @@
     }
 }
 
+void
+SpectrumWifiPhyHelper::AddPhyToFreqRangeMapping(uint8_t linkId, const FrequencyRange& freqRange)
+{
+    if (auto it = m_interfacesMap.find(linkId); it == m_interfacesMap.end())
+    {
+        m_interfacesMap.insert({linkId, {freqRange}});
+    }
+    else
+    {
+        it->second.emplace(freqRange);
+    }
+}
+
+void
+SpectrumWifiPhyHelper::ResetPhyToFreqRangeMapping()
+{
+    m_interfacesMap.clear();
+}
+
 std::vector<Ptr<WifiPhy>>
 SpectrumWifiPhyHelper::Create(Ptr<Node> node, Ptr<WifiNetDevice> device) const
 {
     std::vector<Ptr<WifiPhy>> ret;
 
-    for (std::size_t i = 0; i < m_phy.size(); i++)
+    for (std::size_t i = 0; i < m_phys.size(); i++)
     {
-        Ptr<SpectrumWifiPhy> phy = m_phy.at(i).Create<SpectrumWifiPhy>();
+        auto phy = m_phys.at(i).Create<SpectrumWifiPhy>();
         auto interference = m_interferenceHelper.Create<InterferenceHelper>();
         phy->SetInterferenceHelper(interference);
-        Ptr<ErrorRateModel> error = m_errorRateModel.at(i).Create<ErrorRateModel>();
+        auto error = m_errorRateModel.at(i).Create<ErrorRateModel>();
         phy->SetErrorRateModel(error);
         if (m_frameCaptureModel.at(i).IsTypeIdSet())
         {
@@ -131,10 +146,9 @@
                 m_preambleDetectionModel.at(i).Create<PreambleDetectionModel>();
             phy->SetPreambleDetectionModel(preambleDetection);
         }
-        for (const auto& [freqRange, channel] : m_channels)
-        {
-            phy->AddChannel(channel, freqRange);
-        }
+        InstallPhyInterfaces(i, phy);
+        phy->SetChannelSwitchedCallback(
+            MakeCallback(&SpectrumWifiPhyHelper::SpectrumChannelSwitched, this).Bind(phy));
         phy->SetDevice(device);
         phy->SetMobility(node->GetObject<MobilityModel>());
         ret.emplace_back(phy);
@@ -143,4 +157,52 @@
     return ret;
 }
 
+void
+SpectrumWifiPhyHelper::InstallPhyInterfaces(uint8_t linkId, Ptr<SpectrumWifiPhy> phy) const
+{
+    if (m_interfacesMap.count(linkId) == 0)
+    {
+        // default setup: set all interfaces to this link
+        for (const auto& [freqRange, channel] : m_channels)
+        {
+            phy->AddChannel(channel, freqRange);
+        }
+    }
+    else
+    {
+        for (const auto& freqRange : m_interfacesMap.at(linkId))
+        {
+            phy->AddChannel(m_channels.at(freqRange), freqRange);
+        }
+    }
+}
+
+void
+SpectrumWifiPhyHelper::SpectrumChannelSwitched(Ptr<SpectrumWifiPhy> phy) const
+{
+    NS_LOG_FUNCTION(this << phy);
+    for (const auto& otherPhy : phy->GetDevice()->GetPhys())
+    {
+        auto spectrumPhy = DynamicCast<SpectrumWifiPhy>(otherPhy);
+        NS_ASSERT(spectrumPhy);
+        if (spectrumPhy == phy)
+        {
+            // this is the PHY that has switched
+            continue;
+        }
+        if (spectrumPhy->GetCurrentFrequencyRange() == phy->GetCurrentFrequencyRange())
+        {
+            // this is the active interface
+            continue;
+        }
+        if (const auto& interfaces = spectrumPhy->GetSpectrumPhyInterfaces();
+            interfaces.count(phy->GetCurrentFrequencyRange()) == 0)
+        {
+            // no interface attached to that channel
+            continue;
+        }
+        spectrumPhy->ConfigureInterface(phy->GetFrequency(), phy->GetChannelWidth());
+    }
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/helper/spectrum-wifi-helper.h ns-3.40/src/wifi/helper/spectrum-wifi-helper.h
--- ns-3.39/src/wifi/helper/spectrum-wifi-helper.h	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/helper/spectrum-wifi-helper.h	2023-09-27 13:30:37.898839700 -0700
@@ -22,10 +22,14 @@
 
 #include "wifi-helper.h"
 
+#include <map>
+#include <set>
+
 namespace ns3
 {
 
 class SpectrumChannel;
+class SpectrumWifiPhy;
 
 /**
  * \brief Make it easy to create and manage PHY objects for the spectrum model.
@@ -81,6 +85,21 @@
     void AddChannel(const std::string& channelName,
                     const FrequencyRange& freqRange = WHOLE_WIFI_SPECTRUM);
 
+    /**
+     * Add a given spectrum PHY interface to the PHY instance corresponding of a given link.
+     * If no mapping has been specified for a given link, all spectrum PHY interfaces will
+     * be added to the PHY instance of that link.
+     *
+     * \param linkId ID of the link to setup
+     * \param freqRange frequency range handled by of the spectrum PHY interface
+     */
+    void AddPhyToFreqRangeMapping(uint8_t linkId, const FrequencyRange& freqRange);
+
+    /**
+     * Reset mapping of the spectrum PHY interfaces added to the PHY instances.
+     */
+    void ResetPhyToFreqRangeMapping();
+
   private:
     /**
      * \param node the node on which we wish to create a wifi PHY
@@ -90,6 +109,22 @@
      * This method implements the pure virtual method defined in \ref ns3::WifiPhyHelper.
      */
     std::vector<Ptr<WifiPhy>> Create(Ptr<Node> node, Ptr<WifiNetDevice> device) const override;
+
+    /**
+     * \brief Install PHY interfaces to the PHY instance of a given link
+     * based on the currently configured mapping (\see AddPhyInterface).
+     *
+     * \param linkId ID of the link to setup
+     * \param phy spectrum PHY instance of the link
+     */
+    void InstallPhyInterfaces(uint8_t linkId, Ptr<SpectrumWifiPhy> phy) const;
+
+    /**
+     * Function that is notified when a spectrum channel switched
+     * \param phy spectrum PHY instance that has switched its channel
+     */
+    void SpectrumChannelSwitched(Ptr<SpectrumWifiPhy> phy) const;
+
     /**
      * \param channel The channel to inspect to possibly add a WifiBandwidthFilter
      *
@@ -99,6 +134,9 @@
     void AddWifiBandwidthFilter(Ptr<SpectrumChannel> channel);
 
     std::map<FrequencyRange, Ptr<SpectrumChannel>> m_channels; ///< the spectrum channels
+    std::map<uint8_t /* linkId */, std::set<FrequencyRange>>
+        m_interfacesMap; ///< map of the spectrum PHY interfaces to be added to the PHY instance
+                         ///< corresponding to a given link ID
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/helper/wifi-helper.cc ns-3.40/src/wifi/helper/wifi-helper.cc
--- ns-3.39/src/wifi/helper/wifi-helper.cc	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/helper/wifi-helper.cc	2023-09-27 13:30:37.898839700 -0700
@@ -147,7 +147,7 @@
     : m_pcapDlt(PcapHelper::DLT_IEEE802_11)
 {
     NS_ABORT_IF(nLinks == 0);
-    m_phy.resize(nLinks);
+    m_phys.resize(nLinks);
     m_errorRateModel.resize(nLinks);
     m_frameCaptureModel.resize(nLinks);
     m_preambleDetectionModel.resize(nLinks);
@@ -162,7 +162,7 @@
 void
 WifiPhyHelper::Set(std::string name, const AttributeValue& v)
 {
-    for (auto& phy : m_phy)
+    for (auto& phy : m_phys)
     {
         phy.Set(name, v);
     }
@@ -171,7 +171,7 @@
 void
 WifiPhyHelper::Set(uint8_t linkId, std::string name, const AttributeValue& v)
 {
-    m_phy.at(linkId).Set(name, v);
+    m_phys.at(linkId).Set(name, v);
 }
 
 void
@@ -759,7 +759,7 @@
                     NodeContainer::Iterator last) const
 {
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = first; i != last; ++i)
+    for (auto i = first; i != last; ++i)
     {
         Ptr<Node> node = *i;
         Ptr<WifiNetDevice> device = CreateObject<WifiNetDevice>();
@@ -975,6 +975,11 @@
     LogComponentEnable("YansWifiChannel", LOG_LEVEL_ALL);
     LogComponentEnable("YansWifiPhy", LOG_LEVEL_ALL);
 
+    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);
 }
@@ -984,7 +989,7 @@
 {
     int64_t currentStream = stream;
     Ptr<NetDevice> netDevice;
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         netDevice = (*i);
         Ptr<WifiNetDevice> wifi = DynamicCast<WifiNetDevice>(netDevice);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/helper/wifi-helper.h ns-3.40/src/wifi/helper/wifi-helper.h
--- ns-3.39/src/wifi/helper/wifi-helper.h	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/helper/wifi-helper.h	2023-09-27 13:30:37.898839700 -0700
@@ -235,7 +235,7 @@
                                  SignalNoiseDbm signalNoise,
                                  uint16_t staId = SU_STA_ID);
 
-    std::vector<ObjectFactory> m_phy;                    ///< PHY object
+    std::vector<ObjectFactory> m_phys;                   ///< PHY objects
     ObjectFactory m_interferenceHelper;                  ///< interference helper
     std::vector<ObjectFactory> m_errorRateModel;         ///< error rate model
     std::vector<ObjectFactory> m_frameCaptureModel;      ///< frame capture model
@@ -549,7 +549,7 @@
 void
 WifiPhyHelper::SetErrorRateModel(std::string type, Args&&... args)
 {
-    for (std::size_t linkId = 0; linkId < m_phy.size(); linkId++)
+    for (std::size_t linkId = 0; linkId < m_phys.size(); linkId++)
     {
         SetErrorRateModel(linkId, type, std::forward<Args>(args)...);
     }
@@ -567,7 +567,7 @@
 void
 WifiPhyHelper::SetFrameCaptureModel(std::string type, Args&&... args)
 {
-    for (std::size_t linkId = 0; linkId < m_phy.size(); linkId++)
+    for (std::size_t linkId = 0; linkId < m_phys.size(); linkId++)
     {
         SetFrameCaptureModel(linkId, type, std::forward<Args>(args)...);
     }
@@ -585,7 +585,7 @@
 void
 WifiPhyHelper::SetPreambleDetectionModel(std::string type, Args&&... args)
 {
-    for (std::size_t linkId = 0; linkId < m_phy.size(); linkId++)
+    for (std::size_t linkId = 0; linkId < m_phys.size(); linkId++)
     {
         SetPreambleDetectionModel(linkId, type, std::forward<Args>(args)...);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/helper/yans-wifi-helper.cc ns-3.40/src/wifi/helper/yans-wifi-helper.cc
--- ns-3.39/src/wifi/helper/yans-wifi-helper.cc	2023-07-05 14:23:48.105428500 -0700
+++ ns-3.40/src/wifi/helper/yans-wifi-helper.cc	2023-09-27 13:30:37.898839700 -0700
@@ -54,9 +54,7 @@
 {
     Ptr<YansWifiChannel> channel = CreateObject<YansWifiChannel>();
     Ptr<PropagationLossModel> prev = nullptr;
-    for (std::vector<ObjectFactory>::const_iterator i = m_propagationLoss.begin();
-         i != m_propagationLoss.end();
-         ++i)
+    for (auto i = m_propagationLoss.begin(); i != m_propagationLoss.end(); ++i)
     {
         Ptr<PropagationLossModel> cur = (*i).Create<PropagationLossModel>();
         if (prev)
@@ -84,7 +82,7 @@
     : WifiPhyHelper(1), // YANS phy is not used for 11be devices
       m_channel(nullptr)
 {
-    m_phy.at(0).SetTypeId("ns3::YansWifiPhy");
+    m_phys.front().SetTypeId("ns3::YansWifiPhy");
     SetInterferenceHelper("ns3::InterferenceHelper");
     SetErrorRateModel("ns3::TableBasedErrorRateModel");
 }
@@ -105,19 +103,19 @@
 std::vector<Ptr<WifiPhy>>
 YansWifiPhyHelper::Create(Ptr<Node> node, Ptr<WifiNetDevice> device) const
 {
-    Ptr<YansWifiPhy> phy = m_phy.at(0).Create<YansWifiPhy>();
+    Ptr<YansWifiPhy> phy = m_phys.front().Create<YansWifiPhy>();
     Ptr<InterferenceHelper> interference = m_interferenceHelper.Create<InterferenceHelper>();
     phy->SetInterferenceHelper(interference);
-    Ptr<ErrorRateModel> error = m_errorRateModel.at(0).Create<ErrorRateModel>();
+    Ptr<ErrorRateModel> error = m_errorRateModel.front().Create<ErrorRateModel>();
     phy->SetErrorRateModel(error);
-    if (m_frameCaptureModel.at(0).IsTypeIdSet())
+    if (m_frameCaptureModel.front().IsTypeIdSet())
     {
-        auto frameCapture = m_frameCaptureModel.at(0).Create<FrameCaptureModel>();
+        auto frameCapture = m_frameCaptureModel.front().Create<FrameCaptureModel>();
         phy->SetFrameCaptureModel(frameCapture);
     }
-    if (m_preambleDetectionModel.at(0).IsTypeIdSet())
+    if (m_preambleDetectionModel.front().IsTypeIdSet())
     {
-        auto preambleDetection = m_preambleDetectionModel.at(0).Create<PreambleDetectionModel>();
+        auto preambleDetection = m_preambleDetectionModel.front().Create<PreambleDetectionModel>();
         phy->SetPreambleDetectionModel(preambleDetection);
     }
     phy->SetChannel(m_channel);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/ampdu-subframe-header.cc ns-3.40/src/wifi/model/ampdu-subframe-header.cc
--- ns-3.39/src/wifi/model/ampdu-subframe-header.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/ampdu-subframe-header.cc	2023-09-27 13:30:37.902840000 -0700
@@ -44,7 +44,7 @@
 
 AmpduSubframeHeader::AmpduSubframeHeader()
     : m_length(0),
-      m_eof(0),
+      m_eof(false),
       m_signature(0x4E) // Per 802.11 standard, the unique pattern is set to the value 0x4E.
 {
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/ap-wifi-mac.cc ns-3.40/src/wifi/model/ap-wifi-mac.cc
--- ns-3.39/src/wifi/model/ap-wifi-mac.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/ap-wifi-mac.cc	2023-09-27 13:30:37.902840000 -0700
@@ -686,6 +686,25 @@
         mle.SetTransitionTimeout(time.Get());
     }
 
+    // The MLD Capabilities And Operations subfield is present in the Common Info field of the
+    // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
+    // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
+    if (frameType == WIFI_MAC_MGT_BEACON || frameType == WIFI_MAC_MGT_PROBE_RESPONSE ||
+        frameType == WIFI_MAC_MGT_ASSOCIATION_REQUEST ||
+        frameType == WIFI_MAC_MGT_REASSOCIATION_REQUEST ||
+        frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE)
+    {
+        auto& mldCapabilities = mle.GetCommonInfoBasic().m_mldCapabilities;
+        mldCapabilities.emplace();
+        mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
+        mldCapabilities->srsSupport = 0;
+        EnumValue negSupport;
+        ehtConfiguration->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
+        mldCapabilities->tidToLinkMappingSupport = negSupport.Get();
+        mldCapabilities->freqSepForStrApMld = 0; // not supported yet
+        mldCapabilities->aarSupport = 0;         // not supported yet
+    }
+
     // if the Multi-Link Element is being inserted in a (Re)Association Response frame
     // and the remote station is affiliated with an MLD, try multi-link setup
     if (auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
@@ -1083,6 +1102,10 @@
     {
         assoc.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
         assoc.Get<EhtOperation>() = GetEhtOperation(linkId);
+        // The AP MLD that accepts the requested TID-to-link mapping shall not include in the
+        // (Re)Association Response frame the TID-to-link Mapping element.
+        // (Sec. 35.3.7.1.8 of 802.11be D3.1).
+        // For now, we assume that AP MLDs always accept requested TID-to-link mappings.
     }
     return assoc;
 }
@@ -1466,6 +1489,9 @@
                     StaSwitchingToPsMode(*staAddress, i);
                 }
             }
+
+            // Apply the negotiated TID-to-Link Mapping (if any) for DL direction
+            ApplyTidLinkMapping(*staMldAddress, WifiDirection::DOWNLINK);
         }
     }
     else if (hdr.IsAction())
@@ -1747,8 +1773,7 @@
                     packet->PeekHeader(reassocReq);
                     frame = reassocReq;
                 }
-                ReceiveAssocRequest(frame, from, linkId);
-                if (GetNLinks() > 1)
+                if (ReceiveAssocRequest(frame, from, linkId) && GetNLinks() > 1)
                 {
                     ParseReportedStaInfo(frame, from, linkId);
                 }
@@ -1791,9 +1816,9 @@
                     IsAssociated(hdr->GetAddr2()))
                 {
                     // received an EML Operating Mode Notification frame from an associated station
-                    MgtEmlOperatingModeNotification frame;
+                    MgtEmlOmn frame;
                     pkt->RemoveHeader(frame);
-                    ReceiveEmlNotification(frame, hdr->GetAddr2(), linkId);
+                    ReceiveEmlOmn(frame, hdr->GetAddr2(), linkId);
                     return;
                 }
                 break;
@@ -1892,9 +1917,105 @@
         }
         if (GetEhtSupported())
         {
-            // check whether the EHT STA supports all MCSs in Basic MCS Set
-            //  const auto& ehtCapabilities = frame.GetEhtCapabilities ();
-            // TODO: to be completed
+            // TODO check whether the EHT STA supports all MCSs in Basic MCS Set
+            auto ehtConfig = GetEhtConfiguration();
+            NS_ASSERT(ehtConfig);
+
+            if (const auto& tidLinkMapping = frame.template Get<TidToLinkMapping>();
+                !tidLinkMapping.empty())
+            {
+                // non-AP MLD included TID-to-Link Mapping IE(s) in the Association Request.
+                // We refuse association if we do not support TID-to-Link mapping negotiation
+                // or the non-AP MLD included more than two TID-to-Link Mapping IEs
+                // or we support negotiation type 1 but TIDs are mapped onto distinct link sets
+                // or there is some TID that is not mapped to any link
+                // or the direction(s) is/are not set properly
+                if (tidLinkMapping.size() > 2)
+                {
+                    return failure("More than two TID-to-Link Mapping IEs");
+                }
+
+                // if only one Tid-to-Link Mapping element is present, it must be valid for
+                // both directions
+                bool bothDirIfOneTlm =
+                    tidLinkMapping.size() != 1 ||
+                    tidLinkMapping[0].m_control.direction == WifiDirection::BOTH_DIRECTIONS;
+                // An MLD that includes two TID-To-Link Mapping elements in a (Re)Association
+                // Request frame or a (Re)Association Response frame shall set the Direction
+                // subfield in one of the TID-To-Link Mapping elements to 0 and the Direction
+                // subfield in the other TID-To- Link Mapping element to 1.
+                // (Sec. 35.3.7.1.8 of 802.11be D3.1)
+                bool distinctDirsIfTwoTlms =
+                    tidLinkMapping.size() != 2 ||
+                    (tidLinkMapping[0].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
+                     tidLinkMapping[1].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
+                     tidLinkMapping[0].m_control.direction !=
+                         tidLinkMapping[1].m_control.direction);
+
+                if (!bothDirIfOneTlm || !distinctDirsIfTwoTlms)
+                {
+                    return failure("Incorrect directions in TID-to-Link Mapping IEs");
+                }
+
+                EnumValue negSupport;
+                ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
+
+                if (negSupport.Get() == 0)
+                {
+                    return failure("TID-to-Link Mapping negotiation not supported");
+                }
+
+                auto getMapping = [](const TidToLinkMapping& tlmIe, WifiTidLinkMapping& mapping) {
+                    if (tlmIe.m_control.defaultMapping)
+                    {
+                        return;
+                    }
+                    for (uint8_t tid = 0; tid < 8; tid++)
+                    {
+                        if (auto linkSet = tlmIe.GetLinkMappingOfTid(tid); !linkSet.empty())
+                        {
+                            mapping.emplace(tid, std::move(linkSet));
+                        }
+                    }
+                };
+
+                WifiTidLinkMapping dlMapping;
+                WifiTidLinkMapping ulMapping;
+
+                switch (tidLinkMapping[0].m_control.direction)
+                {
+                case WifiDirection::BOTH_DIRECTIONS:
+                    getMapping(tidLinkMapping.at(0), dlMapping);
+                    ulMapping = dlMapping;
+                    break;
+                case WifiDirection::DOWNLINK:
+                    getMapping(tidLinkMapping.at(0), dlMapping);
+                    getMapping(tidLinkMapping.at(1), ulMapping);
+                    break;
+                case WifiDirection::UPLINK:
+                    getMapping(tidLinkMapping.at(0), ulMapping);
+                    getMapping(tidLinkMapping.at(1), dlMapping);
+                    break;
+                }
+
+                if (negSupport.Get() == 1 &&
+                    !TidToLinkMappingValidForNegType1(dlMapping, ulMapping))
+                {
+                    return failure("Mapping TIDs to distinct link sets is incompatible with "
+                                   "negotiation support of 1");
+                }
+
+                // otherwise, we accept the TID-to-link Mapping and store it
+                const auto& mle = frame.template Get<MultiLinkElement>();
+                NS_ASSERT_MSG(mle,
+                              "Multi-Link Element not present in an Association Request including "
+                              "TID-to-Link Mapping element(s)");
+                auto mldAddr = mle->GetMldMacAddress();
+
+                // The requested link mappings are valid and can be accepted; store them.
+                UpdateTidToLinkMapping(mldAddr, WifiDirection::DOWNLINK, dlMapping);
+                UpdateTidToLinkMapping(mldAddr, WifiDirection::UPLINK, ulMapping);
+            }
         }
 
         // The association request from the station can be accepted.
@@ -1975,7 +2096,6 @@
         NS_LOG_DEBUG("Association Request from " << from << " accepted");
         remoteStationManager->RecordWaitAssocTxOk(from);
         return true;
-        ;
     };
 
     return std::visit(recvAssocRequest, assoc);
@@ -1995,18 +2115,8 @@
             return;
         }
 
-        auto emlCapabilities = std::make_shared<CommonInfoBasicMle::EmlCapabilities>();
-        if (mle->HasEmlCapabilities())
-        {
-            emlCapabilities->emlsrSupport = mle->IsEmlsrSupported() ? 1 : 0;
-            emlCapabilities->emlsrPaddingDelay =
-                CommonInfoBasicMle::EncodeEmlsrPaddingDelay(mle->GetEmlsrPaddingDelay());
-            emlCapabilities->emlsrTransitionDelay =
-                CommonInfoBasicMle::EncodeEmlsrTransitionDelay(mle->GetEmlsrTransitionDelay());
-        }
-
-        GetWifiRemoteStationManager(linkId)->SetMldAddress(from, mle->GetMldMacAddress());
-        GetWifiRemoteStationManager(linkId)->AddStationEmlCapabilities(from, emlCapabilities);
+        auto mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
+        GetWifiRemoteStationManager(linkId)->AddStationMleCommonInfo(from, mleCommonInfo);
 
         for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
         {
@@ -2032,11 +2142,9 @@
             ReceiveAssocRequest(perStaProfile.GetAssocRequest(),
                                 perStaProfile.GetStaMacAddress(),
                                 newLinkId);
-            GetWifiRemoteStationManager(newLinkId)->SetMldAddress(perStaProfile.GetStaMacAddress(),
-                                                                  mle->GetMldMacAddress());
-            GetWifiRemoteStationManager(newLinkId)->AddStationEmlCapabilities(
+            GetWifiRemoteStationManager(newLinkId)->AddStationMleCommonInfo(
                 perStaProfile.GetStaMacAddress(),
-                emlCapabilities);
+                mleCommonInfo);
         }
     };
 
@@ -2044,9 +2152,7 @@
 }
 
 void
-ApWifiMac::ReceiveEmlNotification(MgtEmlOperatingModeNotification& frame,
-                                  const Mac48Address& sender,
-                                  uint8_t linkId)
+ApWifiMac::ReceiveEmlOmn(MgtEmlOmn& frame, const Mac48Address& sender, uint8_t linkId)
 {
     NS_LOG_FUNCTION(this << frame << sender << linkId);
 
@@ -2070,8 +2176,8 @@
         NS_ASSERT_MSG(emlCapabilities, "EML Capabilities not stored for STA " << sender);
 
         // update values stored in remote station manager
-        emlCapabilities->emlsrPaddingDelay = frame.m_emlsrParamUpdate->paddingDelay;
-        emlCapabilities->emlsrTransitionDelay = frame.m_emlsrParamUpdate->transitionDelay;
+        emlCapabilities->get().emlsrPaddingDelay = frame.m_emlsrParamUpdate->paddingDelay;
+        emlCapabilities->get().emlsrTransitionDelay = frame.m_emlsrParamUpdate->transitionDelay;
     }
 
     auto mldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(sender);
@@ -2180,7 +2286,7 @@
     frame.m_emlsrParamUpdate.reset();
 
     auto ehtFem = StaticCast<EhtFrameExchangeManager>(GetFrameExchangeManager(linkId));
-    ehtFem->SendEmlOperatingModeNotification(sender, frame);
+    ehtFem->SendEmlOmn(sender, frame);
 }
 
 void
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/ap-wifi-mac.h ns-3.40/src/wifi/model/ap-wifi-mac.h
--- ns-3.39/src/wifi/model/ap-wifi-mac.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/ap-wifi-mac.h	2023-09-27 13:30:37.902840000 -0700
@@ -48,7 +48,7 @@
 class MgtAssocRequestHeader;
 class MgtReassocRequestHeader;
 class MgtAssocResponseHeader;
-class MgtEmlOperatingModeNotification;
+class MgtEmlOmn;
 
 /// variant holding a  reference to a (Re)Association Request
 using AssocReqRefVariant = std::variant<std::reference_wrapper<MgtAssocRequestHeader>,
@@ -246,9 +246,7 @@
      * \param sender the MAC address of the sender of the frame
      * \param linkId the ID of the link over which the frame was received
      */
-    void ReceiveEmlNotification(MgtEmlOperatingModeNotification& frame,
-                                const Mac48Address& sender,
-                                uint8_t linkId);
+    void ReceiveEmlOmn(MgtEmlOmn& frame, const Mac48Address& sender, uint8_t linkId);
 
     /**
      * The packet we sent was successfully received by the receiver
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/block-ack-manager.cc ns-3.40/src/wifi/model/block-ack-manager.cc
--- ns-3.39/src/wifi/model/block-ack-manager.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/block-ack-manager.cc	2023-09-27 13:30:37.902840000 -0700
@@ -30,6 +30,7 @@
 #include "ns3/log.h"
 #include "ns3/simulator.h"
 
+#include <algorithm>
 #include <optional>
 
 namespace ns3
@@ -689,21 +690,6 @@
     m_queue->Enqueue(Create<WifiMpdu>(pkt, hdr));
 }
 
-void
-BlockAckManager::ScheduleMuBar(Ptr<WifiMpdu> muBar)
-{
-    NS_LOG_FUNCTION(this << *muBar);
-    NS_ASSERT(muBar->GetHeader().IsTrigger());
-
-#ifdef NS3_BUILD_PROFILE_DEBUG
-    CtrlTriggerHeader triggerHdr;
-    muBar->GetPacket()->PeekHeader(triggerHdr);
-    NS_ASSERT(triggerHdr.IsMuBar());
-#endif
-
-    m_queue->Enqueue(muBar);
-}
-
 const std::list<BlockAckManager::AgreementKey>&
 BlockAckManager::GetSendBarIfDataQueuedList() const
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/block-ack-manager.h ns-3.40/src/wifi/model/block-ack-manager.h
--- ns-3.39/src/wifi/model/block-ack-manager.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/block-ack-manager.h	2023-09-27 13:30:37.902840000 -0700
@@ -418,14 +418,6 @@
      * it is placed at the head of the queue, otherwise at the tail.
      */
     void ScheduleBar(const CtrlBAckRequestHeader& reqHdr, const WifiMacHeader& hdr);
-    /**
-     * \param muBar the MU-BAR Trigger Frame to enqueue
-     *
-     * Enqueue the given MU-BAR Trigger Frame into the queue storing the next MU-BAR
-     * frames to transmit. If the given MU-BAR Trigger Frame is retransmitted,
-     * it is placed at the head of the queue, otherwise at the tail.
-     */
-    void ScheduleMuBar(Ptr<WifiMpdu> muBar);
 
     /// agreement key typedef (MAC address and TID)
     using AgreementKey = std::pair<Mac48Address, uint8_t>;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/channel-access-manager.cc ns-3.40/src/wifi/model/channel-access-manager.cc
--- ns-3.39/src/wifi/model/channel-access-manager.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/channel-access-manager.cc	2023-09-27 13:30:37.902840000 -0700
@@ -19,14 +19,16 @@
 
 #include "channel-access-manager.h"
 
-#include "frame-exchange-manager.h"
 #include "txop.h"
 #include "wifi-phy-listener.h"
 #include "wifi-phy.h"
 
+#include "ns3/eht-frame-exchange-manager.h"
 #include "ns3/log.h"
 #include "ns3/simulator.h"
 
+#include <sstream>
+
 #undef NS_LOG_APPEND_CONTEXT
 #define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "] "
 
@@ -36,7 +38,11 @@
 NS_LOG_COMPONENT_DEFINE("ChannelAccessManager");
 
 /**
- * Listener for PHY events. Forwards to ChannelAccessManager
+ * Listener for PHY events. Forwards to ChannelAccessManager.
+ * The ChannelAccessManager may handle multiple PHY listeners connected to distinct PHYs,
+ * but only one listener at a time can be active. Notifications from inactive listeners are
+ * ignored by the ChannelAccessManager, except for the channel switch notification.
+ * Inactive PHY listeners are typically configured by 11be EMLSR clients.
  */
 class PhyListener : public ns3::WifiPhyListener
 {
@@ -47,7 +53,8 @@
      * \param cam the ChannelAccessManager
      */
     PhyListener(ns3::ChannelAccessManager* cam)
-        : m_cam(cam)
+        : m_cam(cam),
+          m_active(true)
     {
     }
 
@@ -55,60 +62,106 @@
     {
     }
 
+    /**
+     * Set this listener to be active or not.
+     *
+     * \param active whether this listener is active or not
+     */
+    void SetActive(bool active)
+    {
+        m_active = active;
+    }
+
+    /**
+     * \return whether this listener is active or not
+     */
+    bool IsActive() const
+    {
+        return m_active;
+    }
+
     void NotifyRxStart(Time duration) override
     {
-        m_cam->NotifyRxStartNow(duration);
+        if (m_active)
+        {
+            m_cam->NotifyRxStartNow(duration);
+        }
     }
 
     void NotifyRxEndOk() override
     {
-        m_cam->NotifyRxEndOkNow();
+        if (m_active)
+        {
+            m_cam->NotifyRxEndOkNow();
+        }
     }
 
     void NotifyRxEndError() override
     {
-        m_cam->NotifyRxEndErrorNow();
+        if (m_active)
+        {
+            m_cam->NotifyRxEndErrorNow();
+        }
     }
 
     void NotifyTxStart(Time duration, double txPowerDbm) override
     {
-        m_cam->NotifyTxStartNow(duration);
+        if (m_active)
+        {
+            m_cam->NotifyTxStartNow(duration);
+        }
     }
 
     void NotifyCcaBusyStart(Time duration,
                             WifiChannelListType channelType,
                             const std::vector<Time>& per20MhzDurations) override
     {
-        m_cam->NotifyCcaBusyStartNow(duration, channelType, per20MhzDurations);
+        if (m_active)
+        {
+            m_cam->NotifyCcaBusyStartNow(duration, channelType, per20MhzDurations);
+        }
     }
 
     void NotifySwitchingStart(Time duration) override
     {
-        m_cam->NotifySwitchingStartNow(duration);
+        m_cam->NotifySwitchingStartNow(this, duration);
     }
 
     void NotifySleep() override
     {
-        m_cam->NotifySleepNow();
+        if (m_active)
+        {
+            m_cam->NotifySleepNow();
+        }
     }
 
     void NotifyOff() override
     {
-        m_cam->NotifyOffNow();
+        if (m_active)
+        {
+            m_cam->NotifyOffNow();
+        }
     }
 
     void NotifyWakeup() override
     {
-        m_cam->NotifyWakeupNow();
+        if (m_active)
+        {
+            m_cam->NotifyWakeupNow();
+        }
     }
 
     void NotifyOn() override
     {
-        m_cam->NotifyOnNow();
+        if (m_active)
+        {
+            m_cam->NotifyOnNow();
+        }
     }
 
   private:
     ns3::ChannelAccessManager* m_cam; //!< ChannelAccessManager to forward events to
+    bool m_active;                    //!< whether this PHY listener is active
 };
 
 /****************************************************************
@@ -116,16 +169,17 @@
  ****************************************************************/
 
 ChannelAccessManager::ChannelAccessManager()
-    : m_lastAckTimeoutEnd(MicroSeconds(0)),
-      m_lastCtsTimeoutEnd(MicroSeconds(0)),
-      m_lastNavEnd(MicroSeconds(0)),
+    : m_lastAckTimeoutEnd(0),
+      m_lastCtsTimeoutEnd(0),
+      m_lastNavEnd(0),
       m_lastRx({MicroSeconds(0), MicroSeconds(0)}),
       m_lastRxReceivedOk(true),
-      m_lastTxEnd(MicroSeconds(0)),
-      m_lastSwitchingEnd(MicroSeconds(0)),
+      m_lastTxEnd(0),
+      m_lastSwitchingEnd(0),
+      m_usingOtherEmlsrLink(false),
+      m_lastUsingOtherEmlsrLinkEnd(0),
       m_sleeping(false),
       m_off(false),
-      m_phyListener(nullptr),
       m_linkId(0)
 {
     NS_LOG_FUNCTION(this);
@@ -135,8 +189,6 @@
 ChannelAccessManager::~ChannelAccessManager()
 {
     NS_LOG_FUNCTION(this);
-    delete m_phyListener;
-    m_phyListener = nullptr;
 }
 
 void
@@ -157,33 +209,96 @@
     }
     m_phy = nullptr;
     m_feManager = nullptr;
+    m_phyListeners.clear();
+}
+
+PhyListener*
+ChannelAccessManager::GetPhyListener(Ptr<WifiPhy> phy) const
+{
+    if (auto listenerIt = m_phyListeners.find(phy); listenerIt != m_phyListeners.end())
+    {
+        return listenerIt->second.get();
+    }
+    return nullptr;
 }
 
 void
 ChannelAccessManager::SetupPhyListener(Ptr<WifiPhy> phy)
 {
     NS_LOG_FUNCTION(this << phy);
-    NS_ASSERT(m_phyListener == nullptr);
-    m_phyListener = new PhyListener(this);
-    phy->RegisterListener(m_phyListener);
-    m_phy = phy;
+
+    auto phyListener = GetPhyListener(phy);
+
+    if (phyListener)
+    {
+        // a PHY listener for the given PHY already exists, it must be inactive
+        NS_ASSERT_MSG(!phyListener->IsActive(),
+                      "There is already an active listener registered for given PHY");
+        NS_ASSERT_MSG(!m_phy, "Cannot reactivate a listener if another PHY is active");
+        phyListener->SetActive(true);
+    }
+    else
+    {
+        phyListener = new PhyListener(this);
+        m_phyListeners.emplace(phy, phyListener);
+        phy->RegisterListener(phyListener);
+    }
+    if (m_phy)
+    {
+        DeactivatePhyListener(m_phy);
+    }
+    m_phy = phy; // this is the new active PHY
     InitLastBusyStructs();
+    if (phy->IsStateSwitching())
+    {
+        auto duration = phy->GetDelayUntilIdle();
+        NS_LOG_DEBUG("switching start for " << duration);
+        m_lastSwitchingEnd = Simulator::Now() + duration;
+    }
 }
 
 void
 ChannelAccessManager::RemovePhyListener(Ptr<WifiPhy> phy)
 {
     NS_LOG_FUNCTION(this << phy);
-    if (m_phyListener != nullptr)
+    if (auto phyListener = GetPhyListener(phy))
+    {
+        phy->UnregisterListener(phyListener);
+        m_phyListeners.erase(phy);
+        // reset m_phy if we are removing listener registered for the active PHY
+        if (m_phy == phy)
+        {
+            m_phy = nullptr;
+        }
+    }
+}
+
+void
+ChannelAccessManager::DeactivatePhyListener(Ptr<WifiPhy> phy)
+{
+    NS_LOG_FUNCTION(this << phy);
+    if (auto listener = GetPhyListener(phy))
+    {
+        listener->SetActive(false);
+    }
+    if (m_phy == phy)
     {
-        phy->UnregisterListener(m_phyListener);
-        delete m_phyListener;
-        m_phyListener = nullptr;
         m_phy = nullptr;
     }
 }
 
 void
+ChannelAccessManager::NotifySwitchingEmlsrLink(Ptr<WifiPhy> phy,
+                                               const WifiPhyOperatingChannel& channel,
+                                               uint8_t linkId)
+{
+    NS_LOG_FUNCTION(this << phy << channel << linkId);
+    NS_ASSERT_MSG(m_switchingEmlsrLinks.count(phy) == 0,
+                  "The given PHY is already expected to switch channel");
+    m_switchingEmlsrLinks.emplace(phy, EmlsrLinkSwitchInfo{channel, linkId});
+}
+
+void
 ChannelAccessManager::SetLinkId(uint8_t linkId)
 {
     NS_LOG_FUNCTION(this << +linkId);
@@ -282,8 +397,8 @@
 {
     NS_LOG_FUNCTION(this << txop);
 
-    // No backoff needed if in sleep mode or off
-    if (m_sleeping || m_off)
+    // No backoff needed if in sleep mode, off or when using another EMLSR link
+    if (m_sleeping || m_off || m_usingOtherEmlsrLink)
     {
         return false;
     }
@@ -342,6 +457,11 @@
     {
         m_phy->NotifyChannelAccessRequested();
     }
+    if (m_usingOtherEmlsrLink)
+    {
+        NS_LOG_DEBUG("Channel access cannot be requested while using another EMLSR link");
+        return;
+    }
     // Deny access if in sleep mode or off
     if (m_sleeping || m_off)
     {
@@ -375,7 +495,7 @@
     NS_LOG_FUNCTION(this);
     uint32_t k = 0;
     Time now = Simulator::Now();
-    for (Txops::iterator i = m_txops.begin(); i != m_txops.end(); k++)
+    for (auto i = m_txops.begin(); i != m_txops.end(); k++)
     {
         Ptr<Txop> txop = *i;
         if (txop->GetAccessStatus(m_linkId) == Txop::REQUESTED &&
@@ -391,7 +511,7 @@
             i++; // go to the next item in the list.
             k++;
             std::vector<Ptr<Txop>> internalCollisionTxops;
-            for (Txops::iterator j = i; j != m_txops.end(); j++, k++)
+            for (auto j = i; j != m_txops.end(); j++, k++)
             {
                 Ptr<Txop> otherTxop = *j;
                 if (otherTxop->GetAccessStatus(m_linkId) == Txop::REQUESTED &&
@@ -475,6 +595,8 @@
     Time ackTimeoutAccessStart = m_lastAckTimeoutEnd + sifs;
     Time ctsTimeoutAccessStart = m_lastCtsTimeoutEnd + sifs;
     Time switchingAccessStart = m_lastSwitchingEnd + sifs;
+    Time usingOtherEmlsrLinkAccessStart =
+        (m_usingOtherEmlsrLink ? Simulator::Now() : m_lastUsingOtherEmlsrLinkEnd) + sifs;
     Time accessGrantedStart;
     if (ignoreNav)
     {
@@ -483,6 +605,7 @@
                                        txAccessStart,
                                        ackTimeoutAccessStart,
                                        ctsTimeoutAccessStart,
+                                       usingOtherEmlsrLinkAccessStart,
                                        switchingAccessStart});
     }
     else
@@ -493,12 +616,18 @@
                                        navAccessStart,
                                        ackTimeoutAccessStart,
                                        ctsTimeoutAccessStart,
+                                       usingOtherEmlsrLinkAccessStart,
                                        switchingAccessStart});
     }
+    std::stringstream ss;
+    if (m_usingOtherEmlsrLink)
+    {
+        ss << ", using other EMLSR link access start=" << usingOtherEmlsrLinkAccessStart;
+    }
     NS_LOG_INFO("access grant start=" << accessGrantedStart << ", rx access start=" << rxAccessStart
                                       << ", busy access start=" << busyAccessStart
                                       << ", tx access start=" << txAccessStart
-                                      << ", nav access start=" << navAccessStart);
+                                      << ", nav access start=" << navAccessStart << ss.str());
     return accessGrantedStart;
 }
 
@@ -751,13 +880,61 @@
 }
 
 void
-ChannelAccessManager::NotifySwitchingStartNow(Time duration)
+ChannelAccessManager::NotifySwitchingStartNow(PhyListener* phyListener, Time duration)
 {
-    NS_LOG_FUNCTION(this << duration);
+    NS_LOG_FUNCTION(this << phyListener << duration);
+
     Time now = Simulator::Now();
     NS_ASSERT(m_lastTxEnd <= now);
     NS_ASSERT(m_lastSwitchingEnd <= now);
 
+    if (phyListener) // to make tests happy
+    {
+        // check if the PHY switched channel to operate on another EMLSR link
+
+        for (const auto& [phyRef, listener] : m_phyListeners)
+        {
+            Ptr<WifiPhy> phy = phyRef;
+            auto emlsrInfoIt = m_switchingEmlsrLinks.find(phy);
+
+            if (listener.get() == phyListener && emlsrInfoIt != m_switchingEmlsrLinks.cend() &&
+                phy->GetOperatingChannel() == emlsrInfoIt->second.channel)
+            {
+                // the PHY associated with the given PHY listener switched channel to
+                // operate on another EMLSR link as expected. We don't need this listener
+                // anymore. The MAC will connect a new listener to the ChannelAccessManager
+                // instance associated with the link the PHY is now operating on
+                RemovePhyListener(phy);
+                auto ehtFem = DynamicCast<EhtFrameExchangeManager>(m_feManager);
+                NS_ASSERT(ehtFem);
+                ehtFem->NotifySwitchingEmlsrLink(phy, emlsrInfoIt->second.linkId, duration);
+                m_switchingEmlsrLinks.erase(emlsrInfoIt);
+                return;
+            }
+        }
+    }
+
+    ResetState();
+
+    // Reset backoffs
+    for (const auto& txop : m_txops)
+    {
+        ResetBackoff(txop);
+    }
+
+    // Notify the FEM, which will in turn notify the MAC
+    m_feManager->NotifySwitchingStartNow(duration);
+
+    NS_LOG_DEBUG("switching start for " << duration);
+    m_lastSwitchingEnd = now + duration;
+}
+
+void
+ChannelAccessManager::ResetState()
+{
+    NS_LOG_FUNCTION(this);
+
+    Time now = Simulator::Now();
     m_lastRxReceivedOk = true;
     UpdateLastIdlePeriod();
     m_lastRx.end = std::min(m_lastRx.end, now);
@@ -765,7 +942,6 @@
     m_lastAckTimeoutEnd = std::min(m_lastAckTimeoutEnd, now);
     m_lastCtsTimeoutEnd = std::min(m_lastCtsTimeoutEnd, now);
 
-    // the new operating channel may have a different width than the previous one
     InitLastBusyStructs();
 
     // Cancel timeout
@@ -773,25 +949,21 @@
     {
         m_accessTimeout.Cancel();
     }
+}
 
-    // Notify the FEM, which will in turn notify the MAC
-    m_feManager->NotifySwitchingStartNow(duration);
+void
+ChannelAccessManager::ResetBackoff(Ptr<Txop> txop)
+{
+    NS_LOG_FUNCTION(this << txop);
 
-    // Reset backoffs
-    for (auto txop : m_txops)
+    uint32_t remainingSlots = txop->GetBackoffSlots(m_linkId);
+    if (remainingSlots > 0)
     {
-        uint32_t remainingSlots = txop->GetBackoffSlots(m_linkId);
-        if (remainingSlots > 0)
-        {
-            txop->UpdateBackoffSlotsNow(remainingSlots, now, m_linkId);
-            NS_ASSERT(txop->GetBackoffSlots(m_linkId) == 0);
-        }
-        txop->ResetCw(m_linkId);
-        txop->GetLink(m_linkId).access = Txop::NOT_REQUESTED;
+        txop->UpdateBackoffSlotsNow(remainingSlots, Simulator::Now(), m_linkId);
+        NS_ASSERT(txop->GetBackoffSlots(m_linkId) == 0);
     }
-
-    NS_LOG_DEBUG("switching start for " << duration);
-    m_lastSwitchingEnd = now + duration;
+    txop->ResetCw(m_linkId);
+    txop->GetLink(m_linkId).access = Txop::NOT_REQUESTED;
 }
 
 void
@@ -837,14 +1009,7 @@
     m_sleeping = false;
     for (auto txop : m_txops)
     {
-        uint32_t remainingSlots = txop->GetBackoffSlots(m_linkId);
-        if (remainingSlots > 0)
-        {
-            txop->UpdateBackoffSlotsNow(remainingSlots, Simulator::Now(), m_linkId);
-            NS_ASSERT(txop->GetBackoffSlots(m_linkId) == 0);
-        }
-        txop->ResetCw(m_linkId);
-        txop->GetLink(m_linkId).access = Txop::NOT_REQUESTED;
+        ResetBackoff(txop);
         txop->NotifyWakeUp(m_linkId);
     }
 }
@@ -856,14 +1021,7 @@
     m_off = false;
     for (auto txop : m_txops)
     {
-        uint32_t remainingSlots = txop->GetBackoffSlots(m_linkId);
-        if (remainingSlots > 0)
-        {
-            txop->UpdateBackoffSlotsNow(remainingSlots, Simulator::Now(), m_linkId);
-            NS_ASSERT(txop->GetBackoffSlots(m_linkId) == 0);
-        }
-        txop->ResetCw(m_linkId);
-        txop->GetLink(m_linkId).access = Txop::NOT_REQUESTED;
+        ResetBackoff(txop);
         txop->NotifyOn();
     }
 }
@@ -925,10 +1083,38 @@
 }
 
 void
+ChannelAccessManager::NotifyStartUsingOtherEmlsrLink()
+{
+    NS_LOG_FUNCTION(this);
+    // update backoff if a PHY is operating on this link
+    if (m_phy)
+    {
+        UpdateBackoff();
+    }
+    // Cancel timeout
+    if (m_accessTimeout.IsRunning())
+    {
+        m_accessTimeout.Cancel();
+    }
+    m_usingOtherEmlsrLink = true;
+    UpdateLastIdlePeriod();
+}
+
+void
+ChannelAccessManager::NotifyStopUsingOtherEmlsrLink()
+{
+    NS_LOG_FUNCTION(this);
+    m_usingOtherEmlsrLink = false;
+    m_lastUsingOtherEmlsrLinkEnd = Simulator::Now();
+    DoRestartAccessTimeoutIfNeeded();
+}
+
+void
 ChannelAccessManager::UpdateLastIdlePeriod()
 {
     NS_LOG_FUNCTION(this);
-    Time idleStart = std::max({m_lastTxEnd, m_lastRx.end, m_lastSwitchingEnd});
+    Time idleStart =
+        std::max({m_lastTxEnd, m_lastRx.end, m_lastSwitchingEnd, m_lastUsingOtherEmlsrLinkEnd});
     Time now = Simulator::Now();
 
     if (idleStart >= now)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/channel-access-manager.h ns-3.40/src/wifi/model/channel-access-manager.h
--- ns-3.39/src/wifi/model/channel-access-manager.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/channel-access-manager.h	2023-09-27 13:30:37.902840000 -0700
@@ -21,6 +21,7 @@
 #define CHANNEL_ACCESS_MANAGER_H
 
 #include "wifi-phy-common.h"
+#include "wifi-phy-operating-channel.h"
 
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
@@ -28,6 +29,8 @@
 
 #include <algorithm>
 #include <map>
+#include <memory>
+#include <unordered_map>
 #include <vector>
 
 namespace ns3
@@ -60,18 +63,27 @@
     ~ChannelAccessManager() override;
 
     /**
-     * Set up listener for PHY events.
+     * Set up (or reactivate) listener for PHY events on the given PHY. The new (or reactivated)
+     * listener becomes the active listener and the previous active listener attached to another
+     * PHY, if any, is deactivated.
      *
      * \param phy the WifiPhy to listen to
      */
     void SetupPhyListener(Ptr<WifiPhy> phy);
     /**
-     * Remove current registered listener for PHY events.
+     * Remove current registered listener for PHY events on the given PHY.
      *
      * \param phy the WifiPhy to listen to
      */
     void RemovePhyListener(Ptr<WifiPhy> phy);
     /**
+     * Deactivate current registered listener for PHY events on the given PHY. All notifications
+     * but channel switch notifications coming from an inactive listener are ignored.
+     *
+     * \param phy the WifiPhy to listen to
+     */
+    void DeactivatePhyListener(Ptr<WifiPhy> phy);
+    /**
      * Set the ID of the link this Channel Access Manager is associated with.
      *
      * \param linkId the ID of the link this Channel Access Manager is associated with
@@ -195,13 +207,14 @@
                                WifiChannelListType channelType,
                                const std::vector<Time>& per20MhzDurations);
     /**
+     * \param phyListener the PHY listener that sent this notification
      * \param duration expected duration of channel switching period
      *
      * Notify the Txop that a channel switching period has just started.
      * During switching state, new packets can be enqueued in Txop/QosTxop
      * but they won't access to the medium until the end of the channel switching.
      */
-    void NotifySwitchingStartNow(Time duration);
+    void NotifySwitchingStartNow(PhyListener* phyListener, Time duration);
     /**
      * Notify the Txop that the device has been put in sleep mode.
      */
@@ -252,6 +265,15 @@
     void NotifyCtsTimeoutResetNow();
 
     /**
+     * Notify that another EMLSR link is being used, hence medium access should be disabled.
+     */
+    void NotifyStartUsingOtherEmlsrLink();
+    /**
+     * Notify that another EMLSR link is no longer being used, hence medium access can be resumed.
+     */
+    void NotifyStopUsingOtherEmlsrLink();
+
+    /**
      * Check if the device is busy sending or receiving,
      * or NAV or CCA busy.
      *
@@ -260,12 +282,43 @@
      */
     bool IsBusy() const;
 
+    /**
+     * Reset the state variables of this channel access manager.
+     */
+    void ResetState();
+    /**
+     * Reset the backoff for the given DCF/EDCAF.
+     *
+     * \param txop the given DCF/EDCAF
+     */
+    void ResetBackoff(Ptr<Txop> txop);
+
+    /**
+     * Notify that the given PHY is about to switch to the given operating channel, which is
+     * used by the given link. This notification is sent by the EMLSR Manager when a PHY object
+     * switches operating channel to operate on another link.
+     *
+     * \param phy the PHY object that is going to switch channel
+     * \param channel the new operating channel of the given PHY
+     * \param linkId the ID of the link on which the given PHY is going to operate
+     */
+    void NotifySwitchingEmlsrLink(Ptr<WifiPhy> phy,
+                                  const WifiPhyOperatingChannel& channel,
+                                  uint8_t linkId);
+
   protected:
     void DoInitialize() override;
     void DoDispose() override;
 
   private:
     /**
+     * Get current registered listener for PHY events on the given PHY.
+     *
+     * \param phy the given PHY
+     * \return the current registered listener for PHY events on the given PHY
+     */
+    PhyListener* GetPhyListener(Ptr<WifiPhy> phy) const;
+    /**
      * Initialize the structures holding busy end times per channel type (primary,
      * secondary, etc.) and per 20 MHz channel.
      */
@@ -360,14 +413,31 @@
     std::vector<Time> m_lastPer20MHzBusyEnd; /**< the last busy end time per 20 MHz channel
                                                   (HE stations and channel width > 20 MHz only) */
     std::map<WifiChannelListType, Timespan>
-        m_lastIdle;             //!< the last idle start and end time for each channel type
-    Time m_lastSwitchingEnd;    //!< the last switching end time
-    bool m_sleeping;            //!< flag whether it is in sleeping state
-    bool m_off;                 //!< flag whether it is in off state
-    Time m_eifsNoDifs;          //!< EIFS no DIFS time
-    EventId m_accessTimeout;    //!< the access timeout ID
-    PhyListener* m_phyListener; //!< the PHY listener
-    Ptr<WifiPhy> m_phy;         //!< pointer to the PHY
+        m_lastIdle;                    //!< the last idle start and end time for each channel type
+    Time m_lastSwitchingEnd;           //!< the last switching end time
+    bool m_usingOtherEmlsrLink;        //!< whether another EMLSR link is being used
+    Time m_lastUsingOtherEmlsrLinkEnd; //!< the last time we were blocked because using another
+                                       //!< EMLSR link
+    bool m_sleeping;                   //!< flag whether it is in sleeping state
+    bool m_off;                        //!< flag whether it is in off state
+    Time m_eifsNoDifs;                 //!< EIFS no DIFS time
+    EventId m_accessTimeout;           //!< the access timeout ID
+
+    /// Information associated with each PHY that is going to operate on another EMLSR link
+    struct EmlsrLinkSwitchInfo
+    {
+        WifiPhyOperatingChannel channel; //!< new operating channel
+        uint8_t linkId; //!< ID of the EMLSR link on which the PHY is going to operate
+    };
+
+    /// Store information about the PHY objects that are going to operate on another EMLSR link
+    std::unordered_map<Ptr<WifiPhy>, EmlsrLinkSwitchInfo> m_switchingEmlsrLinks;
+
+    /// Maps each PHY listener to the associated PHY
+    using PhyListenerMap = std::unordered_map<Ptr<WifiPhy>, std::unique_ptr<PhyListener>>;
+
+    PhyListenerMap m_phyListeners;         //!< the PHY listeners
+    Ptr<WifiPhy> m_phy;                    //!< pointer to the unique active PHY
     Ptr<FrameExchangeManager> m_feManager; //!< pointer to the Frame Exchange Manager
     uint8_t m_linkId;                      //!< the ID of the link this object is associated with
 };
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/ctrl-headers.cc ns-3.40/src/wifi/model/ctrl-headers.cc
--- ns-3.39/src/wifi/model/ctrl-headers.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/ctrl-headers.cc	2023-09-27 13:30:37.902840000 -0700
@@ -232,7 +232,7 @@
 uint8_t
 CtrlBAckRequestHeader::GetTidInfo() const
 {
-    uint8_t tid = static_cast<uint8_t>(m_tidInfo);
+    auto tid = static_cast<uint8_t>(m_tidInfo);
     return tid;
 }
 
@@ -1451,7 +1451,8 @@
 void
 CtrlTriggerUserInfoField::SetUlMcs(uint8_t mcs)
 {
-    NS_ABORT_MSG_IF(mcs > 11, "Invalid MCS index");
+    uint8_t maxMcs = m_variant == TriggerFrameVariant::EHT ? 13 : 11;
+    NS_ABORT_MSG_IF(mcs > maxMcs, "Invalid MCS index");
     m_ulMcs = mcs;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/edca-parameter-set.cc ns-3.40/src/wifi/model/edca-parameter-set.cc
--- ns-3.39/src/wifi/model/edca-parameter-set.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/edca-parameter-set.cc	2023-09-27 13:30:37.902840000 -0700
@@ -61,14 +61,14 @@
 void
 EdcaParameterSet::SetBeCWmin(uint32_t cwMin)
 {
-    uint8_t ECWmin = static_cast<uint8_t>(log2(cwMin + 1));
+    auto ECWmin = static_cast<uint8_t>(log2(cwMin + 1));
     m_acBE |= (ECWmin & 0x0f) << 8;
 }
 
 void
 EdcaParameterSet::SetBeCWmax(uint32_t cwMax)
 {
-    uint8_t ECWmax = static_cast<uint8_t>(log2(cwMax + 1));
+    auto ECWmax = static_cast<uint8_t>(log2(cwMax + 1));
     m_acBE |= (ECWmax & 0x0f) << 12;
 }
 
@@ -93,14 +93,14 @@
 void
 EdcaParameterSet::SetBkCWmin(uint32_t cwMin)
 {
-    uint8_t ECWmin = static_cast<uint8_t>(log2(cwMin + 1));
+    auto ECWmin = static_cast<uint8_t>(log2(cwMin + 1));
     m_acBK |= (ECWmin & 0x0f) << 8;
 }
 
 void
 EdcaParameterSet::SetBkCWmax(uint32_t cwMax)
 {
-    uint8_t ECWmax = static_cast<uint8_t>(log2(cwMax + 1));
+    auto ECWmax = static_cast<uint8_t>(log2(cwMax + 1));
     m_acBK |= (ECWmax & 0x0f) << 12;
 }
 
@@ -125,14 +125,14 @@
 void
 EdcaParameterSet::SetViCWmin(uint32_t cwMin)
 {
-    uint8_t ECWmin = static_cast<uint8_t>(log2(cwMin + 1));
+    auto ECWmin = static_cast<uint8_t>(log2(cwMin + 1));
     m_acVI |= (ECWmin & 0x0f) << 8;
 }
 
 void
 EdcaParameterSet::SetViCWmax(uint32_t cwMax)
 {
-    uint8_t ECWmax = static_cast<uint8_t>(log2(cwMax + 1));
+    auto ECWmax = static_cast<uint8_t>(log2(cwMax + 1));
     m_acVI |= (ECWmax & 0x0f) << 12;
 }
 
@@ -157,14 +157,14 @@
 void
 EdcaParameterSet::SetVoCWmin(uint32_t cwMin)
 {
-    uint8_t ECWmin = static_cast<uint8_t>(log2(cwMin + 1));
+    auto ECWmin = static_cast<uint8_t>(log2(cwMin + 1));
     m_acVO |= (ECWmin & 0x0f) << 8;
 }
 
 void
 EdcaParameterSet::SetVoCWmax(uint32_t cwMax)
 {
-    uint8_t ECWmax = static_cast<uint8_t>(log2(cwMax + 1));
+    auto ECWmax = static_cast<uint8_t>(log2(cwMax + 1));
     m_acVO |= (ECWmax & 0x0f) << 12;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/default-emlsr-manager.cc ns-3.40/src/wifi/model/eht/default-emlsr-manager.cc
--- ns-3.39/src/wifi/model/eht/default-emlsr-manager.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/default-emlsr-manager.cc	2023-09-27 13:30:37.902840000 -0700
@@ -19,8 +19,11 @@
 
 #include "default-emlsr-manager.h"
 
+#include "ns3/boolean.h"
+#include "ns3/channel-access-manager.h"
 #include "ns3/log.h"
 #include "ns3/wifi-mpdu.h"
+#include "ns3/wifi-phy.h"
 
 namespace ns3
 {
@@ -32,10 +35,17 @@
 TypeId
 DefaultEmlsrManager::GetTypeId()
 {
-    static TypeId tid = TypeId("ns3::DefaultEmlsrManager")
-                            .SetParent<EmlsrManager>()
-                            .SetGroupName("Wifi")
-                            .AddConstructor<DefaultEmlsrManager>();
+    static TypeId tid =
+        TypeId("ns3::DefaultEmlsrManager")
+            .SetParent<EmlsrManager>()
+            .SetGroupName("Wifi")
+            .AddConstructor<DefaultEmlsrManager>()
+            .AddAttribute("SwitchAuxPhy",
+                          "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.",
+                          BooleanValue(true),
+                          MakeBooleanAccessor(&DefaultEmlsrManager::m_switchAuxPhy),
+                          MakeBooleanChecker());
     return tid;
 }
 
@@ -53,27 +63,24 @@
 DefaultEmlsrManager::DoNotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId)
 {
     NS_LOG_FUNCTION(this << *mpdu << linkId);
-
-    if (mpdu->GetHeader().IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout())
-    {
-        m_assocLinkId = linkId;
-    }
 }
 
 uint8_t
-DefaultEmlsrManager::GetLinkToSendEmlNotification()
+DefaultEmlsrManager::GetLinkToSendEmlOmn()
 {
     NS_LOG_FUNCTION(this);
-    NS_ASSERT_MSG(m_assocLinkId, "No recorded link on which Assoc Response was received");
-    return *m_assocLinkId;
+    auto linkId = GetStaMac()->GetLinkForPhy(m_mainPhyId);
+    NS_ASSERT_MSG(linkId, "Link on which the main PHY is operating not found");
+    return *linkId;
 }
 
 std::optional<uint8_t>
 DefaultEmlsrManager::ResendNotification(Ptr<const WifiMpdu> mpdu)
 {
     NS_LOG_FUNCTION(this);
-    NS_ASSERT_MSG(m_assocLinkId, "No recorded link on which Assoc Response was received");
-    return *m_assocLinkId;
+    auto linkId = GetStaMac()->GetLinkForPhy(m_mainPhyId);
+    NS_ASSERT_MSG(linkId, "Link on which the main PHY is operating not found");
+    return *linkId;
 }
 
 void
@@ -82,4 +89,30 @@
     NS_LOG_FUNCTION(this);
 }
 
+void
+DefaultEmlsrManager::NotifyMainPhySwitch(uint8_t currLinkId, uint8_t nextLinkId)
+{
+    NS_LOG_FUNCTION(this << currLinkId << nextLinkId);
+
+    if (!m_switchAuxPhy)
+    {
+        return; // nothing to do
+    }
+
+    // switch channel on Aux PHY so that it operates on the link on which the main PHY was operating
+    auto auxPhy = GetStaMac()->GetWifiPhy(nextLinkId);
+
+    auto newAuxPhyChannel = GetChannelForAuxPhy(currLinkId);
+
+    NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << newAuxPhyChannel
+                             << " to operate on link " << +currLinkId);
+
+    GetStaMac()
+        ->GetChannelAccessManager(nextLinkId)
+        ->NotifySwitchingEmlsrLink(auxPhy, newAuxPhyChannel, currLinkId);
+
+    void (WifiPhy::*fp)(const WifiPhyOperatingChannel&) = &WifiPhy::SetOperatingChannel;
+    Simulator::ScheduleNow(fp, auxPhy, newAuxPhyChannel);
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/default-emlsr-manager.h ns-3.40/src/wifi/model/eht/default-emlsr-manager.h
--- ns-3.39/src/wifi/model/eht/default-emlsr-manager.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/default-emlsr-manager.h	2023-09-27 13:30:37.902840000 -0700
@@ -45,15 +45,16 @@
     ~DefaultEmlsrManager() override;
 
   protected:
-    uint8_t GetLinkToSendEmlNotification() override;
+    uint8_t GetLinkToSendEmlOmn() override;
     std::optional<uint8_t> ResendNotification(Ptr<const WifiMpdu> mpdu) override;
 
   private:
     void DoNotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId) override;
     void NotifyEmlsrModeChanged() override;
+    void NotifyMainPhySwitch(uint8_t currLinkId, uint8_t nextLinkId) override;
 
-    std::optional<uint8_t> m_assocLinkId; /**< ID of the link on which Association Response
-                                               was received */
+    bool m_switchAuxPhy; /**< 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 */
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/eht-configuration.cc ns-3.40/src/wifi/model/eht/eht-configuration.cc
--- ns-3.39/src/wifi/model/eht/eht-configuration.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/eht-configuration.cc	2023-09-27 13:30:37.902840000 -0700
@@ -14,13 +14,19 @@
  * 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 "eht-configuration.h"
 
+#include "ns3/attribute-container.h"
 #include "ns3/boolean.h"
+#include "ns3/enum.h"
 #include "ns3/log.h"
+#include "ns3/pair.h"
+#include "ns3/string.h"
+#include "ns3/uinteger.h"
 
 namespace ns3
 {
@@ -42,6 +48,9 @@
 TypeId
 EhtConfiguration::GetTypeId()
 {
+    using TidLinkMapValue =
+        PairValue<AttributeContainerValue<UintegerValue>, AttributeContainerValue<UintegerValue>>;
+
     static ns3::TypeId tid =
         ns3::TypeId("ns3::EhtConfiguration")
             .SetParent<Object>()
@@ -60,8 +69,105 @@
                           "Possible values are 0us or 2^n us, with n=7..16.",
                           TimeValue(MicroSeconds(0)),
                           MakeTimeAccessor(&EhtConfiguration::m_transitionTimeout),
-                          MakeTimeChecker(MicroSeconds(0), MicroSeconds(65536)));
+                          MakeTimeChecker(MicroSeconds(0), MicroSeconds(65536)))
+            .AddAttribute(
+                "TidToLinkMappingNegSupport",
+                "TID-to-Link Mapping Negotiation Support.",
+                EnumValue(WifiTidToLinkMappingNegSupport::WIFI_TID_TO_LINK_MAPPING_ANY_LINK_SET),
+                MakeEnumAccessor(&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(
+                "TidToLinkMappingDl",
+                "A list-of-TIDs-indexed map of the list of links where the TIDs are mapped to "
+                "for the downlink direction. "
+                "In case a string is used to set this attribute, the string shall contain the "
+                "(TID list, link list) pairs separated by a semicolon (;); in every pair, the "
+                "TID list and the link list are separated by a blank space, and the elements of "
+                "each list are separated by a comma (,) without spaces. "
+                "E.g., \"0,4 1,2,3; 1 0;2 0,1\" means that TIDs 0 and 4 are mapped on links "
+                "1, 2 and 3; TID 1 is mapped on link 0 and TID 2 is mapped on links 0 and 1. "
+                "An empty map indicates the default mapping, i.e., all TIDs are mapped to all "
+                "setup links. If the map contains the mapping for some TID(s), the mapping "
+                "corresponding to the missing TID(s) remains unchanged. "
+                "A non-AP MLD includes this mapping in the Association Request frame sent to "
+                "an AP MLD, unless the AP MLD advertises a negotiation support of 1 and this "
+                "mapping is such that TIDs are mapped to distinct link sets, in which case "
+                "the default mapping is included.",
+                StringValue(""),
+                MakeAttributeContainerAccessor<TidLinkMapValue, ';'>(
+                    &EhtConfiguration::m_linkMappingDl),
+                MakeAttributeContainerChecker<TidLinkMapValue, ';'>(
+                    MakePairChecker<AttributeContainerValue<UintegerValue>,
+                                    AttributeContainerValue<UintegerValue>>(
+                        MakeAttributeContainerChecker<UintegerValue>(
+                            MakeUintegerChecker<uint8_t>()),
+                        MakeAttributeContainerChecker<UintegerValue>(
+                            MakeUintegerChecker<uint8_t>()))))
+            .AddAttribute(
+                "TidToLinkMappingUl",
+                "A list-of-TIDs-indexed map of the list of links where the TIDs are mapped to "
+                "for the uplink direction. "
+                "In case a string is used to set this attribute, the string shall contain the "
+                "(TID list, link list) pairs separated by a semicolon (;); in every pair, the "
+                "TID list and the link list are separated by a blank space, and the elements of "
+                "each list are separated by a comma (,) without spaces. "
+                "E.g., \"0,4 1,2,3; 1 0;2 0,1\" means that TIDs 0 and 4 are mapped on links "
+                "1, 2 and 3; TID 1 is mapped on link 0 and TID 2 is mapped on links 0 and 1. "
+                "An empty map indicates the default mapping, i.e., all TIDs are mapped to all "
+                "setup links. If the map contains the mapping for some TID(s), the mapping "
+                "corresponding to the missing TID(s) remains unchanged. "
+                "A non-AP MLD includes this mapping in the Association Request frame sent to "
+                "an AP MLD, unless the AP MLD advertises a negotiation support of 1 and this "
+                "mapping is such that TIDs are mapped to distinct link sets, in which case "
+                "the default mapping is included.",
+                StringValue(""),
+                MakeAttributeContainerAccessor<TidLinkMapValue, ';'>(
+                    &EhtConfiguration::m_linkMappingUl),
+                MakeAttributeContainerChecker<TidLinkMapValue, ';'>(
+                    MakePairChecker<AttributeContainerValue<UintegerValue>,
+                                    AttributeContainerValue<UintegerValue>>(
+                        MakeAttributeContainerChecker<UintegerValue>(
+                            MakeUintegerChecker<uint8_t>()),
+                        MakeAttributeContainerChecker<UintegerValue>(
+                            MakeUintegerChecker<uint8_t>()))));
     return tid;
 }
 
+WifiTidLinkMapping
+EhtConfiguration::GetTidLinkMapping(WifiDirection dir) const
+{
+    NS_ASSERT(dir != WifiDirection::BOTH_DIRECTIONS);
+    WifiTidLinkMapping ret;
+    const auto& linkMapping = (dir == WifiDirection::DOWNLINK ? m_linkMappingDl : m_linkMappingUl);
+
+    for (const auto& [tids, links] : linkMapping)
+    {
+        for (auto tid : tids)
+        {
+            ret[tid] = std::set<uint8_t>(links.cbegin(), links.cend());
+        }
+    }
+    return ret;
+}
+
+void
+EhtConfiguration::SetTidLinkMapping(WifiDirection dir,
+                                    const std::map<std::list<uint8_t>, std::list<uint8_t>>& mapping)
+{
+    NS_ASSERT(dir != WifiDirection::BOTH_DIRECTIONS);
+    auto& linkMapping = (dir == WifiDirection::DOWNLINK ? m_linkMappingDl : m_linkMappingUl);
+    linkMapping.clear();
+    for (const auto& [tids, links] : mapping)
+    {
+        linkMapping.emplace(std::list<uint64_t>(tids.cbegin(), tids.cend()),
+                            std::list<uint64_t>(links.cbegin(), links.cend()));
+    }
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/eht-configuration.h ns-3.40/src/wifi/model/eht/eht-configuration.h
--- ns-3.39/src/wifi/model/eht/eht-configuration.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/eht-configuration.h	2023-09-27 13:30:37.902840000 -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>
  */
 
 #ifndef EHT_CONFIGURATION_H
@@ -22,11 +23,25 @@
 
 #include "ns3/nstime.h"
 #include "ns3/object.h"
+#include "ns3/wifi-utils.h"
+
+#include <list>
+#include <map>
 
 namespace ns3
 {
 
 /**
+ * \brief TID-to-Link Mapping Negotiation Support
+ */
+enum 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
+};
+
+/**
  * \brief EHT configuration
  * \ingroup wifi
  *
@@ -46,9 +61,30 @@
      */
     static TypeId GetTypeId();
 
+    /**
+     * \param dir the direction for the requested TID-to-Link Mapping
+     * \return a TID-indexed map of the list of links where each TID is mapped to
+     */
+    WifiTidLinkMapping GetTidLinkMapping(WifiDirection dir) const;
+
+    /**
+     * Set the TID-to-Link mapping for the given direction.
+     *
+     * \param dir the direction for the TID-to-Link Mapping
+     * \param mapping a list-of-TIDs-indexed map of the list of links where the TIDs are mapped to
+     */
+    void SetTidLinkMapping(WifiDirection dir,
+                           const std::map<std::list<uint8_t>, std::list<uint8_t>>& mapping);
+
   private:
     bool m_emlsrActivated;    //!< whether EMLSR option is activated
     Time m_transitionTimeout; //!< Transition timeout
+    WifiTidToLinkMappingNegSupport
+        m_tidLinkMappingSupport; //!< TID-to-Link Mapping Negotiation Support
+    std::map<std::list<uint64_t>, std::list<uint64_t>>
+        m_linkMappingDl; //!< TIDs-indexed Link Mapping for downlink
+    std::map<std::list<uint64_t>, std::list<uint64_t>>
+        m_linkMappingUl; //!< TIDs-indexed Link Mapping for uplink
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/eht-frame-exchange-manager.cc ns-3.40/src/wifi/model/eht/eht-frame-exchange-manager.cc
--- ns-3.39/src/wifi/model/eht/eht-frame-exchange-manager.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/eht-frame-exchange-manager.cc	2023-09-27 13:30:37.902840000 -0700
@@ -20,10 +20,12 @@
 #include "eht-frame-exchange-manager.h"
 
 #include "eht-phy.h"
+#include "emlsr-manager.h"
 
 #include "ns3/abort.h"
 #include "ns3/ap-wifi-mac.h"
 #include "ns3/log.h"
+#include "ns3/sta-wifi-mac.h"
 #include "ns3/wifi-mac-queue.h"
 
 #undef NS_LOG_APPEND_CONTEXT
@@ -32,6 +34,10 @@
 namespace ns3
 {
 
+/// generic value for aRxPHYStartDelay PHY characteristic (used when we do not know the preamble
+/// type of the next frame)
+static constexpr uint8_t RX_PHY_START_DELAY_USEC = 48;
+
 NS_LOG_COMPONENT_DEFINE("EhtFrameExchangeManager");
 
 NS_OBJECT_ENSURE_REGISTERED(EhtFrameExchangeManager);
@@ -57,8 +63,33 @@
 }
 
 void
+EhtFrameExchangeManager::DoDispose()
+{
+    NS_LOG_FUNCTION(this);
+    m_ongoingTxopEnd.Cancel();
+    HeFrameExchangeManager::DoDispose();
+}
+
+void
+EhtFrameExchangeManager::RxStartIndication(WifiTxVector txVector, Time psduDuration)
+{
+    NS_LOG_FUNCTION(this << txVector << psduDuration.As(Time::MS));
+
+    HeFrameExchangeManager::RxStartIndication(txVector, psduDuration);
+    UpdateTxopEndOnRxStartIndication(psduDuration);
+}
+
+void
 EhtFrameExchangeManager::SetLinkId(uint8_t linkId)
 {
+    if (auto protectionManager = GetProtectionManager())
+    {
+        protectionManager->SetLinkId(linkId);
+    }
+    if (auto ackManager = GetAckManager())
+    {
+        ackManager->SetLinkId(linkId);
+    }
     m_msduAggregator->SetLinkId(linkId);
     m_mpduAggregator->SetLinkId(linkId);
     HeFrameExchangeManager::SetLinkId(linkId);
@@ -107,6 +138,23 @@
     return mpdu;
 }
 
+bool
+EhtFrameExchangeManager::StartTransmission(Ptr<Txop> edca, uint16_t allowedWidth)
+{
+    NS_LOG_FUNCTION(this << edca << allowedWidth);
+
+    auto started = HeFrameExchangeManager::StartTransmission(edca, allowedWidth);
+
+    if (started && m_staMac && m_staMac->IsEmlsrLink(m_linkId))
+    {
+        // notify the EMLSR Manager of the UL TXOP start on an EMLSR link
+        NS_ASSERT(m_staMac->GetEmlsrManager());
+        m_staMac->GetEmlsrManager()->NotifyUlTxopStart(m_linkId);
+    }
+
+    return started;
+}
+
 void
 EhtFrameExchangeManager::ForwardPsduDown(Ptr<const WifiPsdu> psdu, WifiTxVector& txVector)
 {
@@ -120,33 +168,32 @@
         txVector.SetSigBMode(sigBMode);
     }
 
-    if (!m_apMac)
-    {
-        HeFrameExchangeManager::ForwardPsduDown(psdu, txVector);
-        return;
-    }
-
     auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
 
-    // check if the EMLSR clients shall switch back to listening operation at the end of this PPDU
-    for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
-    {
-        auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
+    HeFrameExchangeManager::ForwardPsduDown(psdu, txVector);
+    UpdateTxopEndOnTxStart(txDuration);
 
-        if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
-            GetEmlsrSwitchToListening(psdu, aid, *clientIt))
-        {
-            EmlsrSwitchToListening(*clientIt, txDuration);
-            // this client is no longer involved in the current TXOP
-            clientIt = m_protectedStas.erase(clientIt);
-        }
-        else
+    if (m_apMac)
+    {
+        // check if the EMLSR clients shall switch back to listening operation at the end of this
+        // PPDU
+        for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
         {
-            clientIt++;
+            auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
+
+            if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
+                GetEmlsrSwitchToListening(psdu, aid, *clientIt))
+            {
+                EmlsrSwitchToListening(*clientIt, txDuration);
+                // this client is no longer involved in the current TXOP
+                clientIt = m_protectedStas.erase(clientIt);
+            }
+            else
+            {
+                clientIt++;
+            }
         }
     }
-
-    HeFrameExchangeManager::ForwardPsduDown(psdu, txVector);
 }
 
 void
@@ -154,35 +201,34 @@
 {
     NS_LOG_FUNCTION(this << psduMap << txVector);
 
-    if (!m_apMac)
-    {
-        HeFrameExchangeManager::ForwardPsduMapDown(psduMap, txVector);
-        return;
-    }
-
     auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
 
-    // check if the EMLSR clients shall switch back to listening operation at the end of this PPDU
-    for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
-    {
-        auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
+    HeFrameExchangeManager::ForwardPsduMapDown(psduMap, txVector);
+    UpdateTxopEndOnTxStart(txDuration);
 
-        if (auto psduMapIt = psduMap.find(aid);
-            GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
-            (psduMapIt == psduMap.cend() ||
-             GetEmlsrSwitchToListening(psduMapIt->second, aid, *clientIt)))
-        {
-            EmlsrSwitchToListening(*clientIt, txDuration);
-            // this client is no longer involved in the current TXOP
-            clientIt = m_protectedStas.erase(clientIt);
-        }
-        else
+    if (m_apMac)
+    {
+        // check if the EMLSR clients shall switch back to listening operation at the end of this
+        // PPDU
+        for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
         {
-            clientIt++;
+            auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
+
+            if (auto psduMapIt = psduMap.find(aid);
+                GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
+                (psduMapIt == psduMap.cend() ||
+                 GetEmlsrSwitchToListening(psduMapIt->second, aid, *clientIt)))
+            {
+                EmlsrSwitchToListening(*clientIt, txDuration);
+                // this client is no longer involved in the current TXOP
+                clientIt = m_protectedStas.erase(clientIt);
+            }
+            else
+            {
+                clientIt++;
+            }
         }
     }
-
-    HeFrameExchangeManager::ForwardPsduMapDown(psduMap, txVector);
 }
 
 void
@@ -218,7 +264,7 @@
 
             // unblock all EMLSR links when the transition delay elapses
             Simulator::Schedule(delay + CommonInfoBasicMle::DecodeEmlsrTransitionDelay(
-                                            emlCapabilities->emlsrTransitionDelay),
+                                            emlCapabilities->get().emlsrTransitionDelay),
                                 [=]() {
                                     m_mac->UnblockUnicastTxOnLinks(
                                         WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
@@ -230,9 +276,28 @@
 }
 
 void
-EhtFrameExchangeManager::SendEmlOperatingModeNotification(
-    const Mac48Address& dest,
-    const MgtEmlOperatingModeNotification& frame)
+EhtFrameExchangeManager::NotifySwitchingEmlsrLink(Ptr<WifiPhy> phy, uint8_t linkId, Time delay)
+{
+    NS_LOG_FUNCTION(this << phy << linkId << delay.As(Time::US));
+
+    // TODO Shall we assert that there is no ongoing frame exchange sequence? Or is it possible
+    // that there is an ongoing frame exchange sequence (in such a case, we need to force a
+    // timeout, just like it is done in case of a normal channel switch
+
+    NS_ABORT_MSG_IF(!m_staMac, "This method can only be called on a STA");
+
+    // if we receive the notification from a PHY that is not connected to us, it means that
+    // we have been already connected to another PHY operating on this link, hence we do not
+    // have to reset the connected PHY
+    if (phy == m_phy)
+    {
+        ResetPhy();
+    }
+    m_staMac->NotifySwitchingEmlsrLink(phy, linkId);
+}
+
+void
+EhtFrameExchangeManager::SendEmlOmn(const Mac48Address& dest, const MgtEmlOmn& frame)
 {
     NS_LOG_FUNCTION(this << dest << frame);
 
@@ -311,7 +376,7 @@
 
         auto emlCapabilities = GetWifiRemoteStationManager()->GetStationEmlCapabilities(address);
         NS_ASSERT(emlCapabilities);
-        maxPaddingDelay = std::max(maxPaddingDelay, emlCapabilities->emlsrPaddingDelay);
+        maxPaddingDelay = std::max(maxPaddingDelay, emlCapabilities->get().emlsrPaddingDelay);
 
         auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
         NS_ASSERT(mldAddress);
@@ -333,8 +398,7 @@
     {
         NS_ASSERT(txParams.m_protection &&
                   txParams.m_protection->method == WifiProtection::MU_RTS_CTS);
-        WifiMuRtsCtsProtection* protection =
-            static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
+        auto protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
         NS_ASSERT(protection->muRts.IsMuRts());
 
         // see formula (35-1) in Sec. 35.5.2.2.3 of 802.11be D3.0
@@ -413,22 +477,272 @@
 }
 
 void
+EhtFrameExchangeManager::TransmissionFailed()
+{
+    NS_LOG_FUNCTION(this);
+
+    for (const auto& address : m_txTimer.GetStasExpectedToRespond())
+    {
+        if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
+        {
+            // This EMLSR client did not respond to a frame sent by the AP. Specs say:
+            // The AP affiliated with the AP MLD should transmit before the TXNAV timer expires
+            // another initial Control frame addressed to the non-AP STA affiliated with the
+            // non-AP MLD if the AP intends to continue the frame exchanges with the STA and did
+            // not receive the response frame from this STA for the most recently transmitted
+            // frame that requires an immediate response after a SIFS
+            // (Sec. 35.3.17 of 802.11be D3.1)
+            // We let the AP continue the TXOP. TransmissionSucceeded() removes this client from
+            // protected stations, hence next transmission to this client in this TXOP will be
+            // protected by ICF
+            NS_LOG_DEBUG("EMLSR client " << address << " did not respond, continue TXOP");
+            TransmissionSucceeded();
+            return;
+        }
+    }
+
+    HeFrameExchangeManager::TransmissionFailed();
+}
+
+void
 EhtFrameExchangeManager::NotifyChannelReleased(Ptr<Txop> txop)
 {
     NS_LOG_FUNCTION(this << txop);
 
-    // the channel has been released; all EMLSR clients will switch back to listening
-    // operation after a timeout interval of aSIFSTime + aSlotTime + aRxPHYStartDelay
-    auto delay = m_phy->GetSifs() + m_phy->GetSlot() + MicroSeconds(20);
-    for (const auto& address : m_protectedStas)
+    if (m_apMac)
     {
-        if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
+        // the channel has been released; all EMLSR clients will switch back to listening
+        // operation after a timeout interval of aSIFSTime + aSlotTime + aRxPHYStartDelay
+        auto delay = m_phy->GetSifs() + m_phy->GetSlot() + MicroSeconds(RX_PHY_START_DELAY_USEC);
+        for (const auto& address : m_protectedStas)
         {
-            EmlsrSwitchToListening(address, delay);
+            if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
+            {
+                EmlsrSwitchToListening(address, delay);
+            }
         }
     }
+    else if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
+    {
+        // notify the EMLSR Manager of the UL TXOP end
+        NS_ASSERT(m_staMac->GetEmlsrManager());
+        m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
+    }
 
     HeFrameExchangeManager::NotifyChannelReleased(txop);
 }
 
+void
+EhtFrameExchangeManager::PostProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
+{
+    NS_LOG_FUNCTION(this << psdu << txVector);
+
+    HeFrameExchangeManager::PostProcessFrame(psdu, txVector);
+
+    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);
+
+            // block transmissions on other links
+            auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(psdu->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});
+                }
+            }
+        }
+        else
+        {
+            UpdateTxopEndOnRxEnd();
+        }
+    }
+
+    if (m_staMac && m_ongoingTxopEnd.IsRunning())
+    {
+        if (GetEmlsrSwitchToListening(psdu, m_staMac->GetAssociationId(), m_self))
+        {
+            // we are no longer involved in the TXOP and switching to listening mode
+            m_ongoingTxopEnd.Cancel();
+            m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
+        }
+        else
+        {
+            UpdateTxopEndOnRxEnd();
+        }
+    }
+}
+
+void
+EhtFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
+                                     RxSignalInfo rxSignalInfo,
+                                     const WifiTxVector& txVector,
+                                     bool inAmpdu)
+{
+    // The received MPDU is either broadcast or addressed to this station
+    NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
+
+    const auto& hdr = mpdu->GetHeader();
+
+    if (hdr.IsTrigger())
+    {
+        if (!m_staMac)
+        {
+            return; // Trigger Frames are only processed by STAs
+        }
+
+        CtrlTriggerHeader trigger;
+        mpdu->GetPacket()->PeekHeader(trigger);
+
+        if (hdr.GetAddr1() != m_self &&
+            (!hdr.GetAddr1().IsBroadcast() || !m_staMac->IsAssociated() ||
+             hdr.GetAddr2() != m_bssid // not sent by the AP this STA is associated with
+             || trigger.FindUserInfoWithAid(m_staMac->GetAssociationId()) == trigger.end()))
+        {
+            return; // not addressed to us
+        }
+
+        if (trigger.IsMuRts() && m_staMac->IsEmlsrLink(m_linkId))
+        {
+            // this is an initial Control frame
+            auto apAddress = GetWifiRemoteStationManager()->GetMldAddress(m_bssid);
+            NS_ASSERT_MSG(apAddress, "MLD address not found for BSSID " << m_bssid);
+            // when EMLSR links are blocked, all TIDs are blocked (we test TID 0 here)
+            WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *apAddress, 0);
+            if (auto mask =
+                    m_staMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, m_linkId);
+                mask && mask->test(static_cast<std::size_t>(
+                            WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK)))
+            {
+                // we received an ICF on a link that is blocked because another EMLSR link is
+                // being used. This is likely because transmission on the other EMLSR link
+                // started before the reception of the ICF ended. We drop this ICF and let the
+                // UL TXOP continue.
+                NS_LOG_DEBUG("Drop ICF because another EMLSR link is being used");
+                return;
+            }
+
+            NS_ASSERT(m_staMac->GetEmlsrManager());
+            Simulator::ScheduleNow(&EmlsrManager::NotifyIcfReceived,
+                                   m_staMac->GetEmlsrManager(),
+                                   m_linkId);
+            // we just got involved in a DL TXOP. Check if we are still involved in the TXOP in a
+            // SIFS (we are expected to reply by sending a CTS frame)
+            m_ongoingTxopEnd.Cancel();
+            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);
+        }
+    }
+
+    HeFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
+}
+
+void
+EhtFrameExchangeManager::TxopEnd()
+{
+    NS_LOG_FUNCTION(this);
+
+    if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
+    {
+        m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
+    }
+    else if (m_apMac && m_txopHolder &&
+             GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
+    {
+        // EMLSR client terminated its TXOP and is back to listening operation
+        EmlsrSwitchToListening(*m_txopHolder, Seconds(0));
+    }
+}
+
+void
+EhtFrameExchangeManager::UpdateTxopEndOnTxStart(Time txDuration)
+{
+    NS_LOG_FUNCTION(this << txDuration.As(Time::MS));
+
+    if (!m_ongoingTxopEnd.IsRunning())
+    {
+        // nothing to do
+        return;
+    }
+
+    m_ongoingTxopEnd.Cancel();
+    Time delay;
+
+    if (m_txTimer.IsRunning())
+    {
+        // the TX timer is running, hence we are expecting a response. Postpone the TXOP end
+        // to match the TX timer (which is long enough to get the PHY-RXSTART.indication for
+        // the response)
+        delay = m_txTimer.GetDelayLeft();
+    }
+    else
+    {
+        // the TX Timer is not running, hence no response is expected (e.g., we are
+        // transmitting a CTS after ICS). The TXOP holder may transmit a frame a SIFS
+        // after the end of this PPDU, hence we need to postpone the TXOP end in order to
+        // get the PHY-RXSTART.indication
+        delay = txDuration + 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);
+}
+
+void
+EhtFrameExchangeManager::UpdateTxopEndOnRxStartIndication(Time psduDuration)
+{
+    NS_LOG_FUNCTION(this << psduDuration.As(Time::MS));
+
+    if (!m_ongoingTxopEnd.IsRunning() || !psduDuration.IsStrictlyPositive())
+    {
+        // nothing to do
+        return;
+    }
+
+    // postpone the TXOP end until after the reception of the PSDU is completed
+    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);
+}
+
+void
+EhtFrameExchangeManager::UpdateTxopEndOnRxEnd()
+{
+    NS_LOG_FUNCTION(this);
+
+    if (!m_ongoingTxopEnd.IsRunning())
+    {
+        // nothing to do
+        return;
+    }
+
+    m_ongoingTxopEnd.Cancel();
+
+    // 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);
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/eht-frame-exchange-manager.h ns-3.40/src/wifi/model/eht/eht-frame-exchange-manager.h
--- ns-3.39/src/wifi/model/eht/eht-frame-exchange-manager.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/eht-frame-exchange-manager.h	2023-09-27 13:30:37.902840000 -0700
@@ -45,6 +45,7 @@
 
     void SetLinkId(uint8_t linkId) override;
     Ptr<WifiMpdu> CreateAliasIfNeeded(Ptr<WifiMpdu> mpdu) const override;
+    bool StartTransmission(Ptr<Txop> edca, uint16_t allowedWidth) override;
 
     /**
      * Send an EML Operating Mode Notification frame to the given station.
@@ -52,8 +53,7 @@
      * \param dest the MAC address of the receiver
      * \param frame the EML Operating Mode Notification frame to send
      */
-    void SendEmlOperatingModeNotification(const Mac48Address& dest,
-                                          const MgtEmlOperatingModeNotification& frame);
+    void SendEmlOmn(const Mac48Address& dest, const MgtEmlOmn& frame);
 
     /**
      * Get the RSSI (in dBm) of the most recent packet received from the station having
@@ -77,11 +77,29 @@
                                    uint16_t aid,
                                    const Mac48Address& address) const;
 
+    /**
+     * Notify that the given PHY will switch channel to operate on another EMLSR link
+     * after the given delay.
+     *
+     * \param phy the given PHY
+     * \param linkId the ID of the EMLSR link on which the given PHY is operating
+     * \param delay the delay after which the channel switch will be completed
+     */
+    void NotifySwitchingEmlsrLink(Ptr<WifiPhy> phy, uint8_t linkId, Time delay);
+
   protected:
+    void DoDispose() override;
+    void RxStartIndication(WifiTxVector txVector, Time psduDuration) override;
     void ForwardPsduDown(Ptr<const WifiPsdu> psdu, WifiTxVector& txVector) override;
     void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector) override;
     void SendMuRts(const WifiTxParameters& txParams) override;
+    void TransmissionFailed() override;
     void NotifyChannelReleased(Ptr<Txop> txop) override;
+    void PostProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) override;
+    void ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
+                     RxSignalInfo rxSignalInfo,
+                     const WifiTxVector& txVector,
+                     bool inAmpdu) override;
 
     /**
      * This method is intended to be called when an AP MLD detects that an EMLSR client previously
@@ -94,6 +112,34 @@
      * \param delay the given delay
      */
     void EmlsrSwitchToListening(const Mac48Address& address, const Time& delay);
+
+  private:
+    /**
+     * Update the TXOP end timer when starting a frame transmission.
+     *
+     * \param txDuration the TX duration of the frame being transmitted
+     */
+    void UpdateTxopEndOnTxStart(Time txDuration);
+
+    /**
+     * Update the TXOP end timer when receiving a PHY-RXSTART.indication.
+     *
+     * \param psduDuration the TX duration of the PSDU being received
+     */
+    void UpdateTxopEndOnRxStartIndication(Time psduDuration);
+
+    /**
+     * Update the TXOP end timer when a frame reception ends.
+     */
+    void UpdateTxopEndOnRxEnd();
+
+    /**
+     * Take actions when a TXOP (of which we are not the holder) ends.
+     */
+    void TxopEnd();
+
+    EventId m_ongoingTxopEnd; //!< event indicating the possible end of the current TXOP (of which
+                              //!< we are not the holder)
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/eht-phy.cc ns-3.40/src/wifi/model/eht/eht-phy.cc
--- ns-3.39/src/wifi/model/eht/eht-phy.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/eht-phy.cc	2023-09-27 13:30:37.902840000 -0700
@@ -138,13 +138,15 @@
             txVector.GetChannelWidth(),
             txVector.GetRuAllocation(
                 m_wifiPhy ? m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(20) : 0),
-            txVector.GetEhtPpduType());
+            txVector.GetEhtPpduType(),
+            txVector.IsSigBCompression(),
+            txVector.IsSigBCompression() ? txVector.GetHeMuUserInfoMap().size() : 0);
     }
     return HePhy::GetSigBSize(txVector);
 }
 
 Time
-EhtPhy::CalculateNonOfdmaDurationForHeTb(const WifiTxVector& txVector) const
+EhtPhy::CalculateNonHeDurationForHeTb(const WifiTxVector& txVector) const
 {
     Time duration = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, txVector) +
                     GetDuration(WIFI_PPDU_FIELD_NON_HT_HEADER, txVector) +
@@ -153,7 +155,7 @@
 }
 
 Time
-EhtPhy::CalculateNonOfdmaDurationForHeMu(const WifiTxVector& txVector) const
+EhtPhy::CalculateNonHeDurationForHeMu(const WifiTxVector& txVector) const
 {
     Time duration = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, txVector) +
                     GetDuration(WIFI_PPDU_FIELD_NON_HT_HEADER, txVector) +
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/eht-phy.h ns-3.40/src/wifi/model/eht/eht-phy.h
--- ns-3.39/src/wifi/model/eht/eht-phy.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/eht-phy.h	2023-09-27 13:30:37.902840000 -0700
@@ -260,8 +260,8 @@
                                 PhyFieldRxStatus status,
                                 WifiPpduField field) override;
     WifiPhyRxfailureReason GetFailureReason(WifiPpduField field) const override;
-    Time CalculateNonOfdmaDurationForHeTb(const WifiTxVector& txVector) const override;
-    Time CalculateNonOfdmaDurationForHeMu(const WifiTxVector& txVector) const override;
+    Time CalculateNonHeDurationForHeTb(const WifiTxVector& txVector) const override;
+    Time CalculateNonHeDurationForHeMu(const WifiTxVector& txVector) const override;
     uint32_t GetSigBSize(const WifiTxVector& txVector) const override;
 
     /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/eht-ppdu.cc ns-3.40/src/wifi/model/eht/eht-ppdu.cc
--- ns-3.39/src/wifi/model/eht/eht-ppdu.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/eht-ppdu.cc	2023-09-27 13:30:37.902840000 -0700
@@ -25,6 +25,8 @@
 #include "ns3/wifi-phy-operating-channel.h"
 #include "ns3/wifi-psdu.h"
 
+#include <numeric>
+
 namespace ns3
 {
 
@@ -135,7 +137,19 @@
             ruAllocation.has_value())
         {
             txVector.SetRuAllocation(ruAllocation.value(), p20Index);
-            SetHeMuUserInfos(txVector, ruAllocation.value(), ehtPhyHeader->m_contentChannels);
+            const auto isMuMimo = (ehtPhyHeader->m_ppduType == 2);
+            const auto muMimoUsers =
+                isMuMimo
+                    ? std::accumulate(ehtPhyHeader->m_contentChannels.cbegin(),
+                                      ehtPhyHeader->m_contentChannels.cend(),
+                                      0,
+                                      [](uint8_t prev, const auto& cc) { return prev + cc.size(); })
+                    : 0;
+            SetHeMuUserInfos(txVector,
+                             ruAllocation.value(),
+                             ehtPhyHeader->m_contentChannels,
+                             ehtPhyHeader->m_ppduType == 2,
+                             muMimoUsers);
         }
         if (ehtPhyHeader->m_ppduType == 1) // EHT SU
         {
@@ -159,13 +173,18 @@
 std::pair<std::size_t, std::size_t>
 EhtPpdu::GetNumRusPerEhtSigBContentChannel(uint16_t channelWidth,
                                            uint8_t ehtPpduType,
-                                           const RuAllocation& ruAllocation)
+                                           const RuAllocation& ruAllocation,
+                                           bool compression,
+                                           std::size_t numMuMimoUsers)
 {
     if (ehtPpduType == 1)
     {
         return {1, 0};
     }
-    return HePpdu::GetNumRusPerHeSigBContentChannel(channelWidth, ruAllocation);
+    return HePpdu::GetNumRusPerHeSigBContentChannel(channelWidth,
+                                                    ruAllocation,
+                                                    compression,
+                                                    numMuMimoUsers);
 }
 
 HePpdu::HeSigBContentChannels
@@ -183,22 +202,31 @@
 uint32_t
 EhtPpdu::GetEhtSigFieldSize(uint16_t channelWidth,
                             const RuAllocation& ruAllocation,
-                            uint8_t ehtPpduType)
+                            uint8_t ehtPpduType,
+                            bool compression,
+                            std::size_t numMuMimoUsers)
 {
     // FIXME: EHT-SIG is not implemented yet, hence this is a copy of HE-SIG-B
-    auto commonFieldSize = 4 /* CRC */ + 6 /* tail */;
-    if (channelWidth <= 40)
-    {
-        commonFieldSize += 8; // only one allocation subfield
-    }
-    else
+    uint32_t commonFieldSize = 0;
+    if (!compression)
     {
-        commonFieldSize +=
-            8 * (channelWidth / 40) /* one allocation field per 40 MHz */ + 1 /* center RU */;
+        commonFieldSize = 4 /* CRC */ + 6 /* tail */;
+        if (channelWidth <= 40)
+        {
+            commonFieldSize += 8; // only one allocation subfield
+        }
+        else
+        {
+            commonFieldSize +=
+                8 * (channelWidth / 40) /* one allocation field per 40 MHz */ + 1 /* center RU */;
+        }
     }
 
-    auto numRusPerContentChannel =
-        GetNumRusPerEhtSigBContentChannel(channelWidth, ehtPpduType, ruAllocation);
+    auto numRusPerContentChannel = GetNumRusPerEhtSigBContentChannel(channelWidth,
+                                                                     ehtPpduType,
+                                                                     ruAllocation,
+                                                                     compression,
+                                                                     numMuMimoUsers);
     auto maxNumRusPerContentChannel =
         std::max(numRusPerContentChannel.first, numRusPerContentChannel.second);
     auto maxNumUserBlockFields = maxNumRusPerContentChannel /
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/eht-ppdu.h ns-3.40/src/wifi/model/eht/eht-ppdu.h
--- ns-3.39/src/wifi/model/eht/eht-ppdu.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/eht-ppdu.h	2023-09-27 13:30:37.902840000 -0700
@@ -110,13 +110,16 @@
      * \param channelWidth the channel width occupied by the PPDU (in MHz)
      * \param ehtPpduType the EHT_PPDU_TYPE used by the PPDU
      * \param ruAllocation 8 bit RU_ALLOCATION per 20 MHz
-
+     * \param compression flag whether compression mode is used by the PPDU
+     * \param numMuMimoUsers the number of MU-MIMO users addressed by the PPDU
      * \return a pair containing the number of RUs in each EHT-SIG-B content channel (resp. 1 and 2)
      */
     static std::pair<std::size_t, std::size_t> GetNumRusPerEhtSigBContentChannel(
         uint16_t channelWidth,
         uint8_t ehtPpduType,
-        const std::vector<uint8_t>& ruAllocation);
+        const std::vector<uint8_t>& ruAllocation,
+        bool compression,
+        std::size_t numMuMimoUsers);
 
     /**
      * Get the EHT-SIG content channels for a given PPDU
@@ -134,11 +137,15 @@
      * \param channelWidth the channel width occupied by the PPDU (in MHz)
      * \param ruAllocation 8 bit RU_ALLOCATION per 20 MHz
      * \param ehtPpduType the EHT_PPDU_TYPE used by the PPDU
+     * \param compression flag whether compression mode is used by the PPDU
+     * \param numMuMimoUsers the number of MU-MIMO users addressed by the PPDU
      * \return field size in bytes
      */
     static uint32_t GetEhtSigFieldSize(uint16_t channelWidth,
                                        const std::vector<uint8_t>& ruAllocation,
-                                       uint8_t ehtPpduType);
+                                       uint8_t ehtPpduType,
+                                       bool compression,
+                                       std::size_t numMuMimoUsers);
 
   private:
     bool IsDlMu() const override;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/emlsr-manager.cc ns-3.40/src/wifi/model/eht/emlsr-manager.cc
--- ns-3.39/src/wifi/model/eht/emlsr-manager.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/emlsr-manager.cc	2023-09-27 13:30:37.902840000 -0700
@@ -27,6 +27,8 @@
 #include "ns3/attribute-container.h"
 #include "ns3/log.h"
 #include "ns3/wifi-mpdu.h"
+#include "ns3/wifi-net-device.h"
+#include "ns3/wifi-phy-state-helper.h"
 
 namespace ns3
 {
@@ -55,12 +57,31 @@
                           MakeTimeAccessor(&EmlsrManager::m_emlsrTransitionDelay),
                           MakeTimeChecker(MicroSeconds(0), MicroSeconds(256)))
             .AddAttribute(
+                "MainPhyId",
+                "The ID of the main PHY (position in the vector of PHYs held by "
+                "WifiNetDevice). This attribute cannot be set after initialization.",
+                UintegerValue(0),
+                MakeUintegerAccessor(&EmlsrManager::SetMainPhyId, &EmlsrManager::GetMainPhyId),
+                MakeUintegerChecker<uint8_t>())
+            .AddAttribute("AuxPhyChannelWidth",
+                          "The maximum channel width (MHz) supported by Aux PHYs",
+                          UintegerValue(20),
+                          MakeUintegerAccessor(&EmlsrManager::m_auxPhyMaxWidth),
+                          MakeUintegerChecker<uint16_t>(20, 160))
+            .AddAttribute(
                 "EmlsrLinkSet",
                 "IDs of the links on which EMLSR mode will be enabled. An empty set "
                 "indicates to disable EMLSR.",
                 AttributeContainerValue<UintegerValue>(),
                 MakeAttributeContainerAccessor<UintegerValue>(&EmlsrManager::SetEmlsrLinks),
-                MakeAttributeContainerChecker<UintegerValue>(MakeUintegerChecker<uint8_t>()));
+                MakeAttributeContainerChecker<UintegerValue>(MakeUintegerChecker<uint8_t>()))
+            .AddAttribute("ResetCamState",
+                          "Whether to reset the state of the ChannelAccessManager associated with "
+                          "the link on which the main PHY has just switched to.",
+                          BooleanValue(false),
+                          MakeBooleanAccessor(&EmlsrManager::SetCamStateReset,
+                                              &EmlsrManager::GetCamStateReset),
+                          MakeBooleanChecker());
     return tid;
 }
 
@@ -103,6 +124,32 @@
                                          MakeCallback(&EmlsrManager::TxDropped, this));
 }
 
+void
+EmlsrManager::SetMainPhyId(uint8_t mainPhyId)
+{
+    NS_LOG_FUNCTION(this << mainPhyId);
+    NS_ABORT_MSG_IF(IsInitialized(), "Cannot be called once this object has been initialized");
+    m_mainPhyId = mainPhyId;
+}
+
+uint8_t
+EmlsrManager::GetMainPhyId() const
+{
+    return m_mainPhyId;
+}
+
+void
+EmlsrManager::SetCamStateReset(bool enable)
+{
+    m_resetCamState = enable;
+}
+
+bool
+EmlsrManager::GetCamStateReset() const
+{
+    return m_resetCamState;
+}
+
 const std::set<uint8_t>&
 EmlsrManager::GetEmlsrLinks() const
 {
@@ -148,7 +195,7 @@
     if (GetStaMac() && GetStaMac()->IsAssociated() && GetTransitionTimeout() && m_nextEmlsrLinks)
     {
         // Request to enable EMLSR mode on the given links, provided that they have been setup
-        SendEmlOperatingModeNotification();
+        SendEmlOmn();
     }
 }
 
@@ -161,12 +208,17 @@
 
     DoNotifyMgtFrameReceived(mpdu, linkId);
 
-    if (hdr.IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout() &&
-        m_nextEmlsrLinks && !m_nextEmlsrLinks->empty())
+    if (hdr.IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout())
     {
-        // we just completed ML setup with an AP MLD that supports EMLSR and a non-empty
-        // set of EMLSR links have been configured, hence enable EMLSR mode on those links
-        SendEmlOperatingModeNotification();
+        // we just completed ML setup with an AP MLD that supports EMLSR
+        ComputeOperatingChannels();
+
+        if (m_nextEmlsrLinks && !m_nextEmlsrLinks->empty())
+        {
+            // a non-empty set of EMLSR links have been configured, hence enable EMLSR mode
+            // on those links
+            SendEmlOmn();
+        }
     }
 
     if (hdr.IsAction() && hdr.GetAddr2() == m_staMac->GetBssid(linkId))
@@ -188,15 +240,152 @@
 }
 
 void
-EmlsrManager::SendEmlOperatingModeNotification()
+EmlsrManager::NotifyIcfReceived(uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this);
+    NS_LOG_FUNCTION(this << linkId);
 
-    NS_ABORT_MSG_IF(!m_emlsrTransitionTimeout,
-                    "AP did not advertise a Transition Timeout, cannot send EML notification");
-    NS_ASSERT_MSG(m_nextEmlsrLinks, "Need to set EMLSR links before calling this method");
+    NS_ASSERT(m_staMac->IsEmlsrLink(linkId));
+
+    // block transmissions and suspend medium access on all other EMLSR links
+    for (auto id : m_staMac->GetLinkIds())
+    {
+        if (id != linkId && m_staMac->IsEmlsrLink(id))
+        {
+            m_staMac->BlockTxOnLink(id, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
+            m_staMac->GetChannelAccessManager(id)->NotifyStartUsingOtherEmlsrLink();
+        }
+    }
+
+    auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
+    auto auxPhy = m_staMac->GetWifiPhy(linkId);
+
+    if (m_staMac->GetWifiPhy(linkId) == mainPhy)
+    {
+        // nothing to do, we received an ICF from the main PHY
+        return;
+    }
+
+    SwitchMainPhy(linkId, true); // channel switch should occur instantaneously
+
+    // aux PHY received the ICF but main PHY will send the response
+    auto uid = auxPhy->GetPreviouslyRxPpduUid();
+    mainPhy->SetPreviouslyRxPpduUid(uid);
+}
+
+void
+EmlsrManager::NotifyUlTxopStart(uint8_t linkId)
+{
+    NS_LOG_FUNCTION(this << linkId);
+
+    if (!m_staMac->IsEmlsrLink(linkId))
+    {
+        NS_LOG_DEBUG("EMLSR is not enabled on link " << +linkId);
+        return;
+    }
+
+    // block transmissions and suspend medium access on all other EMLSR links
+    for (auto id : m_staMac->GetLinkIds())
+    {
+        if (id != linkId && m_staMac->IsEmlsrLink(id))
+        {
+            m_staMac->BlockTxOnLink(id, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
+            m_staMac->GetChannelAccessManager(id)->NotifyStartUsingOtherEmlsrLink();
+        }
+    }
+
+    // if this TXOP is being started by an aux PHY, wait until the end of RTS transmission and
+    // then have the main PHY (instantaneously) take over the TXOP on this link. We may start the
+    // channel switch now and use the channel switch delay configured for the main PHY, but then
+    // we would have no guarantees that the channel switch is completed in RTS TX time plus SIFS.
+    if (m_staMac->GetLinkForPhy(m_mainPhyId) != linkId)
+    {
+        auto stateHelper = m_staMac->GetWifiPhy(linkId)->GetState();
+        NS_ASSERT(stateHelper);
+        NS_ASSERT_MSG(stateHelper->GetState() == TX,
+                      "Expecting the aux PHY to be transmitting (an RTS frame)");
+        Simulator::Schedule(stateHelper->GetDelayUntilIdle(),
+                            &EmlsrManager::SwitchMainPhy,
+                            this,
+                            linkId,
+                            true); // channel switch should occur instantaneously
+    }
+}
+
+void
+EmlsrManager::NotifyTxopEnd(uint8_t linkId)
+{
+    NS_LOG_FUNCTION(this << linkId);
+
+    if (!m_staMac->IsEmlsrLink(linkId))
+    {
+        NS_LOG_DEBUG("EMLSR is not enabled on link " << +linkId);
+        return;
+    }
+
+    // unblock transmissions and resume medium access on other EMLSR links
+    for (auto id : m_staMac->GetLinkIds())
+    {
+        if (id != linkId && m_staMac->IsEmlsrLink(id))
+        {
+            m_staMac->UnblockTxOnLink(id, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
+            m_staMac->GetChannelAccessManager(id)->NotifyStopUsingOtherEmlsrLink();
+        }
+    }
+}
+
+void
+EmlsrManager::SwitchMainPhy(uint8_t linkId, bool noSwitchDelay)
+{
+    NS_LOG_FUNCTION(this << linkId << noSwitchDelay);
+
+    auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
+
+    NS_ASSERT_MSG(mainPhy != m_staMac->GetWifiPhy(linkId),
+                  "Main PHY is already operating on link " << +linkId);
+
+    // 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");
+
+    auto newMainPhyChannel = GetChannelForMainPhy(linkId);
+
+    NS_LOG_DEBUG("Main PHY (" << mainPhy << ") is about to switch to " << newMainPhyChannel
+                              << " to operate on link " << +linkId);
+
+    // notify the channel access manager of the upcoming channel switch(es)
+    m_staMac->GetChannelAccessManager(*currMainPhyLinkId)
+        ->NotifySwitchingEmlsrLink(mainPhy, newMainPhyChannel, linkId);
+
+    // this assert also ensures that the actual channel switch is not delayed
+    NS_ASSERT_MSG(!mainPhy->GetState()->IsStateTx(),
+                  "We should not ask the main PHY to switch channel while transmitting");
+
+    // request the main PHY to switch channel
+    Simulator::ScheduleNow([=]() {
+        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) << ")");
+        if (noSwitchDelay)
+        {
+            mainPhy->SetAttribute("ChannelSwitchDelay", TimeValue(Seconds(0)));
+        }
+        mainPhy->SetOperatingChannel(newMainPhyChannel);
+        // restore previous channel switch delay
+        if (noSwitchDelay)
+        {
+            mainPhy->SetAttribute("ChannelSwitchDelay", TimeValue(delay));
+        }
+    });
+
+    NotifyMainPhySwitch(*currMainPhyLinkId, linkId);
+}
 
-    MgtEmlOperatingModeNotification frame;
+MgtEmlOmn
+EmlsrManager::GetEmlOmn()
+{
+    MgtEmlOmn frame;
 
     // Add the EMLSR Parameter Update field if needed
     if (m_lastAdvPaddingDelay != m_emlsrPaddingDelay ||
@@ -205,7 +394,7 @@
         m_lastAdvPaddingDelay = m_emlsrPaddingDelay;
         m_lastAdvTransitionDelay = m_emlsrTransitionDelay;
         frame.m_emlControl.emlsrParamUpdateCtrl = 1;
-        frame.m_emlsrParamUpdate = MgtEmlOperatingModeNotification::EmlsrParamUpdate{};
+        frame.m_emlsrParamUpdate = MgtEmlOmn::EmlsrParamUpdate{};
         frame.m_emlsrParamUpdate->paddingDelay =
             CommonInfoBasicMle::EncodeEmlsrPaddingDelay(m_lastAdvPaddingDelay);
         frame.m_emlsrParamUpdate->transitionDelay =
@@ -220,9 +409,7 @@
         if (auto setupLinkIt = setupLinkIds.find(*emlsrLinkIt); setupLinkIt != setupLinkIds.cend())
         {
             setupLinkIds.erase(setupLinkIt);
-            auto apLinkId = m_staMac->GetApLinkId(*emlsrLinkIt);
-            NS_ASSERT(apLinkId);
-            frame.SetLinkIdInBitmap(*apLinkId);
+            frame.SetLinkIdInBitmap(*emlsrLinkIt);
             emlsrLinkIt++;
         }
         else
@@ -235,6 +422,18 @@
     // EMLSR Mode is enabled if and only if the set of EMLSR links is not empty
     frame.m_emlControl.emlsrMode = m_nextEmlsrLinks->empty() ? 0 : 1;
 
+    return frame;
+}
+
+void
+EmlsrManager::SendEmlOmn()
+{
+    NS_LOG_FUNCTION(this);
+
+    NS_ABORT_MSG_IF(!m_emlsrTransitionTimeout,
+                    "AP did not advertise a Transition Timeout, cannot send EML notification");
+    NS_ASSERT_MSG(m_nextEmlsrLinks, "Need to set EMLSR links before calling this method");
+
     // TODO if this is a single radio non-AP MLD and not all setup links are in the EMLSR link
     // set, we have to put setup links that are not included in the given EMLSR link set (i.e.,
     // those remaining in setupLinkIds, if m_nextEmlsrLinks is not empty) in the sleep mode:
@@ -244,8 +443,9 @@
     // non-AP STA affiliated with the non-AP MLD that operates on one of the EMLSR links is
     // in awake state. (Sec. 35.3.17 of 802.11be D3.0)
 
-    auto linkId = GetLinkToSendEmlNotification();
-    GetEhtFem(linkId)->SendEmlOperatingModeNotification(m_staMac->GetBssid(linkId), frame);
+    auto frame = GetEmlOmn();
+    auto linkId = GetLinkToSendEmlOmn();
+    GetEhtFem(linkId)->SendEmlOmn(m_staMac->GetBssid(linkId), frame);
 }
 
 void
@@ -303,10 +503,9 @@
             auto linkId = ResendNotification(mpdu);
             if (linkId)
             {
-                MgtEmlOperatingModeNotification frame;
+                MgtEmlOmn frame;
                 pkt->RemoveHeader(frame);
-                GetEhtFem(*linkId)->SendEmlOperatingModeNotification(m_staMac->GetBssid(*linkId),
-                                                                     frame);
+                GetEhtFem(*linkId)->SendEmlOmn(m_staMac->GetBssid(*linkId), frame);
             }
             else
             {
@@ -332,10 +531,108 @@
     m_emlsrLinks.swap(*m_nextEmlsrLinks);
     m_nextEmlsrLinks.reset();
 
-    // TODO Make other non-AP STAs operating on the corresponding EMLSR links transition to
+    // Make other non-AP STAs operating on the corresponding EMLSR links transition to
     // active mode or passive mode (depending on whether EMLSR mode has been enabled or disabled)
+    m_staMac->NotifyEmlsrModeChanged(m_emlsrLinks);
+    // Enforce the limit on the max channel width supported by aux PHYs
+    ApplyMaxChannelWidthOnAuxPhys();
 
     NotifyEmlsrModeChanged();
 }
 
+void
+EmlsrManager::ApplyMaxChannelWidthOnAuxPhys()
+{
+    NS_LOG_FUNCTION(this);
+    auto currMainPhyLinkId = m_staMac->GetLinkForPhy(m_mainPhyId);
+    NS_ASSERT(currMainPhyLinkId);
+
+    for (const auto linkId : m_staMac->GetLinkIds())
+    {
+        auto auxPhy = m_staMac->GetWifiPhy(linkId);
+        auto channel = GetChannelForAuxPhy(linkId);
+
+        if (linkId == currMainPhyLinkId || !m_staMac->IsEmlsrLink(linkId) ||
+            auxPhy->GetOperatingChannel() == channel)
+        {
+            continue;
+        }
+
+        NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << channel
+                                 << " to operate on link " << +linkId);
+        // We cannot simply set the new channel, because otherwise the MAC will disable
+        // the setup link. We need to inform the MAC (via the Channel Access Manager) that
+        // this channel switch must not have such a consequence. We already have a method
+        // for doing so, i.e., inform the MAC that the PHY is switching channel to operate
+        // on the "same" link.
+        m_staMac->GetChannelAccessManager(linkId)->NotifySwitchingEmlsrLink(auxPhy,
+                                                                            channel,
+                                                                            linkId);
+
+        void (WifiPhy::*fp)(const WifiPhyOperatingChannel&) = &WifiPhy::SetOperatingChannel;
+        Simulator::ScheduleNow(fp, auxPhy, channel);
+    }
+}
+
+void
+EmlsrManager::ComputeOperatingChannels()
+{
+    NS_LOG_FUNCTION(this);
+
+    m_mainPhyChannels.clear();
+    m_auxPhyChannels.clear();
+
+    auto linkIds = m_staMac->GetSetupLinkIds();
+
+    for (auto linkId : linkIds)
+    {
+        const auto& channel = m_staMac->GetWifiPhy(linkId)->GetOperatingChannel();
+        m_mainPhyChannels.emplace(linkId, channel);
+
+        auto mainPhyChWidth = channel.GetWidth();
+        if (m_auxPhyMaxWidth >= mainPhyChWidth)
+        {
+            // same channel can be used by aux PHYs
+            m_auxPhyChannels.emplace(linkId, channel);
+            continue;
+        }
+        // aux PHYs will operate on a primary subchannel
+        auto freq = channel.GetPrimaryChannelCenterFrequency(m_auxPhyMaxWidth);
+        auto chIt = WifiPhyOperatingChannel::FindFirst(0,
+                                                       freq,
+                                                       m_auxPhyMaxWidth,
+                                                       WIFI_STANDARD_UNSPECIFIED,
+                                                       channel.GetPhyBand());
+        NS_ASSERT_MSG(chIt != WifiPhyOperatingChannel::m_frequencyChannels.end(),
+                      "Primary" << m_auxPhyMaxWidth << " channel not found");
+        m_auxPhyChannels.emplace(linkId, chIt);
+        // find the P20 index for the channel used by the aux PHYs
+        auto p20Index = channel.GetPrimaryChannelIndex(20);
+        while (mainPhyChWidth > m_auxPhyMaxWidth)
+        {
+            mainPhyChWidth /= 2;
+            p20Index /= 2;
+        }
+        m_auxPhyChannels[linkId].SetPrimary20Index(p20Index);
+    }
+}
+
+const WifiPhyOperatingChannel&
+EmlsrManager::GetChannelForMainPhy(uint8_t linkId) const
+{
+    auto it = m_mainPhyChannels.find(linkId);
+    NS_ASSERT_MSG(it != m_mainPhyChannels.end(),
+                  "Channel for main PHY on link ID " << +linkId << " not found");
+    return it->second;
+}
+
+const WifiPhyOperatingChannel&
+EmlsrManager::GetChannelForAuxPhy(uint8_t linkId) const
+{
+    auto it = m_auxPhyChannels.find(linkId);
+    NS_ASSERT_MSG(it != m_auxPhyChannels.end(),
+                  "Channel for aux PHY on link ID " << +linkId << " not found");
+    return it->second;
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/emlsr-manager.h ns-3.40/src/wifi/model/eht/emlsr-manager.h
--- ns-3.39/src/wifi/model/eht/emlsr-manager.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/emlsr-manager.h	2023-09-27 13:30:37.902840000 -0700
@@ -20,11 +20,14 @@
 #ifndef EMLSR_MANAGER_H
 #define EMLSR_MANAGER_H
 
+#include "ns3/ctrl-headers.h"
 #include "ns3/mac48-address.h"
 #include "ns3/mgt-headers.h"
 #include "ns3/object.h"
 #include "ns3/sta-wifi-mac.h"
+#include "ns3/wifi-phy-operating-channel.h"
 
+#include <map>
 #include <optional>
 #include <set>
 
@@ -71,6 +74,19 @@
     std::optional<Time> GetTransitionTimeout() const;
 
     /**
+     * Set the ID of main PHY (position in the vector of PHYs held by WifiNetDevice). This
+     * method cannot be called during or after initialization.
+     *
+     * \param mainPhyId the ID of the main PHY
+     */
+    void SetMainPhyId(uint8_t mainPhyId);
+
+    /**
+     * \return the ID of main PHY (position in the vector of PHYs held by WifiNetDevice)
+     */
+    uint8_t GetMainPhyId() const;
+
+    /**
      * Take actions to enable EMLSR mode on the given set of links, if non-empty, or
      * disable EMLSR mode, otherwise.
      *
@@ -85,6 +101,20 @@
     const std::set<uint8_t>& GetEmlsrLinks() const;
 
     /**
+     * Set the member variable indicating whether the state of the CAM should be reset when
+     * the main PHY switches channel and operates on the link associated with the CAM.
+     *
+     * \param enable whether the CAM state should be reset
+     */
+    void SetCamStateReset(bool enable);
+
+    /**
+     * \return the value of the member variable indicating whether the state of the CAM should be
+     * reset when the main PHY switches channel and operates on the link associated with the CAM.
+     */
+    bool GetCamStateReset() const;
+
+    /**
      * Notify the reception of a management frame addressed to us.
      *
      * \param mpdu the received MPDU
@@ -92,6 +122,27 @@
      */
     void NotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId);
 
+    /**
+     * Notify the reception of an initial Control frame on the given link.
+     *
+     * \param linkId the ID of the link on which the initial Control frame was received
+     */
+    void NotifyIcfReceived(uint8_t linkId);
+
+    /**
+     * Notify the start of an UL TXOP on the given link
+     *
+     * \param linkId the ID of the given link
+     */
+    void NotifyUlTxopStart(uint8_t linkId);
+
+    /**
+     * Notify the end of a TXOP on the given link.
+     *
+     * \param linkId the ID of the given link
+     */
+    void NotifyTxopEnd(uint8_t linkId);
+
   protected:
     void DoDispose() override;
 
@@ -109,7 +160,7 @@
     /**
      * \return the ID of the link on which the EML Operating Mode Notification frame has to be sent
      */
-    virtual uint8_t GetLinkToSendEmlNotification() = 0;
+    virtual uint8_t GetLinkToSendEmlOmn() = 0;
 
     /**
      * A previous EML Operating Mode Notification frame was dropped. Ask the subclass whether
@@ -120,14 +171,43 @@
      */
     virtual std::optional<uint8_t> ResendNotification(Ptr<const WifiMpdu> mpdu) = 0;
 
+    /**
+     * \param linkId the ID of the given link
+     * \return the operating channel the main PHY must switch to in order to operate
+     *         on the given link
+     */
+    const WifiPhyOperatingChannel& GetChannelForMainPhy(uint8_t linkId) const;
+
+    /**
+     * \param linkId the ID of the given link
+     * \return the operating channel an aux PHY must switch to in order to operate
+     *         on the given link
+     */
+    const WifiPhyOperatingChannel& GetChannelForAuxPhy(uint8_t linkId) const;
+
+    /**
+     * \return the EML Operating Mode Notification to send
+     */
+    MgtEmlOmn GetEmlOmn();
+
     Time m_emlsrPaddingDelay;    //!< EMLSR Padding delay
     Time m_emlsrTransitionDelay; //!< EMLSR Transition delay
+    uint8_t m_mainPhyId; //!< ID of main PHY (position in the vector of PHYs held by WifiNetDevice)
+    uint16_t m_auxPhyMaxWidth; //!< max channel width (MHz) supported by aux PHYs
 
   private:
     /**
+     * Compute the operating channels that the main PHY and the aux PHY(s) must switch to in order
+     * to operate on each of the setup links. The operating channels may be different due to
+     * limited channel width capabilities of the aux PHY(s). This method shall be called upon
+     * completion of ML setup.
+     */
+    void ComputeOperatingChannels();
+
+    /**
      * Send an EML Operating Mode Notification frame.
      */
-    void SendEmlOperatingModeNotification();
+    void SendEmlOmn();
 
     /**
      * Notify the subclass of the reception of a management frame addressed to us.
@@ -159,10 +239,32 @@
     void ChangeEmlsrMode();
 
     /**
+     * Switch channel on the Main PHY so that it operates on the given link.
+     *
+     * \param linkId the ID of the link on which the main PHY has to operate
+     * \param noSwitchDelay whether switching delay should be zero
+     */
+    void SwitchMainPhy(uint8_t linkId, bool noSwitchDelay);
+
+    /**
+     * Adjust the operating channel of all the aux PHYs to meet the constraint on the maximum
+     * channel width supported by aux PHYs.
+     */
+    void ApplyMaxChannelWidthOnAuxPhys();
+
+    /**
      * Notify subclass that EMLSR mode changed.
      */
     virtual void NotifyEmlsrModeChanged() = 0;
 
+    /**
+     * Notify subclass that the main PHY is switching channel to operate on another link.
+     *
+     * \param currLinkId the ID of the link on which the main PHY is operating
+     * \param nextLinkId the ID of the link on which the main PHY will be operating
+     */
+    virtual void NotifyMainPhySwitch(uint8_t currLinkId, uint8_t nextLinkId) = 0;
+
     Ptr<StaWifiMac> m_staMac;                     //!< the MAC of the managed non-AP MLD
     std::optional<Time> m_emlsrTransitionTimeout; /**< Transition timeout advertised by APs with
                                                        EMLSR activated */
@@ -174,6 +276,11 @@
     Time m_lastAdvTransitionDelay;                     //!< last advertised transition delay
     EventId m_transitionTimeoutEvent; /**< Timer started after the successful transmission of an
                                            EML Operating Mode Notification frame */
+    bool m_resetCamState; //!< whether to reset the state of CAM when main PHY switches channel
+    std::map<uint8_t, WifiPhyOperatingChannel>
+        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
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/multi-link-element.cc ns-3.40/src/wifi/model/eht/multi-link-element.cc
--- ns-3.39/src/wifi/model/eht/multi-link-element.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/multi-link-element.cc	2023-09-27 13:30:37.902840000 -0700
@@ -269,6 +269,18 @@
     }
 }
 
+CommonInfoBasicMle&
+MultiLinkElement::GetCommonInfoBasic()
+{
+    return std::get<BASIC_VARIANT>(m_commonInfo);
+}
+
+const CommonInfoBasicMle&
+MultiLinkElement::GetCommonInfoBasic() const
+{
+    return std::get<BASIC_VARIANT>(m_commonInfo);
+}
+
 void
 MultiLinkElement::SetMldMacAddress(Mac48Address address)
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/multi-link-element.h ns-3.40/src/wifi/model/eht/multi-link-element.h
--- ns-3.39/src/wifi/model/eht/multi-link-element.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/multi-link-element.h	2023-09-27 13:30:37.902840000 -0700
@@ -217,6 +217,12 @@
      */
     Variant GetVariant() const;
 
+    /// \return a reference to the Common Info field (the MLE variant must be Basic)
+    CommonInfoBasicMle& GetCommonInfoBasic();
+
+    /// \return a const reference to the Common Info field (the MLE variant must be Basic)
+    const CommonInfoBasicMle& GetCommonInfoBasic() const;
+
     /**
      * Set the MLD MAC Address subfield in the Common Info field. Make sure that
      * this is a Basic Multi-Link Element.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/tid-to-link-mapping-element.cc ns-3.40/src/wifi/model/eht/tid-to-link-mapping-element.cc
--- ns-3.39/src/wifi/model/eht/tid-to-link-mapping-element.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/tid-to-link-mapping-element.cc	2023-09-27 13:30:37.902840000 -0700
@@ -17,20 +17,25 @@
  * Author: Sharan Naribole <sharan.naribole@gmail.com>
  */
 
-#include <ns3/assert.h>
-#include <ns3/tid-to-link-mapping-element.h>
+#include "tid-to-link-mapping-element.h"
+
+#include "ns3/assert.h"
+#include "ns3/simulator.h"
 
 namespace ns3
 {
 
+/// Bitmask with all bits from 63 to 26 set to 1, all the others set to 0
+static constexpr uint64_t BIT_63_TO_26_MASK = 0xfffffffffc000000;
+
 uint16_t
 TidToLinkMapping::Control::GetSubfieldSize() const
 {
-    // IEEE 802.11be D2.0 Figure 9-1002an
-    NS_ASSERT_MSG(defaultMapping != presenceBitmap.has_value(),
+    // IEEE 802.11be D3.1 Figure 9-1002ap
+    NS_ASSERT_MSG(!defaultMapping || !presenceBitmap.has_value(),
                   "Presence bitmap not expected if default mapping is set");
     auto size = WIFI_TID_TO_LINK_MAPPING_CONTROL_BASIC_SIZE_B;
-    if (defaultMapping)
+    if (!presenceBitmap.has_value())
     {
         return size;
     }
@@ -40,10 +45,12 @@
 void
 TidToLinkMapping::Control::Serialize(Buffer::Iterator& start) const
 {
-    uint8_t val = static_cast<uint8_t>(direction);
-    val |= ((defaultMapping ? 1 : 0) << 2);
+    auto val = static_cast<uint8_t>(direction) | ((defaultMapping ? 1 : 0) << 2) |
+               ((mappingSwitchTimePresent ? 1 : 0) << 3) |
+               ((expectedDurationPresent ? 1 : 0) << 4) | ((linkMappingSize == 1 ? 1 : 0) << 5);
+
     start.WriteU8(val);
-    NS_ASSERT_MSG(defaultMapping != presenceBitmap.has_value(),
+    NS_ASSERT_MSG(!defaultMapping || !presenceBitmap.has_value(),
                   "Presence bitmap not expected if default mapping is set");
     if (presenceBitmap.has_value())
     {
@@ -59,10 +66,14 @@
     auto val = i.ReadU8();
     count++;
 
-    direction = static_cast<TidLinkMapDir>(val & 0x03);
+    direction = static_cast<WifiDirection>(val & 0x03);
     defaultMapping = (((val >> 2) & 0x01) == 1);
+    mappingSwitchTimePresent = (((val >> 3) & 0x01) == 1);
+    expectedDurationPresent = (((val >> 4) & 0x01) == 1);
+    linkMappingSize = (((val >> 5) & 0x01) == 1 ? 1 : 2);
     if (defaultMapping)
     {
+        presenceBitmap.reset();
         return count;
     }
     presenceBitmap = i.ReadU8();
@@ -82,7 +93,60 @@
 }
 
 void
-TidToLinkMapping::SetLinkMappingOfTid(uint8_t tid, std::list<uint8_t> linkIds)
+TidToLinkMapping::SetMappingSwitchTime(Time mappingSwitchTime)
+{
+    // The 2 octet Mapping Switch Time field has units of TUs and is set to the time at which
+    // the new mapping is established using as a time-base the value of the TSF corresponding
+    // to the BSS identified by the BSSID of the frame containing the TID-To-Link Mapping
+    // element: i.e., bits 10 to 25 of the TSF. (Sec. 9.4.2.314 of 802.11be D3.1)
+    NS_ABORT_IF(mappingSwitchTime < Simulator::Now());
+    auto switchTimeUsec = static_cast<uint64_t>(mappingSwitchTime.GetMicroSeconds());
+    // set the Mapping Switch Time field to bits 10 to 25 of the given time
+    m_mappingSwitchTime = (switchTimeUsec & ~BIT_63_TO_26_MASK) >> 10;
+    m_control.mappingSwitchTimePresent = true;
+}
+
+std::optional<Time>
+TidToLinkMapping::GetMappingSwitchTime() const
+{
+    if (!m_control.mappingSwitchTimePresent)
+    {
+        return std::nullopt;
+    }
+
+    auto nowUsec = static_cast<uint64_t>(Simulator::Now().GetMicroSeconds());
+    uint64_t switchTimeUsec = (*m_mappingSwitchTime << 10) + (nowUsec & BIT_63_TO_26_MASK);
+    if (switchTimeUsec < nowUsec)
+    {
+        // The switch time derived from the value in the corresponding field may be less than the
+        // current time in case the bits 10 to 25 of TSF have been reset since the transmission
+        // of the frame carrying this field. In such a case we have to increase bits 63 to 26 by 1
+        switchTimeUsec += (1 << 26);
+    }
+    return MicroSeconds(switchTimeUsec);
+}
+
+void
+TidToLinkMapping::SetExpectedDuration(Time expectedDuration)
+{
+    auto durationTu = static_cast<uint64_t>(expectedDuration.GetMicroSeconds()) >> 10;
+    m_expectedDuration = (durationTu & 0x0000000000ffffff); // Expected Duration size is 3 bytes
+    m_control.expectedDurationPresent = true;
+}
+
+std::optional<Time>
+TidToLinkMapping::GetExpectedDuration() const
+{
+    if (!m_control.expectedDurationPresent)
+    {
+        return std::nullopt;
+    }
+
+    return MicroSeconds(*m_expectedDuration << 10);
+}
+
+void
+TidToLinkMapping::SetLinkMappingOfTid(uint8_t tid, std::set<uint8_t> linkIds)
 {
     NS_ABORT_MSG_IF(tid > 7, "Invalid tid: " << +tid);
     NS_ABORT_MSG_IF(m_control.defaultMapping,
@@ -94,35 +158,35 @@
     for (const auto& linkId : linkIds)
     {
         linkMapping |= (1 << linkId);
+        if (linkId > 7)
+        {
+            m_control.linkMappingSize = 2;
+        }
     }
 
     m_linkMapping[tid] = linkMapping;
-
-    if (!m_control.presenceBitmap.has_value())
-    {
-        m_control.presenceBitmap = 0;
-    }
-    *m_control.presenceBitmap |= (1 << tid);
+    m_control.presenceBitmap = m_control.presenceBitmap.value_or(0) | (1 << tid);
 }
 
-std::list<uint8_t>
+std::set<uint8_t>
 TidToLinkMapping::GetLinkMappingOfTid(uint8_t tid) const
 {
     auto it = m_linkMapping.find(tid);
 
-    if (it == m_linkMapping.end())
+    if (it == m_linkMapping.cend())
     {
         return {};
     }
 
-    std::list<uint8_t> linkIds;
+    std::set<uint8_t> linkIds;
     for (uint8_t linkId = 0; linkId < 15; linkId++)
     {
         if (((it->second >> linkId) & 0x0001) == 1)
         {
-            linkIds.push_back(linkId);
+            linkIds.insert(linkId);
         }
     }
+    NS_ABORT_MSG_IF(linkIds.empty(), "TID " << +tid << " cannot be mapped to an empty link set");
 
     return linkIds;
 }
@@ -130,26 +194,53 @@
 uint16_t
 TidToLinkMapping::GetInformationFieldSize() const
 {
-    // IEEE 802.11be D2.0 9.4.2.314 TID-To-Link Mapping element
+    // IEEE 802.11be D3.1 9.4.2.314 TID-To-Link Mapping element
     uint16_t ret = WIFI_IE_ELEMENT_ID_EXT_SIZE; // Element ID Extension
     ret += m_control.GetSubfieldSize();
-    NS_ASSERT_MSG(m_linkMapping.empty() == m_control.defaultMapping,
+    if (m_control.mappingSwitchTimePresent)
+    {
+        ret += 2; // Mapping Switch Time
+    }
+    if (m_control.expectedDurationPresent)
+    {
+        ret += 3; // Expected Duration
+    }
+
+    NS_ASSERT_MSG(!m_control.defaultMapping || m_linkMapping.empty(),
                   "Per-TID link mapping not expected if default mapping is set");
-    ret += WIFI_LINK_MAPPING_PER_TID_SIZE_B * (m_linkMapping.size());
+    ret += m_control.linkMappingSize * (m_linkMapping.size());
     return ret;
 }
 
 void
 TidToLinkMapping::SerializeInformationField(Buffer::Iterator start) const
 {
-    // IEEE 802.11be D2.0 9.4.2.314 TID-To-Link Mapping element
+    // IEEE 802.11be D3.1 9.4.2.314 TID-To-Link Mapping element
     m_control.Serialize(start);
-    NS_ASSERT_MSG(m_linkMapping.empty() == m_control.defaultMapping,
+    if (m_control.mappingSwitchTimePresent)
+    {
+        start.WriteHtolsbU16(*m_mappingSwitchTime);
+    }
+    if (m_control.expectedDurationPresent)
+    {
+        start.WriteU8((*m_expectedDuration >> 0) & 0xff);
+        start.WriteU8((*m_expectedDuration >> 8) & 0xff);
+        start.WriteU8((*m_expectedDuration >> 16) & 0xff);
+    }
+
+    NS_ASSERT_MSG(!m_control.defaultMapping || m_linkMapping.empty(),
                   "Per-TID link mapping not expected if default mapping is set");
 
     for (const auto& [tid, linkMapping] : m_linkMapping)
     {
-        start.WriteHtolsbU16(linkMapping);
+        if (m_control.linkMappingSize == 1)
+        {
+            start.WriteU8(linkMapping);
+        }
+        else
+        {
+            start.WriteHtolsbU16(linkMapping);
+        }
     }
 }
 
@@ -162,6 +253,23 @@
     NS_ASSERT_MSG(nCtrlOctets <= length, "Tid-to-Link Mapping deserialize error");
     i.Next(nCtrlOctets);
     count += nCtrlOctets;
+    if (m_control.mappingSwitchTimePresent)
+    {
+        m_mappingSwitchTime = i.ReadLsbtohU16();
+        count += 2;
+    }
+    if (m_control.expectedDurationPresent)
+    {
+        uint8_t byte0 = i.ReadU8();
+        uint8_t byte1 = i.ReadU8();
+        uint8_t byte2 = i.ReadU8();
+        m_expectedDuration = byte2;
+        m_expectedDuration.value() <<= 8;
+        m_expectedDuration.value() |= byte1;
+        m_expectedDuration.value() <<= 8;
+        m_expectedDuration.value() |= byte0;
+        count += 3;
+    }
     m_linkMapping.clear();
     if (m_control.presenceBitmap.has_value())
     {
@@ -172,8 +280,16 @@
         {
             if (((presenceBitmap >> tid) & 0x01) == 1)
             {
-                m_linkMapping[tid] = i.ReadLsbtohU16();
-                count += 2;
+                if (m_control.linkMappingSize == 1)
+                {
+                    m_linkMapping[tid] = i.ReadU8();
+                    count++;
+                }
+                else
+                {
+                    m_linkMapping[tid] = i.ReadLsbtohU16();
+                    count += 2;
+                }
             }
         }
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/eht/tid-to-link-mapping-element.h ns-3.40/src/wifi/model/eht/tid-to-link-mapping-element.h
--- ns-3.39/src/wifi/model/eht/tid-to-link-mapping-element.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/eht/tid-to-link-mapping-element.h	2023-09-27 13:30:37.902840000 -0700
@@ -20,33 +20,21 @@
 #ifndef TID_TO_LINK_MAPPING_H
 #define TID_TO_LINK_MAPPING_H
 
-#include <ns3/wifi-information-element.h>
+#include "ns3/nstime.h"
+#include "ns3/wifi-information-element.h"
+#include "ns3/wifi-utils.h"
 
-#include <list>
 #include <map>
 #include <optional>
-#include <vector>
+#include <set>
 
 namespace ns3
 {
 
-/**
- * TID-to-Link Mapping Control Direction
- * IEEE 802.11be D2.0 Figure 9-1002an
- */
-enum class TidLinkMapDir : uint8_t
-{
-    DOWNLINK = 0,
-    UPLINK = 1,
-    BOTH_DIRECTIONS = 2,
-};
-
 /// whether to enforce the default link mapping
 constexpr auto DEFAULT_WIFI_TID_LINK_MAPPING{true};
 /// default value for the Direction subfield of the TID-To-Link Control field
-constexpr auto DEFAULT_WIFI_TID_LINK_MAP_DIR{TidLinkMapDir::BOTH_DIRECTIONS};
-/// size in bytes of the Link Mapping Of TID n field (IEEE 802.11be D2.0 9.4.2.314)
-constexpr uint16_t WIFI_LINK_MAPPING_PER_TID_SIZE_B = 2;
+constexpr auto DEFAULT_WIFI_TID_LINK_MAP_DIR{WifiDirection::BOTH_DIRECTIONS};
 /// size in bytes of the TID-To-Link Control field with default link mapping
 constexpr uint16_t WIFI_TID_TO_LINK_MAPPING_CONTROL_BASIC_SIZE_B =
     1; // IEEE 802.11be D2.0 9.4.2.314
@@ -59,7 +47,7 @@
  *
  * This class serializes and deserializes
  * the TID-to-Link Mapping element
- * IEEE 802.11be D2.0 9.4.2.314
+ * IEEE 802.11be D3.1 9.4.2.314
  *
  */
 class TidToLinkMapping : public WifiInformationElement
@@ -67,13 +55,14 @@
   public:
     /**
      * TID-to-Link Mapping Control subfield
-     * IEEE 802.11be D2.0 Figure 9-1002an
+     * IEEE 802.11be D3.1 Figure 9-1002ap
      */
     struct Control
     {
-        TidLinkMapDir direction{DEFAULT_WIFI_TID_LINK_MAP_DIR}; ///< Direction
+        friend class TidToLinkMapping;
+
+        WifiDirection direction{DEFAULT_WIFI_TID_LINK_MAP_DIR}; ///< Direction
         bool defaultMapping{DEFAULT_WIFI_TID_LINK_MAPPING};     ///< Default link mapping
-        std::optional<uint8_t> presenceBitmap;                  ///< Link Mapping Presence Indicator
 
         /// \return Serialized size of TID-to-Link Mapping Control in octets
         uint16_t GetSubfieldSize() const;
@@ -91,31 +80,66 @@
          * \return the number of octets read
          */
         uint16_t Deserialize(Buffer::Iterator start);
+
+      private:
+        /**
+         * These members are private to prevent users to manipulate them directly (their values
+         * depend on the values of other fields)
+         */
+        bool mappingSwitchTimePresent{false}; ///< Mapping Switch Time Present
+        bool expectedDurationPresent{false};  ///< Expected Duration Present
+        uint8_t linkMappingSize{1}; ///< length of the Link Mapping Of TID n field in octets
+        std::optional<uint8_t> presenceBitmap; ///< Link Mapping Presence Indicator
     };
 
     WifiInformationElementId ElementId() const override;
     WifiInformationElementId ElementIdExt() const override;
 
     /**
+     * Set the Mapping Switch Time field.
+     *
+     * \param mappingSwitchTime the time when the new mapping is established (rounded to a
+     *                          multiple of a TU)
+     */
+    void SetMappingSwitchTime(Time mappingSwitchTime);
+
+    /// \return the value of the Mapping Switch Time field, if present.
+    std::optional<Time> GetMappingSwitchTime() const;
+
+    /**
+     * Set the Expected Duration field.
+     *
+     * \param expectedDuration the value for the Expected Duration field (rounded to a
+     *                         multiple of a TU)
+     */
+    void SetExpectedDuration(Time expectedDuration);
+
+    /// \return the value of the Expected Duration field, if present.
+    std::optional<Time> GetExpectedDuration() const;
+
+    /**
      * Set the Link Mapping field of the given TID such that the given TID is mapped
      * to the links associated with the given link IDs.
      *
      * \param tid the given TID
      * \param linkIds the IDs of the links which the given TID is mapped to
      */
-    void SetLinkMappingOfTid(uint8_t tid, std::list<uint8_t> linkIds);
+    void SetLinkMappingOfTid(uint8_t tid, std::set<uint8_t> linkIds);
     /**
      * Get the Link Mapping field of the given TID.
      *
      * \param tid the given TID
      * \return the IDs of the links which the given TID is mapped to
      */
-    std::list<uint8_t> GetLinkMappingOfTid(uint8_t tid) const;
+    std::set<uint8_t> GetLinkMappingOfTid(uint8_t tid) const;
 
     TidToLinkMapping::Control m_control;       ///< TID-to-link Mapping Control
     std::map<uint8_t, uint16_t> m_linkMapping; ///< TID-indexed Link Mapping
 
   private:
+    std::optional<uint16_t> m_mappingSwitchTime; ///< Mapping Switch Time
+    std::optional<uint32_t> m_expectedDuration;  ///< Expected Duration
+
     uint16_t GetInformationFieldSize() const override;
     void SerializeInformationField(Buffer::Iterator start) const override;
     uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/frame-exchange-manager.cc ns-3.40/src/wifi/model/frame-exchange-manager.cc
--- ns-3.39/src/wifi/model/frame-exchange-manager.cc	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/frame-exchange-manager.cc	2023-09-27 13:30:37.906839800 -0700
@@ -493,8 +493,7 @@
         // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
         // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
         // aRxPHYStartDelay equals the time to transmit the PHY header.
-        WifiNormalAck* normalAcknowledgment =
-            static_cast<WifiNormalAck*>(m_txParams.m_acknowledgment.get());
+        auto normalAcknowledgment = static_cast<WifiNormalAck*>(m_txParams.m_acknowledgment.get());
 
         Time timeout =
             txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
@@ -502,6 +501,7 @@
         NS_ASSERT(!m_txTimer.IsRunning());
         m_txTimer.Set(WifiTxTimer::WAIT_NORMAL_ACK,
                       timeout,
+                      {m_mpdu->GetHeader().GetAddr1()},
                       &FrameExchangeManager::NormalAckTimeout,
                       this,
                       m_mpdu,
@@ -525,6 +525,7 @@
 
     auto psdu = Create<WifiPsdu>(mpdu, false);
     FinalizeMacHeader(psdu);
+    m_allowedWidth = std::min(m_allowedWidth, txVector.GetChannelWidth());
     m_phy->Send(psdu, txVector);
 }
 
@@ -587,7 +588,7 @@
     }
     else if (protection->method == WifiProtection::RTS_CTS)
     {
-        WifiRtsCtsProtection* rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(protection);
+        auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(protection);
         rtsCtsProtection->protectionTime = m_phy->CalculateTxDuration(GetRtsSize(),
                                                                       rtsCtsProtection->rtsTxVector,
                                                                       m_phy->GetPhyBand()) +
@@ -598,8 +599,7 @@
     }
     else if (protection->method == WifiProtection::CTS_TO_SELF)
     {
-        WifiCtsToSelfProtection* ctsToSelfProtection =
-            static_cast<WifiCtsToSelfProtection*>(protection);
+        auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(protection);
         ctsToSelfProtection->protectionTime =
             m_phy->CalculateTxDuration(GetCtsSize(),
                                        ctsToSelfProtection->ctsTxVector,
@@ -620,7 +620,7 @@
     }
     else if (acknowledgment->method == WifiAcknowledgment::NORMAL_ACK)
     {
-        WifiNormalAck* normalAcknowledgment = static_cast<WifiNormalAck*>(acknowledgment);
+        auto normalAcknowledgment = static_cast<WifiNormalAck*>(acknowledgment);
         normalAcknowledgment->acknowledgmentTime =
             m_phy->GetSifs() + m_phy->CalculateTxDuration(GetAckSize(),
                                                           normalAcknowledgment->ackTxVector,
@@ -706,8 +706,7 @@
     rts.SetAddr2(m_self);
 
     NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS);
-    WifiRtsCtsProtection* rtsCtsProtection =
-        static_cast<WifiRtsCtsProtection*>(txParams.m_protection.get());
+    auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(txParams.m_protection.get());
 
     NS_ASSERT(txParams.m_txDuration != Time::Min());
     rts.SetDuration(GetRtsDurationId(rtsCtsProtection->rtsTxVector,
@@ -726,6 +725,7 @@
     NS_ASSERT(!m_txTimer.IsRunning());
     m_txTimer.Set(WifiTxTimer::WAIT_CTS,
                   timeout,
+                  {receiver},
                   &FrameExchangeManager::CtsTimeout,
                   this,
                   mpdu,
@@ -807,8 +807,7 @@
 
     NS_ASSERT(txParams.m_protection &&
               txParams.m_protection->method == WifiProtection::CTS_TO_SELF);
-    WifiCtsToSelfProtection* ctsToSelfProtection =
-        static_cast<WifiCtsToSelfProtection*>(txParams.m_protection.get());
+    auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(txParams.m_protection.get());
 
     NS_ASSERT(txParams.m_txDuration != Time::Min());
     cts.SetDuration(GetCtsToSelfDurationId(ctsToSelfProtection->ctsTxVector,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/frame-exchange-manager.h ns-3.40/src/wifi/model/frame-exchange-manager.h
--- ns-3.39/src/wifi/model/frame-exchange-manager.h	2023-07-05 14:23:48.109428400 -0700
+++ ns-3.40/src/wifi/model/frame-exchange-manager.h	2023-09-27 13:30:37.906839800 -0700
@@ -30,12 +30,12 @@
 #include "wifi-tx-timer.h"
 #include "wifi-tx-vector.h"
 
-#include "ns3/object.h"
 // Needed to compile wave bindings
 #include "channel-access-manager.h"
+#include "wifi-ack-manager.h"
+#include "wifi-protection-manager.h"
 
-#include "ns3/wifi-ack-manager.h"
-#include "ns3/wifi-protection-manager.h"
+#include "ns3/object.h"
 
 namespace ns3
 {
@@ -635,7 +635,6 @@
      */
     virtual void Reset();
 
-  private:
     /**
      * \param txVector the TXVECTOR decoded from PHY header.
      * \param psduDuration the duration of the PSDU that is about to be received.
@@ -646,8 +645,9 @@
      * If the reception is correct for at least one MPDU of the PSDU
      * the Receive method will be called after \p psduDuration.
      */
-    void RxStartIndication(WifiTxVector txVector, Time psduDuration);
+    virtual void RxStartIndication(WifiTxVector txVector, Time psduDuration);
 
+  private:
     /**
      * Send the current MPDU, which can be acknowledged by a Normal Ack.
      */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/he/he-frame-exchange-manager.cc ns-3.40/src/wifi/model/he/he-frame-exchange-manager.cc
--- ns-3.39/src/wifi/model/he/he-frame-exchange-manager.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/he/he-frame-exchange-manager.cc	2023-09-27 13:30:37.906839800 -0700
@@ -116,15 +116,12 @@
 }
 
 void
-HeFrameExchangeManager::SetWifiPhy(const Ptr<WifiPhy> phy)
+HeFrameExchangeManager::RxStartIndication(WifiTxVector txVector, Time psduDuration)
 {
-    NS_LOG_FUNCTION(this << phy);
-    VhtFrameExchangeManager::SetWifiPhy(phy);
+    NS_LOG_FUNCTION(this << txVector << psduDuration.As(Time::MS));
+    VhtFrameExchangeManager::RxStartIndication(txVector, psduDuration);
     // Cancel intra-BSS NAV reset timer when receiving a frame from the PHY
-    phy->TraceConnectWithoutContext("PhyRxPayloadBegin",
-                                    Callback<void, WifiTxVector, Time>([this](WifiTxVector, Time) {
-                                        m_intraBssNavResetEvent.Cancel();
-                                    }));
+    m_intraBssNavResetEvent.Cancel();
 }
 
 void
@@ -214,26 +211,6 @@
     return false;
 }
 
-bool
-HeFrameExchangeManager::SendMpduFromBaManager(Ptr<WifiMpdu> mpdu,
-                                              Time availableTime,
-                                              bool initialFrame)
-{
-    NS_LOG_FUNCTION(this << *mpdu << availableTime << initialFrame);
-
-    // First, check if there is a Trigger Frame to be transmitted
-    if (!mpdu->GetHeader().IsTrigger())
-    {
-        // BlockAckReq are handled by the HT FEM
-        return HtFrameExchangeManager::SendMpduFromBaManager(mpdu, availableTime, initialFrame);
-    }
-
-    m_triggerFrame = mpdu;
-
-    SendPsduMap();
-    return true;
-}
-
 void
 HeFrameExchangeManager::SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxParameters& txParams)
 {
@@ -318,8 +295,7 @@
     NS_LOG_FUNCTION(this << &txParams);
 
     NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS);
-    WifiMuRtsCtsProtection* protection =
-        static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
+    auto protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
 
     NS_ASSERT(protection->muRts.IsMuRts());
     NS_ASSERT_MSG(m_apMac, "APs only can send MU-RTS TF");
@@ -386,8 +362,7 @@
     hdr.SetNoMoreFragments();
 
     NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS);
-    WifiMuRtsCtsProtection* protection =
-        static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
+    auto protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
 
     NS_ASSERT(protection->muRts.IsMuRts());
     protection->muRts.SetCsRequired(true);
@@ -420,6 +395,7 @@
     NS_ASSERT(!m_txTimer.IsRunning());
     m_txTimer.Set(WifiTxTimer::WAIT_CTS_AFTER_MU_RTS,
                   timeout,
+                  m_sentRtsTo,
                   &HeFrameExchangeManager::CtsAfterMuRtsTimeout,
                   this,
                   mpdu,
@@ -527,6 +503,23 @@
 }
 
 void
+HeFrameExchangeManager::TransmissionSucceeded()
+{
+    NS_LOG_FUNCTION(this);
+
+    // A multi-user transmission may succeed even if some stations did not respond.
+    // Remove such stations from the set of stations for which protection is not needed
+    // in the current TXOP.
+    for (const auto& address : m_txTimer.GetStasExpectedToRespond())
+    {
+        NS_LOG_DEBUG(address << " did not respond, hence it is no longer protected");
+        m_protectedStas.erase(address);
+    }
+
+    VhtFrameExchangeManager::TransmissionSucceeded();
+}
+
+void
 HeFrameExchangeManager::SendPsduMap()
 {
     NS_LOG_FUNCTION(this);
@@ -539,6 +532,7 @@
     Ptr<WifiMpdu> mpdu = nullptr;
     Ptr<WifiPsdu> psdu = nullptr;
     WifiTxVector txVector;
+    std::set<Mac48Address> staExpectResponseFrom;
 
     // Compute the type of TX timer to set depending on the acknowledgment method
 
@@ -547,7 +541,7 @@
      */
     if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
     {
-        WifiDlMuBarBaSequence* acknowledgment =
+        auto acknowledgment =
             static_cast<WifiDlMuBarBaSequence*>(m_txParams.m_acknowledgment.get());
 
         // schedule the transmission of required BlockAckReq frames
@@ -575,10 +569,11 @@
             timerType = WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU;
             responseTxVector =
                 &acknowledgment->stationsReplyingWithNormalAck.begin()->second.ackTxVector;
-            psdu =
-                GetPsduTo(acknowledgment->stationsReplyingWithNormalAck.begin()->first, m_psduMap);
+            auto from = acknowledgment->stationsReplyingWithNormalAck.begin()->first;
+            psdu = GetPsduTo(from, m_psduMap);
             NS_ASSERT(psdu->GetNMpdus() == 1);
             mpdu = *psdu->begin();
+            staExpectResponseFrom.insert(from);
         }
         else if (!acknowledgment->stationsReplyingWithBlockAck.empty())
         {
@@ -586,8 +581,9 @@
             timerType = WifiTxTimer::WAIT_BLOCK_ACK;
             responseTxVector =
                 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
-            psdu =
-                GetPsduTo(acknowledgment->stationsReplyingWithBlockAck.begin()->first, m_psduMap);
+            auto from = acknowledgment->stationsReplyingWithBlockAck.begin()->first;
+            psdu = GetPsduTo(from, m_psduMap);
+            staExpectResponseFrom.insert(from);
         }
         // else no station will reply immediately
     }
@@ -596,8 +592,7 @@
      */
     else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
     {
-        WifiDlMuTfMuBar* acknowledgment =
-            static_cast<WifiDlMuTfMuBar*>(m_txParams.m_acknowledgment.get());
+        auto acknowledgment = static_cast<WifiDlMuTfMuBar*>(m_txParams.m_acknowledgment.get());
 
         if (!m_triggerFrame)
         {
@@ -624,18 +619,16 @@
             // set the UL Length field of the MU-BAR Trigger Frame
             m_trigVector.SetLength(acknowledgment->ulLength);
 
-            NS_ASSERT(m_edca);
-            m_edca->GetBaManager()->ScheduleMuBar(PrepareMuBar(m_trigVector, recipients));
+            m_triggerFrame = PrepareMuBar(m_trigVector, recipients);
         }
         else
         {
             // we are transmitting the MU-BAR following the DL MU PPDU after a SIFS.
             // m_psduMap and m_txParams are still the same as when the DL MU PPDU was sent.
             // record the set of stations expected to send a BlockAck frame
-            m_staExpectTbPpduFrom.clear();
             for (auto& station : acknowledgment->stationsReplyingWithBlockAck)
             {
-                m_staExpectTbPpduFrom.insert(station.first);
+                staExpectResponseFrom.insert(station.first);
             }
 
             Ptr<WifiPsdu> triggerPsdu = GetWifiPsdu(m_triggerFrame, acknowledgment->muBarTxVector);
@@ -653,11 +646,11 @@
 
             m_txTimer.Set(WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU,
                           timeout,
+                          staExpectResponseFrom,
                           &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
                           this,
                           &m_psduMap,
-                          &m_staExpectTbPpduFrom,
-                          m_staExpectTbPpduFrom.size());
+                          staExpectResponseFrom.size());
             m_channelAccessManager->NotifyAckTimeoutStartNow(timeout);
 
             ForwardPsduDown(triggerPsdu, acknowledgment->muBarTxVector);
@@ -675,18 +668,15 @@
      */
     else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
     {
-        WifiDlMuAggregateTf* acknowledgment =
-            static_cast<WifiDlMuAggregateTf*>(m_txParams.m_acknowledgment.get());
-
-        // record the set of stations expected to send a BlockAck frame
-        m_staExpectTbPpduFrom.clear();
+        auto acknowledgment = static_cast<WifiDlMuAggregateTf*>(m_txParams.m_acknowledgment.get());
 
         m_trigVector =
             acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
 
+        // record the set of stations expected to send a BlockAck frame
         for (auto& station : acknowledgment->stationsReplyingWithBlockAck)
         {
-            m_staExpectTbPpduFrom.insert(station.first);
+            staExpectResponseFrom.insert(station.first);
             // check that the station that is expected to send a BlockAck frame is
             // actually the receiver of a PSDU
             auto psduMapIt = std::find_if(m_psduMap.begin(),
@@ -725,15 +715,12 @@
         NS_ASSERT(IsTrigger(m_psduMap));
         mpdu = *m_psduMap.begin()->second->begin();
 
-        WifiUlMuMultiStaBa* acknowledgment =
-            static_cast<WifiUlMuMultiStaBa*>(m_txParams.m_acknowledgment.get());
+        auto acknowledgment = static_cast<WifiUlMuMultiStaBa*>(m_txParams.m_acknowledgment.get());
 
         // record the set of stations solicited by this Trigger Frame
-        m_staExpectTbPpduFrom.clear();
-
         for (const auto& station : acknowledgment->stationsReceivingMultiStaBa)
         {
-            m_staExpectTbPpduFrom.insert(station.first.first);
+            staExpectResponseFrom.insert(station.first.first);
         }
 
         // Reset stationsReceivingMultiStaBa, which will be filled as soon as
@@ -756,13 +743,11 @@
         NS_ASSERT(m_apMac);
 
         // record the set of stations solicited by this Trigger Frame
-        m_staExpectTbPpduFrom.clear();
-
         for (const auto& userInfo : trigger)
         {
             auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
             NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
-            m_staExpectTbPpduFrom.insert(staIt->second);
+            staExpectResponseFrom.insert(staIt->second);
         }
 
         timerType = WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF;
@@ -779,10 +764,10 @@
         NS_ASSERT(m_psduMap.size() == 1);
         timerType = WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU;
         NS_ASSERT(m_staMac && m_staMac->IsAssociated());
-        txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(
-            m_psduMap.begin()->second->GetAddr1(),
-            m_txParams.m_txVector);
+        auto recv = m_psduMap.begin()->second->GetAddr1();
+        txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(recv, m_txParams.m_txVector);
         responseTxVector = &txVector;
+        staExpectResponseFrom.insert(recv);
     }
     /*
      * QoS Null frames solicited by a BSRP Trigger Frame
@@ -827,7 +812,14 @@
 
     if (timerType == WifiTxTimer::NOT_RUNNING)
     {
-        if (!m_txParams.m_txVector.IsUlMu())
+        if (m_triggerFrame)
+        {
+            NS_LOG_DEBUG("Scheduling MU-BAR " << *m_triggerFrame);
+            Simulator::Schedule(txDuration + m_phy->GetSifs(),
+                                &HeFrameExchangeManager::SendPsduMap,
+                                this);
+        }
+        else if (!m_txParams.m_txVector.IsUlMu())
         {
             Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded, this);
         }
@@ -845,6 +837,7 @@
             NS_ASSERT(mpdu);
             m_txTimer.Set(timerType,
                           timeout,
+                          staExpectResponseFrom,
                           &HeFrameExchangeManager::NormalAckTimeout,
                           this,
                           mpdu,
@@ -854,6 +847,7 @@
             NS_ASSERT(psdu);
             m_txTimer.Set(timerType,
                           timeout,
+                          staExpectResponseFrom,
                           &HeFrameExchangeManager::BlockAckTimeout,
                           this,
                           psdu,
@@ -862,25 +856,26 @@
         case WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU:
             m_txTimer.Set(timerType,
                           timeout,
+                          staExpectResponseFrom,
                           &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
                           this,
                           &m_psduMap,
-                          &m_staExpectTbPpduFrom,
-                          m_staExpectTbPpduFrom.size());
+                          staExpectResponseFrom.size());
             break;
         case WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF:
         case WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF:
             m_txTimer.Set(timerType,
                           timeout,
+                          staExpectResponseFrom,
                           &HeFrameExchangeManager::TbPpduTimeout,
                           this,
                           &m_psduMap,
-                          &m_staExpectTbPpduFrom,
-                          m_staExpectTbPpduFrom.size());
+                          staExpectResponseFrom.size());
             break;
         case WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU:
             m_txTimer.Set(timerType,
                           timeout,
+                          staExpectResponseFrom,
                           &HeFrameExchangeManager::BlockAckAfterTbPpduTimeout,
                           this,
                           m_psduMap.begin()->second,
@@ -932,6 +927,8 @@
         FinalizeMacHeader(psdu);
         NotifyTxToEdca(psdu);
     }
+    m_allowedWidth = std::min(m_allowedWidth, txVector.GetChannelWidth());
+
     if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
         psduMap.begin()->second->IsSingle())
     {
@@ -1002,8 +999,7 @@
 
     if (protection->method == WifiProtection::MU_RTS_CTS)
     {
-        WifiMuRtsCtsProtection* muRtsCtsProtection =
-            static_cast<WifiMuRtsCtsProtection*>(protection);
+        auto muRtsCtsProtection = static_cast<WifiMuRtsCtsProtection*>(protection);
 
         // Get the TXVECTOR used by one station to send the CTS response. This is used
         // to compute the TX duration, so it does not matter which station we choose
@@ -1037,8 +1033,7 @@
      */
     if (acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
     {
-        WifiDlMuBarBaSequence* dlMuBarBaAcknowledgment =
-            static_cast<WifiDlMuBarBaSequence*>(acknowledgment);
+        auto dlMuBarBaAcknowledgment = static_cast<WifiDlMuBarBaSequence*>(acknowledgment);
 
         Time duration = Seconds(0);
 
@@ -1085,7 +1080,7 @@
      */
     else if (acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
     {
-        WifiDlMuTfMuBar* dlMuTfMuBarAcknowledgment = static_cast<WifiDlMuTfMuBar*>(acknowledgment);
+        auto dlMuTfMuBarAcknowledgment = static_cast<WifiDlMuTfMuBar*>(acknowledgment);
 
         Time duration = Seconds(0);
 
@@ -1131,8 +1126,7 @@
      */
     else if (acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
     {
-        WifiDlMuAggregateTf* dlMuAggrTfAcknowledgment =
-            static_cast<WifiDlMuAggregateTf*>(acknowledgment);
+        auto dlMuAggrTfAcknowledgment = static_cast<WifiDlMuAggregateTf*>(acknowledgment);
 
         Time duration = Seconds(0);
 
@@ -1166,7 +1160,7 @@
      */
     else if (acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
     {
-        WifiUlMuMultiStaBa* ulMuMultiStaBa = static_cast<WifiUlMuMultiStaBa*>(acknowledgment);
+        auto ulMuMultiStaBa = static_cast<WifiUlMuMultiStaBa*>(acknowledgment);
 
         Time duration = m_phy->CalculateTxDuration(GetBlockAckSize(ulMuMultiStaBa->baType),
                                                    ulMuMultiStaBa->multiStaBaTxVector,
@@ -1250,8 +1244,7 @@
         txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
     {
         // we need to account for the size of the aggregated MU-BAR Trigger Frame
-        WifiDlMuAggregateTf* acknowledgment =
-            static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
+        auto acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
 
         const auto& info = acknowledgment->stationsReplyingWithBlockAck.find(receiver);
         NS_ASSERT(info != acknowledgment->stationsReplyingWithBlockAck.end());
@@ -1271,20 +1264,19 @@
 }
 
 void
-HeFrameExchangeManager::TbPpduTimeout(WifiPsduMap* psduMap,
-                                      const std::set<Mac48Address>* staMissedTbPpduFrom,
-                                      std::size_t nSolicitedStations)
+HeFrameExchangeManager::TbPpduTimeout(WifiPsduMap* psduMap, std::size_t nSolicitedStations)
 {
-    NS_LOG_FUNCTION(this << psduMap << staMissedTbPpduFrom->size() << nSolicitedStations);
+    const auto& staMissedTbPpduFrom = m_txTimer.GetStasExpectedToRespond();
+    NS_LOG_FUNCTION(this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations);
 
     NS_ASSERT(psduMap);
     NS_ASSERT(IsTrigger(*psduMap));
 
     // This method is called if some station(s) did not send a TB PPDU
-    NS_ASSERT(!staMissedTbPpduFrom->empty());
+    NS_ASSERT(!staMissedTbPpduFrom.empty());
     NS_ASSERT(m_edca);
 
-    if (staMissedTbPpduFrom->size() == nSolicitedStations)
+    if (staMissedTbPpduFrom.size() == nSolicitedStations)
     {
         // no station replied, the transmission failed
         m_edca->UpdateFailedCw(m_linkId);
@@ -1301,10 +1293,8 @@
 }
 
 void
-HeFrameExchangeManager::BlockAcksInTbPpduTimeout(
-    WifiPsduMap* psduMap,
-    const std::set<Mac48Address>* staMissedBlockAckFrom,
-    std::size_t nSolicitedStations)
+HeFrameExchangeManager::BlockAcksInTbPpduTimeout(WifiPsduMap* psduMap,
+                                                 std::size_t nSolicitedStations)
 {
     NS_LOG_FUNCTION(this << psduMap << nSolicitedStations);
 
@@ -1314,11 +1304,12 @@
                m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
 
     // This method is called if some station(s) did not send a BlockAck frame in a TB PPDU
-    NS_ASSERT(!staMissedBlockAckFrom->empty());
+    const auto& staMissedBlockAckFrom = m_txTimer.GetStasExpectedToRespond();
+    NS_ASSERT(!staMissedBlockAckFrom.empty());
 
     bool resetCw;
 
-    if (staMissedBlockAckFrom->size() == nSolicitedStations)
+    if (staMissedBlockAckFrom.size() == nSolicitedStations)
     {
         // no station replied, the transmission failed
         // call ReportDataFailed to increase SRC/LRC
@@ -1334,11 +1325,10 @@
     if (m_triggerFrame)
     {
         // this is strictly needed for DL_MU_TF_MU_BAR only
-        DequeueMpdu(m_triggerFrame);
         m_triggerFrame = nullptr;
     }
 
-    for (const auto& sta : *staMissedBlockAckFrom)
+    for (const auto& sta : staMissedBlockAckFrom)
     {
         Ptr<WifiPsdu> psdu = GetPsduTo(sta, *psduMap);
         NS_ASSERT(psdu);
@@ -1362,7 +1352,7 @@
         m_edca->UpdateFailedCw(m_linkId);
     }
 
-    if (staMissedBlockAckFrom->size() == nSolicitedStations)
+    if (staMissedBlockAckFrom.size() == nSolicitedStations)
     {
         // no station replied, the transmission failed
         TransmissionFailed();
@@ -1508,7 +1498,7 @@
         trigger.GetApTxPower() -
         static_cast<int8_t>(
             *optRssi); // cast RSSI to be on equal footing with AP Tx power information
-    double reqTxPowerDbm = static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb);
+    auto reqTxPowerDbm = static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb);
 
     // Convert the transmit power to a power level
     uint8_t numPowerLevels = m_phy->GetNTxPower();
@@ -1561,7 +1551,7 @@
         NS_ASSERT(itAidAddr != staList.end());
         auto optRssi = GetMostRecentRssi(itAidAddr->second);
         NS_ASSERT(optRssi);
-        int8_t rssi = static_cast<int8_t>(*optRssi);
+        auto rssi = static_cast<int8_t>(*optRssi);
         rssi = (rssi >= -20)
                    ? -20
                    : ((rssi <= -110) ? -110 : rssi); // cap so as to keep within [-110; -20] dBm
@@ -1642,8 +1632,7 @@
     NS_ASSERT(m_apMac);
     NS_ASSERT(txParams.m_acknowledgment &&
               txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
-    WifiUlMuMultiStaBa* acknowledgment =
-        static_cast<WifiUlMuMultiStaBa*>(txParams.m_acknowledgment.get());
+    auto acknowledgment = static_cast<WifiUlMuMultiStaBa*>(txParams.m_acknowledgment.get());
 
     NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
 
@@ -2203,11 +2192,10 @@
         Mac48Address sender = hdr.GetAddr2();
         NS_ASSERT(m_txParams.m_acknowledgment &&
                   m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
-        WifiUlMuMultiStaBa* acknowledgment =
-            static_cast<WifiUlMuMultiStaBa*>(m_txParams.m_acknowledgment.get());
+        auto acknowledgment = static_cast<WifiUlMuMultiStaBa*>(m_txParams.m_acknowledgment.get());
         std::size_t index = acknowledgment->baType.m_bitmapLen.size();
 
-        if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
+        if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
         {
             NS_LOG_WARN("Received a TB PPDU from an unexpected station: " << sender);
             return;
@@ -2268,9 +2256,9 @@
         }
 
         // remove the sender from the set of stations that are expected to send a TB PPDU
-        m_staExpectTbPpduFrom.erase(sender);
+        m_txTimer.GotResponseFrom(sender);
 
-        if (m_staExpectTbPpduFrom.empty())
+        if (m_txTimer.GetStasExpectedToRespond().empty())
         {
             // we do not expect any other BlockAck frame
             m_txTimer.Cancel();
@@ -2296,7 +2284,7 @@
     {
         const auto& sender = hdr.GetAddr2();
 
-        if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
+        if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
         {
             NS_LOG_WARN("Received a TB PPDU from an unexpected station: " << sender);
             return;
@@ -2310,9 +2298,9 @@
         NS_LOG_DEBUG("Received a QoS Null frame in a TB PPDU from " << sender);
 
         // remove the sender from the set of stations that are expected to send a TB PPDU
-        m_staExpectTbPpduFrom.erase(sender);
+        m_txTimer.GotResponseFrom(sender);
 
-        if (m_staExpectTbPpduFrom.empty())
+        if (m_txTimer.GetStasExpectedToRespond().empty())
         {
             // we do not expect any other response
             m_txTimer.Cancel();
@@ -2375,7 +2363,7 @@
             NS_ASSERT(m_txParams.m_acknowledgment->method ==
                       WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
 
-            WifiDlMuBarBaSequence* acknowledgment =
+            auto acknowledgment =
                 static_cast<WifiDlMuBarBaSequence*>(m_txParams.m_acknowledgment.get());
             NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
             NS_ASSERT(m_apMac);
@@ -2427,13 +2415,15 @@
                                                                m_txParams.m_txVector);
 
             // remove the sender from the set of stations that are expected to send a BlockAck
-            if (m_staExpectTbPpduFrom.erase(sender) == 0)
+            if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
             {
                 NS_LOG_WARN("Received a BlockAck from an unexpected stations: " << sender);
                 return;
             }
 
-            if (m_staExpectTbPpduFrom.empty())
+            m_txTimer.GotResponseFrom(sender);
+
+            if (m_txTimer.GetStasExpectedToRespond().empty())
             {
                 // we do not expect any other BlockAck frame
                 m_txTimer.Cancel();
@@ -2441,7 +2431,6 @@
                 if (m_triggerFrame)
                 {
                     // this is strictly needed for DL_MU_TF_MU_BAR only
-                    DequeueMpdu(m_triggerFrame);
                     m_triggerFrame = nullptr;
                 }
 
@@ -2676,11 +2665,10 @@
         Mac48Address sender = psdu->GetAddr2();
         NS_ASSERT(m_txParams.m_acknowledgment &&
                   m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
-        WifiUlMuMultiStaBa* acknowledgment =
-            static_cast<WifiUlMuMultiStaBa*>(m_txParams.m_acknowledgment.get());
+        auto acknowledgment = static_cast<WifiUlMuMultiStaBa*>(m_txParams.m_acknowledgment.get());
         std::size_t index = acknowledgment->baType.m_bitmapLen.size();
 
-        if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
+        if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
         {
             NS_LOG_WARN("Received a TB PPDU from an unexpected station: " << sender);
             return;
@@ -2726,9 +2714,9 @@
         }
 
         // remove the sender from the set of stations that are expected to send a TB PPDU
-        m_staExpectTbPpduFrom.erase(sender);
+        m_txTimer.GotResponseFrom(sender);
 
-        if (m_staExpectTbPpduFrom.empty())
+        if (m_txTimer.GetStasExpectedToRespond().empty())
         {
             // we do not expect any other BlockAck frame
             m_txTimer.Cancel();
@@ -2753,7 +2741,7 @@
     {
         Mac48Address sender = psdu->GetAddr2();
 
-        if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
+        if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
         {
             NS_LOG_WARN("Received a TB PPDU from an unexpected station: " << sender);
             return;
@@ -2769,9 +2757,9 @@
         NS_LOG_DEBUG("Received QoS Null frames in a TB PPDU from " << sender);
 
         // remove the sender from the set of stations that are expected to send a TB PPDU
-        m_staExpectTbPpduFrom.erase(sender);
+        m_txTimer.GotResponseFrom(sender);
 
-        if (m_staExpectTbPpduFrom.empty())
+        if (m_txTimer.GetStasExpectedToRespond().empty())
         {
             // we do not expect any other response
             m_txTimer.Cancel();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/he/he-frame-exchange-manager.h ns-3.40/src/wifi/model/he/he-frame-exchange-manager.h
--- ns-3.39/src/wifi/model/he/he-frame-exchange-manager.h	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/he/he-frame-exchange-manager.h	2023-09-27 13:30:37.906839800 -0700
@@ -78,7 +78,6 @@
     uint16_t GetSupportedBaBufferSize() const override;
     bool StartFrameExchange(Ptr<QosTxop> edca, Time availableTime, bool initialFrame) override;
     void SetWifiMac(const Ptr<WifiMac> mac) override;
-    void SetWifiPhy(const Ptr<WifiPhy> phy) override;
     void CalculateAcknowledgmentTime(WifiAcknowledgment* acknowledgment) const override;
     void CalculateProtectionTime(WifiProtection* protection) const override;
     void SetTxopHolder(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) override;
@@ -144,7 +143,7 @@
   protected:
     void DoDispose() override;
     void Reset() override;
-
+    void RxStartIndication(WifiTxVector txVector, Time psduDuration) override;
     void ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
                      RxSignalInfo rxSignalInfo,
                      const WifiTxVector& txVector,
@@ -157,7 +156,6 @@
     Time GetTxDuration(uint32_t ppduPayloadSize,
                        Mac48Address receiver,
                        const WifiTxParameters& txParams) const override;
-    bool SendMpduFromBaManager(Ptr<WifiMpdu> mpdu, Time availableTime, bool initialFrame) override;
     void NormalAckTimeout(Ptr<WifiMpdu> mpdu, const WifiTxVector& txVector) override;
     void BlockAckTimeout(Ptr<WifiPsdu> psdu, const WifiTxVector& txVector) override;
     void CtsTimeout(Ptr<WifiMpdu> rts, const WifiTxVector& txVector) override;
@@ -165,6 +163,7 @@
     void NavResetTimeout() override;
     void StartProtection(const WifiTxParameters& txParams) override;
     void ProtectionCompleted() override;
+    void TransmissionSucceeded() override;
 
     /**
      * Clear the TXOP holder if the intra-BSS NAV counted down to zero (includes the case
@@ -264,12 +263,9 @@
      * expected BlockAck frames were received.
      *
      * \param psduMap a pointer to PSDU map transmitted in a DL MU PPDU
-     * \param staMissedBlockAckFrom set of stations we missed a BlockAck frame from
      * \param nSolicitedStations the number of stations solicited to send a TB PPDU
      */
-    virtual void BlockAcksInTbPpduTimeout(WifiPsduMap* psduMap,
-                                          const std::set<Mac48Address>* staMissedBlockAckFrom,
-                                          std::size_t nSolicitedStations);
+    virtual void BlockAcksInTbPpduTimeout(WifiPsduMap* psduMap, std::size_t nSolicitedStations);
 
     /**
      * Take the necessary actions after that some TB PPDUs are missing in
@@ -277,12 +273,9 @@
      * expected TB PPDUs were received.
      *
      * \param psduMap a pointer to PSDU map transmitted in a DL MU PPDU
-     * \param staMissedTbPpduFrom set of stations we missed a TB PPDU from
      * \param nSolicitedStations the number of stations solicited to send a TB PPDU
      */
-    virtual void TbPpduTimeout(WifiPsduMap* psduMap,
-                               const std::set<Mac48Address>* staMissedTbPpduFrom,
-                               std::size_t nSolicitedStations);
+    virtual void TbPpduTimeout(WifiPsduMap* psduMap, std::size_t nSolicitedStations);
 
     /**
      * Take the necessary actions after that a Block Ack is missing after a
@@ -381,14 +374,13 @@
                              Time durationId,
                              double snr);
 
-    WifiPsduMap m_psduMap;                        //!< the A-MPDU being transmitted
-    WifiTxParameters m_txParams;                  //!< the TX parameters for the current PPDU
-    Ptr<MultiUserScheduler> m_muScheduler;        //!< Multi-user Scheduler (HE APs only)
-    Ptr<WifiMpdu> m_triggerFrame;                 //!< Trigger Frame being sent
-    std::set<Mac48Address> m_staExpectTbPpduFrom; //!< set of stations expected to send a TB PPDU
-    EventId m_multiStaBaEvent;                    //!< Sending a Multi-STA BlockAck event
-    MuSnrTag m_muSnrTag;                          //!< Tag to attach to Multi-STA BlockAck frames
-    bool m_triggerFrameInAmpdu; //!< True if the received A-MPDU contains an MU-BAR
+    WifiPsduMap m_psduMap;                 //!< the A-MPDU being transmitted
+    WifiTxParameters m_txParams;           //!< the TX parameters for the current PPDU
+    Ptr<MultiUserScheduler> m_muScheduler; //!< Multi-user Scheduler (HE APs only)
+    Ptr<WifiMpdu> m_triggerFrame;          //!< Trigger Frame being sent
+    EventId m_multiStaBaEvent;             //!< Sending a Multi-STA BlockAck event
+    MuSnrTag m_muSnrTag;                   //!< Tag to attach to Multi-STA BlockAck frames
+    bool m_triggerFrameInAmpdu;            //!< True if the received A-MPDU contains an MU-BAR
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/he/he-phy.cc ns-3.40/src/wifi/model/he/he-phy.cc
--- ns-3.39/src/wifi/model/he/he-phy.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/he/he-phy.cc	2023-09-27 13:30:37.906839800 -0700
@@ -225,7 +225,9 @@
         return HePpdu::GetSigBFieldSize(
             txVector.GetChannelWidth(),
             txVector.GetRuAllocation(
-                m_wifiPhy ? m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(20) : 0));
+                m_wifiPhy ? m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(20) : 0),
+            txVector.IsSigBCompression(),
+            txVector.IsSigBCompression() ? txVector.GetHeMuUserInfoMap().size() : 0);
     }
     return 0;
 }
@@ -297,7 +299,7 @@
 }
 
 Time
-HePhy::CalculateNonOfdmaDurationForHeTb(const WifiTxVector& txVector) const
+HePhy::CalculateNonHeDurationForHeTb(const WifiTxVector& txVector) const
 {
     Time duration = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, txVector) +
                     GetDuration(WIFI_PPDU_FIELD_NON_HT_HEADER, txVector) +
@@ -306,7 +308,7 @@
 }
 
 Time
-HePhy::CalculateNonOfdmaDurationForHeMu(const WifiTxVector& txVector) const
+HePhy::CalculateNonHeDurationForHeMu(const WifiTxVector& txVector) const
 {
     Time duration = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, txVector) +
                     GetDuration(WIFI_PPDU_FIELD_NON_HT_HEADER, txVector) +
@@ -371,35 +373,35 @@
         NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
         if (m_currentMuPpduUid == ppdu->GetUid() && GetCurrentEvent())
         {
-            // AP or STA has already received non-OFDMA part, switch to OFDMA part, and schedule
+            // AP or STA has already received non-HE portion, switch to HE portion, and schedule
             // reception of payload (will be canceled for STAs by StartPayload)
-            bool ofdmaStarted = !m_beginOfdmaPayloadRxEvents.empty();
-            NS_LOG_INFO("Switch to OFDMA part (already started? "
-                        << (ofdmaStarted ? "Y" : "N") << ") "
-                        << "and schedule OFDMA payload reception in "
+            bool hePortionStarted = !m_beginMuPayloadRxEvents.empty();
+            NS_LOG_INFO("Switch to HE portion (already started? "
+                        << (hePortionStarted ? "Y" : "N") << ") "
+                        << "and schedule payload reception in "
                         << GetDuration(WIFI_PPDU_FIELD_TRAINING, txVector).As(Time::NS));
-            auto event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW, !ofdmaStarted);
+            auto event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW, !hePortionStarted);
             uint16_t staId = GetStaId(ppdu);
-            NS_ASSERT(m_beginOfdmaPayloadRxEvents.find(staId) == m_beginOfdmaPayloadRxEvents.end());
-            m_beginOfdmaPayloadRxEvents[staId] =
+            NS_ASSERT(m_beginMuPayloadRxEvents.find(staId) == m_beginMuPayloadRxEvents.end());
+            m_beginMuPayloadRxEvents[staId] =
                 Simulator::Schedule(GetDuration(WIFI_PPDU_FIELD_TRAINING, txVector),
-                                    &HePhy::StartReceiveOfdmaPayload,
+                                    &HePhy::StartReceiveMuPayload,
                                     this,
                                     event);
         }
         else
         {
-            // PHY receives the OFDMA payload while having dropped the preamble
-            NS_LOG_INFO("Consider OFDMA part of the PPDU as interference since device dropped the "
+            // PHY receives the HE portion while having dropped the preamble
+            NS_LOG_INFO("Consider HE portion of the PPDU as interference since device dropped the "
                         "preamble");
             CreateInterferenceEvent(ppdu, rxDuration, rxPowersW);
-            // the OFDMA part of the PPDU will be noise _after_ the completion of the current event
+            // the HE portion of the PPDU will be noise _after_ the completion of the current event
             ErasePreambleEvent(ppdu, rxDuration);
         }
     }
     else
     {
-        PhyEntity::StartReceivePreamble(
+        VhtPhy::StartReceivePreamble(
             ppdu,
             rxPowersW,
             ppdu->GetTxDuration()); // The actual duration of the PPDU should be used
@@ -410,12 +412,12 @@
 HePhy::CancelAllEvents()
 {
     NS_LOG_FUNCTION(this);
-    for (auto& beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
+    for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
     {
-        beginOfdmaPayloadRxEvent.second.Cancel();
+        beginMuPayloadRxEvent.second.Cancel();
     }
-    m_beginOfdmaPayloadRxEvents.clear();
-    PhyEntity::CancelAllEvents();
+    m_beginMuPayloadRxEvents.clear();
+    VhtPhy::CancelAllEvents();
 }
 
 void
@@ -432,7 +434,7 @@
     }
     else
     {
-        PhyEntity::DoAbortCurrentReception(reason);
+        VhtPhy::DoAbortCurrentReception(reason);
     }
 }
 
@@ -444,11 +446,11 @@
     {
         NS_ASSERT(event->GetEndTime() == Simulator::Now());
     }
-    for (auto& beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
+    for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
     {
-        beginOfdmaPayloadRxEvent.second.Cancel();
+        beginMuPayloadRxEvent.second.Cancel();
     }
-    m_beginOfdmaPayloadRxEvents.clear();
+    m_beginMuPayloadRxEvents.clear();
 }
 
 Ptr<Event>
@@ -462,14 +464,14 @@
     const auto uidPreamblePair = std::make_pair(ppdu->GetUid(), ppdu->GetPreamble());
     const auto& currentPreambleEvents = GetCurrentPreambleEvents();
     const auto it = currentPreambleEvents.find(uidPreamblePair);
-    const auto isResponseToTrigger = (m_previouslyTxPpduUid == ppdu->GetUid());
-    if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU || isResponseToTrigger)
+    if (const auto isResponseToTrigger = (m_previouslyTxPpduUid == ppdu->GetUid());
+        ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU || isResponseToTrigger)
     {
         const auto& txVector = ppdu->GetTxVector();
         const auto rxDuration =
             (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
-                ? CalculateNonOfdmaDurationForHeTb(
-                      txVector) // the OFDMA part of the transmission will be added later on
+                ? CalculateNonHeDurationForHeTb(
+                      txVector) // the HE portion of the transmission will be added later on
                 : ppdu->GetTxDuration();
         if (it != currentPreambleEvents.cend())
         {
@@ -484,34 +486,7 @@
                 NS_LOG_DEBUG("Received another response to a trigger frame " << ppdu->GetUid());
             }
             event = it->second;
-
-            if (Simulator::Now() - event->GetStartTime() > GetMaxDelayPpduSameUid(txVector))
-            {
-                // This HE TB PPDU arrived too late to be decoded properly. The HE TB PPDU
-                // is dropped and added as interference
-                event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW);
-                NS_LOG_DEBUG("Drop HE TB PPDU that arrived too late");
-                m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(ppdu), PPDU_TOO_LATE);
-            }
-            else
-            {
-                // Update received power of the event associated to that UL MU transmission
-                UpdateInterferenceEvent(event, rxPowersW);
-            }
-
-            if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU && GetCurrentEvent() &&
-                (GetCurrentEvent()->GetPpdu()->GetUid() != ppdu->GetUid()))
-            {
-                NS_LOG_DEBUG("Drop packet because already receiving another HE TB PPDU");
-                m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(ppdu), RXING);
-            }
-            else if (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);
-            }
+            HandleRxPpduWithSameContent(event, ppdu, rxPowersW);
             return nullptr;
         }
         else
@@ -533,18 +508,40 @@
     else if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
     {
         const auto& txVector = ppdu->GetTxVector();
-        Time rxDuration = CalculateNonOfdmaDurationForHeMu(
-            txVector); // the OFDMA part of the transmission will be added later on
+        Time rxDuration = CalculateNonHeDurationForHeMu(
+            txVector); // the HE portion of the transmission will be added later on
         event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW);
         AddPreambleEvent(event);
     }
     else
     {
-        event = PhyEntity::DoGetEvent(ppdu, rxPowersW);
+        event = VhtPhy::DoGetEvent(ppdu, rxPowersW);
     }
     return event;
 }
 
+void
+HePhy::HandleRxPpduWithSameContent(Ptr<Event> event,
+                                   Ptr<const WifiPpdu> ppdu,
+                                   RxPowerWattPerChannelBand& rxPower)
+{
+    VhtPhy::HandleRxPpduWithSameContent(event, ppdu, rxPower);
+
+    if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU && GetCurrentEvent() &&
+        (GetCurrentEvent()->GetPpdu()->GetUid() != ppdu->GetUid()))
+    {
+        NS_LOG_DEBUG("Drop packet because already receiving another HE TB PPDU");
+        m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(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);
+    }
+}
+
 Ptr<const WifiPsdu>
 HePhy::GetAddressedPsduInPpdu(Ptr<const WifiPpdu> ppdu) const
 {
@@ -554,7 +551,7 @@
         NS_ASSERT(hePpdu);
         return hePpdu->GetPsdu(GetBssColor(), GetStaId(ppdu));
     }
-    return PhyEntity::GetAddressedPsduInPpdu(ppdu);
+    return VhtPhy::GetAddressedPsduInPpdu(ppdu);
 }
 
 uint8_t
@@ -587,14 +584,14 @@
             return mac->GetAssociationId();
         }
     }
-    return PhyEntity::GetStaId(ppdu);
+    return VhtPhy::GetStaId(ppdu);
 }
 
 PhyEntity::PhyFieldRxStatus
 HePhy::ProcessSig(Ptr<Event> event, PhyFieldRxStatus status, WifiPpduField field)
 {
     NS_LOG_FUNCTION(this << *event << status << field);
-    NS_ASSERT(event->GetTxVector().GetPreambleType() >= WIFI_PREAMBLE_HE_SU);
+    NS_ASSERT(event->GetPpdu()->GetTxVector().GetPreambleType() >= WIFI_PREAMBLE_HE_SU);
     switch (field)
     {
     case WIFI_PPDU_FIELD_SIG_A:
@@ -612,7 +609,7 @@
 {
     NS_LOG_FUNCTION(this << *event << status);
     // Notify end of SIG-A (in all cases)
-    WifiTxVector txVector = event->GetTxVector();
+    const auto& txVector = event->GetPpdu()->GetTxVector();
     HeSigAParameters params;
     params.rssiW = GetRxPowerWForPpdu(event);
     params.bssColor = txVector.GetBssColor();
@@ -685,7 +682,7 @@
             NS_ASSERT(txVector.GetHeMuUserInfo(staId) == m_trigVector->GetHeMuUserInfo(staId));
 
             m_currentMuPpduUid =
-                ppdu->GetUid(); // to be able to correctly schedule start of OFDMA payload
+                ppdu->GetUid(); // to be able to correctly schedule start of MU payload
         }
 
         if (ppdu->GetType() != WIFI_PPDU_TYPE_DL_MU &&
@@ -726,7 +723,7 @@
 HePhy::ProcessSigB(Ptr<Event> event, PhyFieldRxStatus status)
 {
     NS_LOG_FUNCTION(this << *event << status);
-    NS_ASSERT(IsDlMu(event->GetTxVector().GetPreambleType()));
+    NS_ASSERT(IsDlMu(event->GetPpdu()->GetTxVector().GetPreambleType()));
     if (status.isSuccess)
     {
         // Check if PPDU is filtered only if the SIG-B content is supported (not explicitly stated
@@ -738,18 +735,9 @@
             return PhyFieldRxStatus(false, FILTERED, DROP);
         }
     }
-    if (event->GetTxVector().IsDlMu())
-    {
-        // When including a Trigger Frame, a DL MU PPDU solicits a TB PPDU.
-        // NOTE that the 'if' condition above is not needed for HE because SIG-B is only
-        // included in HE MU PPDUs, but it is necessary for EHT to avoid that a non-AP
-        // STA receiving a Trigger Frame sent as an EHT SU transmission (which carries
-        // the EHT-SIG field) stores the PPDU UID and uses it later to schedule the
-        // reception of the OFDMA payload of the TB PPDU (see HePhy::StartReceivePreamble())
-        // despite it lacks the TRIGVECTOR.
-        m_currentMuPpduUid =
-            event->GetPpdu()->GetUid(); // to be able to correctly schedule start of OFDMA payload
-    }
+    m_currentMuPpduUid =
+        event->GetPpdu()->GetUid(); // to be able to correctly schedule start of MU payload
+
     return status;
 }
 
@@ -761,7 +749,7 @@
         return true; // evaluated in ProcessSigA
     }
 
-    const WifiTxVector& txVector = ppdu->GetTxVector();
+    const auto& txVector = ppdu->GetTxVector();
     uint16_t staId = GetStaId(ppdu);
     WifiMode txMode = txVector.GetMode(staId);
     uint8_t nss = txVector.GetNssMax();
@@ -796,15 +784,15 @@
 HePhy::DoStartReceivePayload(Ptr<Event> event)
 {
     NS_LOG_FUNCTION(this << *event);
-    const auto& txVector = event->GetTxVector();
+    const auto ppdu = event->GetPpdu();
+    const auto& txVector = ppdu->GetTxVector();
 
     if (!txVector.IsMu())
     {
-        return PhyEntity::DoStartReceivePayload(event);
+        return VhtPhy::DoStartReceivePayload(event);
     }
 
     NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
-    Ptr<const WifiPpdu> ppdu = event->GetPpdu();
 
     if (txVector.IsDlMu())
     {
@@ -819,13 +807,13 @@
                                                                txVector,
                                                                m_wifiPhy->GetPhyBand()) -
                            CalculatePhyPreambleAndHeaderDuration(txVector);
-    // This method is called when we start receiving the first OFDMA payload. To
+    // This method is called when we start receiving the first MU payload. To
     // compute the time to the reception end of the last TB PPDU, we need to add the
     // offset of the last TB PPDU to the payload duration (same for all TB PPDUs)
     Time maxOffset{0};
-    for (const auto& beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
+    for (const auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
     {
-        maxOffset = Max(maxOffset, Simulator::GetDelayLeft(beginOfdmaPayloadRxEvent.second));
+        maxOffset = Max(maxOffset, Simulator::GetDelayLeft(beginMuPayloadRxEvent.second));
     }
     Time timeToEndRx = payloadDuration + maxOffset;
 
@@ -834,15 +822,15 @@
         NS_LOG_DEBUG("Ignore HE TB PPDU payload received by STA but keep state in Rx");
         NotifyPayloadBegin(txVector, timeToEndRx);
         m_endRxPayloadEvents.push_back(
-            Simulator::Schedule(timeToEndRx, &PhyEntity::ResetReceive, this, event));
-        // Cancel all scheduled events for OFDMA payload reception
-        NS_ASSERT(!m_beginOfdmaPayloadRxEvents.empty() &&
-                  m_beginOfdmaPayloadRxEvents.begin()->second.IsRunning());
-        for (auto& beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
+            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());
+        for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
         {
-            beginOfdmaPayloadRxEvent.second.Cancel();
+            beginMuPayloadRxEvent.second.Cancel();
         }
-        m_beginOfdmaPayloadRxEvents.clear();
+        m_beginMuPayloadRxEvents.clear();
     }
     else
     {
@@ -851,11 +839,11 @@
         m_signalNoiseMap.insert({std::make_pair(ppdu->GetUid(), staId), SignalNoiseDbm()});
         m_statusPerMpduMap.insert({std::make_pair(ppdu->GetUid(), staId), std::vector<bool>()});
         // for HE TB PPDUs, ScheduleEndOfMpdus and EndReceive are scheduled by
-        // StartReceiveOfdmaPayload
-        NS_ASSERT(!m_beginOfdmaPayloadRxEvents.empty());
-        for (auto& beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
+        // StartReceiveMuPayload
+        NS_ASSERT(!m_beginMuPayloadRxEvents.empty());
+        for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
         {
-            NS_ASSERT(beginOfdmaPayloadRxEvent.second.IsRunning());
+            NS_ASSERT(beginMuPayloadRxEvent.second.IsRunning());
         }
     }
 
@@ -911,7 +899,7 @@
         }
         if (m_endRxPayloadEvents.empty())
         {
-            // We've got the last PPDU of the UL-OFDMA transmission.
+            // We've got the last PPDU of the UL-MU transmission.
             // Indicate a successful reception is terminated if at least one HE TB PPDU
             // has been successfully received, otherwise indicate a unsuccessful reception is
             // terminated.
@@ -930,12 +918,14 @@
     else
     {
         NS_ASSERT(m_wifiPhy->GetLastRxEndTime() == Simulator::Now());
-        PhyEntity::DoEndReceivePayload(ppdu);
+        VhtPhy::DoEndReceivePayload(ppdu);
     }
+    // we are done receiving the payload, we can reset the current MU PPDU UID
+    m_currentMuPpduUid = UINT64_MAX;
 }
 
 void
-HePhy::StartReceiveOfdmaPayload(Ptr<Event> event)
+HePhy::StartReceiveMuPayload(Ptr<Event> event)
 {
     NS_LOG_FUNCTION(this << event);
     Ptr<const WifiPpdu> ppdu = event->GetPpdu();
@@ -952,22 +942,22 @@
     NS_LOG_FUNCTION(this << *event << it->second);
     NS_ASSERT(GetCurrentEvent());
     NS_ASSERT(m_rxHeTbPpdus == 0);
-    auto itEvent = m_beginOfdmaPayloadRxEvents.find(GetStaId(ppdu));
+    auto itEvent = m_beginMuPayloadRxEvents.find(GetStaId(ppdu));
     /**
-     * m_beginOfdmaPayloadRxEvents should still be running only for APs, since canceled in
+     * m_beginMuPayloadRxEvents should still be running only for APs, since canceled in
      * StartReceivePayload for STAs. This is because SpectrumWifiPhy does not have access to the
      * device type and thus blindly schedules things, letting the parent WifiPhy class take into
      * account device type.
      */
-    NS_ASSERT(itEvent != m_beginOfdmaPayloadRxEvents.end() && itEvent->second.IsExpired());
-    m_beginOfdmaPayloadRxEvents.erase(itEvent);
+    NS_ASSERT(itEvent != m_beginMuPayloadRxEvents.end() && itEvent->second.IsExpired());
+    m_beginMuPayloadRxEvents.erase(itEvent);
 
     Time payloadDuration =
         ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(ppdu->GetTxVector());
     Ptr<const WifiPsdu> psdu = GetAddressedPsduInPpdu(ppdu);
     ScheduleEndOfMpdus(event);
     m_endRxPayloadEvents.push_back(
-        Simulator::Schedule(payloadDuration, &PhyEntity::EndReceivePayload, this, event));
+        Simulator::Schedule(payloadDuration, &HePhy::EndReceivePayload, this, event));
     uint16_t staId = GetStaId(ppdu);
     m_signalNoiseMap.insert({std::make_pair(ppdu->GetUid(), staId), SignalNoiseDbm()});
     m_statusPerMpduMap.insert({std::make_pair(ppdu->GetUid(), staId), std::vector<bool>()});
@@ -985,7 +975,7 @@
     }
     else
     {
-        return PhyEntity::GetChannelWidthAndBand(txVector, staId);
+        return VhtPhy::GetChannelWidthAndBand(txVector, staId);
     }
 }
 
@@ -1307,10 +1297,10 @@
     auto heConfiguration = m_wifiPhy->GetDevice()->GetHeConfiguration();
     NS_ASSERT(heConfiguration);
     // DoStartReceivePayload(), which is called when we start receiving the Data field,
-    // computes the max offset among TB PPDUs based on the begin OFDMA payload RX events,
+    // computes the max offset among TB PPDUs based on the begin MU payload RX events,
     // which are scheduled by StartReceivePreamble() when starting the reception of the
-    // OFDMA portion. Therefore, the maximum delay cannot exceed the duration of the
-    // training fields that are between the start of the OFDMA portion and the start
+    // HE portion. Therefore, the maximum delay cannot exceed the duration of the
+    // training fields that are between the start of the HE portion and the start
     // of the Data field.
     auto maxDelay = GetDuration(WIFI_PPDU_FIELD_TRAINING, txVector);
     if (heConfiguration->GetMaxTbPpduDelay().IsStrictlyPositive())
@@ -1354,9 +1344,9 @@
     case WIFI_PPDU_TYPE_UL_MU: {
         if (flag == HePpdu::PSD_NON_HE_PORTION)
         {
-            // non-OFDMA portion is sent only on the 20 MHz channels covering the RU
+            // non-HE portion is sent only on the 20 MHz channels covering the RU
             const uint16_t staId = GetStaId(ppdu);
-            centerFrequency = GetCenterFrequencyForNonOfdmaPart(txVector, staId);
+            centerFrequency = GetCenterFrequencyForNonHePart(txVector, staId);
             const uint16_t ruWidth = HeRu::GetBandwidth(txVector.GetRu(staId).GetRuType());
             channelWidth = (ruWidth < 20) ? 20 : ruWidth;
             return WifiSpectrumValueHelper::CreateDuplicated20MhzTxPowerSpectralDensity(
@@ -1422,7 +1412,7 @@
 }
 
 uint16_t
-HePhy::GetCenterFrequencyForNonOfdmaPart(const WifiTxVector& txVector, uint16_t staId) const
+HePhy::GetCenterFrequencyForNonHePart(const WifiTxVector& txVector, uint16_t staId) const
 {
     NS_LOG_FUNCTION(this << txVector << staId);
     NS_ASSERT(txVector.IsUlMu() && (txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE));
@@ -1460,58 +1450,57 @@
     }
     if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU || ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
     {
-        auto nonOfdmaTxPowerDbm =
-            m_wifiPhy->GetTxPowerForTransmission(ppdu) + m_wifiPhy->GetTxGain();
+        auto nonHeTxPowerDbm = m_wifiPhy->GetTxPowerForTransmission(ppdu) + m_wifiPhy->GetTxGain();
 
-        // temporarily set WifiPpdu flag to PSD_HE_PORTION for correct calculation of the OFDMA TX
-        // power
+        // temporarily set WifiPpdu flag to PSD_HE_PORTION for correct calculation of TX power for
+        // the HE portion
         auto hePpdu = DynamicCast<const HePpdu>(ppdu);
         NS_ASSERT(hePpdu);
         hePpdu->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
-        auto ofdmaTxPowerDbm = m_wifiPhy->GetTxPowerForTransmission(ppdu) + m_wifiPhy->GetTxGain();
+        auto heTxPowerDbm = m_wifiPhy->GetTxPowerForTransmission(ppdu) + m_wifiPhy->GetTxGain();
         hePpdu->SetTxPsdFlag(HePpdu::PSD_NON_HE_PORTION);
 
-        // non-OFDMA part
-        auto nonOfdmaDuration = ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU
-                                    ? CalculateNonOfdmaDurationForHeTb(txVector)
-                                    : CalculateNonOfdmaDurationForHeMu(txVector);
-        auto nonOfdmaTxPowerSpectrum =
-            GetTxPowerSpectralDensity(DbmToW(nonOfdmaTxPowerDbm), ppdu, HePpdu::PSD_NON_HE_PORTION);
-        Transmit(nonOfdmaDuration,
+        // non-HE portion
+        auto nonHePortionDuration = ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU
+                                        ? CalculateNonHeDurationForHeTb(txVector)
+                                        : CalculateNonHeDurationForHeMu(txVector);
+        auto nonHeTxPowerSpectrum =
+            GetTxPowerSpectralDensity(DbmToW(nonHeTxPowerDbm), ppdu, HePpdu::PSD_NON_HE_PORTION);
+        Transmit(nonHePortionDuration,
                  ppdu,
-                 nonOfdmaTxPowerDbm,
-                 nonOfdmaTxPowerSpectrum,
-                 "non-OFDMA transmission");
-
-        // OFDMA part
-        auto ofdmaDuration = ppdu->GetTxDuration() - nonOfdmaDuration;
-        auto ofdmaTxPowerSpectrum =
-            GetTxPowerSpectralDensity(DbmToW(ofdmaTxPowerDbm), ppdu, HePpdu::PSD_HE_PORTION);
-        Simulator::Schedule(nonOfdmaDuration,
-                            &HePhy::StartTxOfdma,
+                 nonHeTxPowerDbm,
+                 nonHeTxPowerSpectrum,
+                 "non-HE portion transmission");
+
+        // HE portion
+        auto hePortionDuration = ppdu->GetTxDuration() - nonHePortionDuration;
+        auto heTxPowerSpectrum =
+            GetTxPowerSpectralDensity(DbmToW(heTxPowerDbm), ppdu, HePpdu::PSD_HE_PORTION);
+        Simulator::Schedule(nonHePortionDuration,
+                            &HePhy::StartTxHePortion,
                             this,
                             ppdu,
-                            ofdmaTxPowerDbm,
-                            ofdmaTxPowerSpectrum,
-                            ofdmaDuration);
+                            heTxPowerDbm,
+                            heTxPowerSpectrum,
+                            hePortionDuration);
     }
     else
     {
-        PhyEntity::StartTx(ppdu);
+        VhtPhy::StartTx(ppdu);
     }
 }
 
 void
-HePhy::StartTxOfdma(Ptr<const WifiPpdu> ppdu,
-                    double txPowerDbm,
-                    Ptr<SpectrumValue> txPowerSpectrum,
-                    Time ofdmaDuration)
+HePhy::StartTxHePortion(Ptr<const WifiPpdu> ppdu,
+                        double txPowerDbm,
+                        Ptr<SpectrumValue> txPowerSpectrum,
+                        Time hePortionDuration)
 {
-    NS_LOG_FUNCTION(this << ppdu << txPowerDbm << ofdmaDuration);
+    NS_LOG_FUNCTION(this << ppdu << txPowerDbm << hePortionDuration);
     auto hePpdu = DynamicCast<const HePpdu>(ppdu);
     NS_ASSERT(hePpdu);
     hePpdu->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
-    Transmit(ofdmaDuration, ppdu, txPowerDbm, txPowerSpectrum, "OFDMA transmission");
+    Transmit(hePortionDuration, ppdu, txPowerDbm, txPowerSpectrum, "HE portion transmission");
 }
 
 Time
@@ -1785,7 +1774,7 @@
 }
 
 bool
-HePhy::CanStartRx(Ptr<const WifiPpdu> ppdu, uint16_t txChannelWidth) const
+HePhy::CanStartRx(Ptr<const WifiPpdu> ppdu) const
 {
     /*
      * The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU
@@ -1800,7 +1789,7 @@
     {
         return true;
     }
-    return PhyEntity::CanStartRx(ppdu, txChannelWidth);
+    return VhtPhy::CanStartRx(ppdu);
 }
 
 Ptr<const WifiPpdu>
@@ -1826,19 +1815,7 @@
         hePpdu->UpdateTxVectorForUlMu(m_trigVector);
         return rxPpdu;
     }
-    else if (auto txVector = ppdu->GetTxVector();
-             m_currentTxVector.has_value() &&
-             (m_previouslyTxPpduUid == ppdu->GetUid()) &&         // response to a trigger frame
-             (txVector.GetModulationClass() < WIFI_MOD_CLASS_HT)) // PPDU is a non-HT (duplicate)
-    {
-        auto triggerChannelWidth = m_currentTxVector->GetChannelWidth();
-        if (txVector.GetChannelWidth() != triggerChannelWidth)
-        {
-            txVector.SetChannelWidth(triggerChannelWidth);
-            ppdu->UpdateTxVector(txVector);
-        }
-    }
-    return PhyEntity::GetRxPpduFromTxPpdu(ppdu);
+    return VhtPhy::GetRxPpduFromTxPpdu(ppdu);
 }
 
 WifiSpectrumBandIndices
@@ -1849,7 +1826,7 @@
                               uint8_t bandIndex)
 {
     WifiSpectrumBandIndices convertedSubcarriers;
-    uint32_t nGuardBands =
+    auto nGuardBands =
         static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / subcarrierSpacing) + 0.5);
     uint32_t centerFrequencyIndex = 0;
     switch (bandWidth)
@@ -1871,7 +1848,7 @@
         break;
     }
 
-    size_t numBandsInBand = static_cast<size_t>(bandWidth * 1e6 / subcarrierSpacing);
+    auto numBandsInBand = static_cast<size_t>(bandWidth * 1e6 / subcarrierSpacing);
     centerFrequencyIndex += numBandsInBand * bandIndex;
 
     convertedSubcarriers.first = centerFrequencyIndex + subcarrierRange.first;
@@ -1879,47 +1856,6 @@
     return convertedSubcarriers;
 }
 
-HePhy::RuBands
-HePhy::GetRuBands(Ptr<const WifiPhy> phy, uint16_t channelWidth, uint16_t guardBandwidth)
-{
-    HePhy::RuBands ruBands{};
-    for (uint16_t bw = 160; bw >= 20; bw = bw / 2)
-    {
-        for (uint32_t i = 0; i < (channelWidth / bw); ++i)
-        {
-            for (uint32_t type = 0; type < 7; type++)
-            {
-                HeRu::RuType ruType = static_cast<HeRu::RuType>(type);
-                std::size_t nRus = HeRu::GetNRus(bw, ruType);
-                for (std::size_t phyIndex = 1; phyIndex <= nRus; phyIndex++)
-                {
-                    HeRu::SubcarrierGroup group = HeRu::GetSubcarrierGroup(bw, ruType, phyIndex);
-                    HeRu::SubcarrierRange subcarrierRange =
-                        std::make_pair(group.front().first, group.back().second);
-                    const auto bandIndices = ConvertHeRuSubcarriers(bw,
-                                                                    guardBandwidth,
-                                                                    phy->GetSubcarrierSpacing(),
-                                                                    subcarrierRange,
-                                                                    i);
-                    const auto bandFrequencies = phy->ConvertIndicesToFrequencies(bandIndices);
-                    WifiSpectrumBandInfo band = {bandIndices, bandFrequencies};
-                    std::size_t index =
-                        (bw == 160 && phyIndex > nRus / 2 ? phyIndex - nRus / 2 : phyIndex);
-                    const auto p20Index = phy->GetOperatingChannel().GetPrimaryChannelIndex(20);
-                    bool primary80IsLower80 = (p20Index < bw / 40);
-                    bool primary80 = (bw < 160 || ruType == HeRu::RU_2x996_TONE ||
-                                      (primary80IsLower80 && phyIndex <= nRus / 2) ||
-                                      (!primary80IsLower80 && phyIndex > nRus / 2));
-                    HeRu::RuSpec ru(ruType, index, primary80);
-                    NS_ABORT_IF(ru.GetPhyIndex(bw, p20Index) != phyIndex);
-                    ruBands.insert({band, ru});
-                }
-            }
-        }
-    }
-    return ruBands;
-}
-
 } // namespace ns3
 
 namespace
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/he/he-phy.h ns-3.40/src/wifi/model/he/he-phy.h
--- ns-3.39/src/wifi/model/he/he-phy.h	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/he/he-phy.h	2023-09-27 13:30:37.906839800 -0700
@@ -116,7 +116,7 @@
     void NotifyCcaBusy(const Ptr<const WifiPpdu> ppdu,
                        Time duration,
                        WifiChannelListType channelType) override;
-    bool CanStartRx(Ptr<const WifiPpdu> ppdu, uint16_t txChannelWidth) const override;
+    bool CanStartRx(Ptr<const WifiPpdu> ppdu) const override;
     Ptr<const WifiPpdu> GetRxPpduFromTxPpdu(Ptr<const WifiPpdu> ppdu) override;
 
     /**
@@ -152,16 +152,16 @@
     /**
      * \param txVector the transmission parameters used for the HE TB PPDU
      *
-     * \return the duration of the non-OFDMA portion of the HE TB PPDU.
+     * \return the duration of the non-HE portion of the HE TB PPDU.
      */
-    virtual Time CalculateNonOfdmaDurationForHeTb(const WifiTxVector& txVector) const;
+    virtual Time CalculateNonHeDurationForHeTb(const WifiTxVector& txVector) const;
 
     /**
      * \param txVector the transmission parameters used for the HE MU PPDU
      *
-     * \return the duration of the non-OFDMA portion of the HE MU PPDU.
+     * \return the duration of the non-HE portion of the HE MU PPDU.
      */
-    virtual Time CalculateNonOfdmaDurationForHeMu(const WifiTxVector& txVector) const;
+    virtual Time CalculateNonHeDurationForHeMu(const WifiTxVector& txVector) const;
 
     /**
      * Get the band in the TX spectrum associated with the RU used by the PSDU
@@ -215,15 +215,15 @@
     void SetTrigVector(const WifiTxVector& trigVector, Time validity);
 
     /**
-     * Get the center frequency of the non-OFDMA part of the current TxVector for the
+     * Get the center frequency of the non-HE portion of the current TxVector for the
      * given STA-ID.
      * Note this method is only to be used for UL MU.
      *
      * \param txVector the TXVECTOR that has the RU allocation
      * \param staId the STA-ID of the station taking part of the UL MU
-     * \return the center frequency in MHz corresponding to the non-OFDMA part of the HE TB PPDU
+     * \return the center frequency in MHz corresponding to the non-HE portion of the HE TB PPDU
      */
-    uint16_t GetCenterFrequencyForNonOfdmaPart(const WifiTxVector& txVector, uint16_t staId) const;
+    uint16_t GetCenterFrequencyForNonHePart(const WifiTxVector& txVector, uint16_t staId) const;
 
     /**
      * Sets the OBSS-PD algorithm.
@@ -451,21 +451,6 @@
                                                           HeRu::SubcarrierRange subcarrierRange,
                                                           uint8_t bandIndex = 0);
 
-    /// Map a spectrum band associated with an RU to the RU specification
-    using RuBands = std::map<WifiSpectrumBandInfo, HeRu::RuSpec>;
-
-    /**
-     * Static function to compute the RU bands that belong to a given channel width.
-     *
-     * \param phy the PHY that issued the function call
-     * \param channelWidth the channelWidth the channel width in MHz
-     * \param guardBandwidth width of the guard band in MHz
-     * \returns the computed RU bands that belong to the channel width
-     */
-    static RuBands GetRuBands(Ptr<const WifiPhy> phy,
-                              uint16_t channelWidth,
-                              uint16_t guardBandwidth);
-
   protected:
     PhyFieldRxStatus ProcessSig(Ptr<Event> event,
                                 PhyFieldRxStatus status,
@@ -493,6 +478,9 @@
     uint32_t GetMaxPsduSize() const override;
     WifiConstPsduMap GetWifiConstPsduMap(Ptr<const WifiPsdu> psdu,
                                          const WifiTxVector& txVector) const override;
+    void HandleRxPpduWithSameContent(Ptr<Event> event,
+                                     Ptr<const WifiPpdu> ppdu,
+                                     RxPowerWattPerChannelBand& rxPower) override;
 
     /**
      * Process SIG-A, perform amendment-specific actions, and
@@ -523,13 +511,13 @@
     virtual uint32_t GetSigBSize(const WifiTxVector& txVector) const;
 
     /**
-     * Start receiving the PSDU (i.e. the first symbol of the PSDU has arrived) of an OFDMA
-     * transmission. This function is called upon the RX event corresponding to the OFDMA part of
+     * Start receiving the PSDU (i.e. the first symbol of the PSDU has arrived) of an MU
+     * transmission. This function is called upon the RX event corresponding to the HE portion of
      * the MU PPDU.
      *
-     * \param event the event holding incoming OFDMA part of the PPDU's information
+     * \param event the event holding incoming HE portion of the PPDU's information
      */
-    void StartReceiveOfdmaPayload(Ptr<Event> event);
+    void StartReceiveMuPayload(Ptr<Event> event);
 
     /**
      * Return the rate (in bps) of the non-HT Reference Rate
@@ -563,8 +551,8 @@
     uint64_t m_currentMuPpduUid;    //!< UID of the HE MU or HE TB PPDU being received
 
     std::map<uint16_t /* STA-ID */, EventId>
-        m_beginOfdmaPayloadRxEvents; //!< the beginning of the OFDMA payload reception events
-                                     //!< (indexed by STA-ID)
+        m_beginMuPayloadRxEvents; //!< the beginning of the MU payload reception events (indexed by
+                                  //!< STA-ID)
 
     EndOfHeSigACallback m_endOfHeSigACallback;      //!< end of HE-SIG-A callback
     std::optional<WifiTxVector> m_trigVector;       //!< the TRIGVECTOR
@@ -590,17 +578,17 @@
                                                  HePpdu::TxPsdFlag flag) const;
 
     /**
-     * Start the transmission of the OFDMA part of the MU PPDU.
+     * Start the transmission of the HE portion of the MU PPDU.
      *
      * \param ppdu the PPDU
      * \param txPowerDbm the total TX power in dBm
      * \param txPowerSpectrum the TX PSD
-     * \param ofdmaDuration the duration of the OFDMA part
+     * \param hePortionDuration the duration of the HE portion
      */
-    void StartTxOfdma(Ptr<const WifiPpdu> ppdu,
-                      double txPowerDbm,
-                      Ptr<SpectrumValue> txPowerSpectrum,
-                      Time ofdmaDuration);
+    void StartTxHePortion(Ptr<const WifiPpdu> ppdu,
+                          double txPowerDbm,
+                          Ptr<SpectrumValue> txPowerSpectrum,
+                          Time hePortionDuration);
 
     /**
      * Notify PHY state helper to switch to CCA busy state,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/he/he-ppdu.cc ns-3.40/src/wifi/model/he/he-ppdu.cc
--- ns-3.39/src/wifi/model/he/he-ppdu.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/he/he-ppdu.cc	2023-09-27 13:30:37.906839800 -0700
@@ -29,6 +29,8 @@
 #include "ns3/wifi-psdu.h"
 #include "ns3/wifi-utils.h"
 
+#include <algorithm>
+
 namespace ns3
 {
 
@@ -129,10 +131,15 @@
     else if (ns3::IsDlMu(m_preamble))
     {
         const auto p20Index = m_operatingChannel.GetPrimaryChannelIndex(20);
+        const uint8_t noMuMimoUsers{0};
         m_heSig.emplace<HeMuSigHeader>(HeMuSigHeader{
             .m_bssColor = bssColor,
             .m_bandwidth = GetChannelWidthEncodingFromMhz(txVector.GetChannelWidth()),
             .m_sigBMcs = txVector.GetSigBMode().GetMcsValue(),
+            .m_muMimoUsers = (txVector.IsSigBCompression()
+                                  ? GetMuMimoUsersEncoding(txVector.GetHeMuUserInfoMap().size())
+                                  : noMuMimoUsers),
+            .m_sigBCompression = txVector.IsSigBCompression(),
             .m_giLtfSize = GetGuardIntervalAndNltfEncoding(txVector.GetGuardInterval(),
                                                            2 /*NLTF currently unused*/),
             .m_ruAllocation = txVector.GetRuAllocation(p20Index),
@@ -194,7 +201,11 @@
         txVector.SetChannelWidth(GetChannelWidthMhzFromEncoding(heSigHeader->m_bandwidth));
         txVector.SetGuardInterval(GetGuardIntervalFromEncoding(heSigHeader->m_giLtfSize));
         txVector.SetBssColor(heSigHeader->m_bssColor);
-        SetHeMuUserInfos(txVector, heSigHeader->m_ruAllocation, heSigHeader->m_contentChannels);
+        SetHeMuUserInfos(txVector,
+                         heSigHeader->m_ruAllocation,
+                         heSigHeader->m_contentChannels,
+                         heSigHeader->m_sigBCompression,
+                         GetMuMimoUsersFromEncoding(heSigHeader->m_muMimoUsers));
         txVector.SetSigBMode(HePhy::GetVhtMcs(heSigHeader->m_sigBMcs));
         const auto p20Index = m_operatingChannel.GetPrimaryChannelIndex(20);
         txVector.SetRuAllocation(heSigHeader->m_ruAllocation, p20Index);
@@ -202,25 +213,37 @@
         {
             txVector.SetCenter26ToneRuIndication(heSigHeader->m_center26ToneRuIndication.value());
         }
+        if (heSigHeader->m_sigBCompression)
+        {
+            NS_ASSERT(GetMuMimoUsersFromEncoding(heSigHeader->m_muMimoUsers) ==
+                      txVector.GetHeMuUserInfoMap().size());
+        }
     }
 }
 
 void
 HePpdu::SetHeMuUserInfos(WifiTxVector& txVector,
                          const RuAllocation& ruAllocation,
-                         const HeSigBContentChannels& contentChannels) const
+                         const HeSigBContentChannels& contentChannels,
+                         bool sigBcompression,
+                         uint8_t numMuMimoUsers) const
 {
-    auto contentChannelIndex = 0;
+    std::size_t contentChannelIndex = 0;
     for (const auto& contentChannel : contentChannels)
     {
-        auto numRusLeft = 0;
-        auto ruAllocIndex = contentChannelIndex;
+        std::size_t numRusLeft = 0;
+        std::size_t numUsersLeft = 0;
+        std::size_t ruAllocIndex = contentChannelIndex;
         for (const auto& userInfo : contentChannel)
         {
             if (userInfo.staId == NO_USER_STA_ID)
             {
                 continue;
             }
+            if (ruAllocIndex >= ruAllocation.size())
+            {
+                break;
+            }
             auto ruSpecs = HeRu::GetRuSpecs(ruAllocation.at(ruAllocIndex));
             if (ruSpecs.empty())
             {
@@ -230,14 +253,27 @@
             {
                 numRusLeft = ruSpecs.size();
             }
+            if (numUsersLeft == 0)
+            {
+                if (sigBcompression)
+                {
+                    numUsersLeft = numMuMimoUsers;
+                }
+                else
+                {
+                    // not MU-MIMO
+                    numUsersLeft = 1;
+                }
+            }
             auto ruIndex = (ruSpecs.size() - numRusLeft);
             auto ruSpec = ruSpecs.at(ruIndex);
             auto ruType = ruSpec.GetRuType();
             if ((ruAllocation.size() == 8) && (ruType == HeRu::RU_996_TONE) &&
-                (std::all_of(
-                    contentChannel.cbegin(),
-                    contentChannel.cend(),
-                    [&userInfo](const auto& item) { return userInfo.staId == item.staId; })))
+                (((txVector.GetChannelWidth() == 160) && sigBcompression) ||
+                 std::all_of(
+                     contentChannel.cbegin(),
+                     contentChannel.cend(),
+                     [&userInfo](const auto& item) { return userInfo.staId == item.staId; })))
             {
                 NS_ASSERT(txVector.GetChannelWidth() == 160);
                 ruType = HeRu::RU_2x996_TONE;
@@ -259,12 +295,13 @@
                                           userInfo.mcs,
                                           userInfo.nss});
             }
-            if (ruType == HeRu::RU_2x996_TONE)
+            if ((ruType == HeRu::RU_2x996_TONE) && !sigBcompression)
             {
                 return;
             }
             numRusLeft--;
-            if (numRusLeft == 0)
+            numUsersLeft--;
+            if (numRusLeft == 0 && numUsersLeft == 0)
             {
                 ruAllocIndex += (2 * numRuAllocsInContentChannel);
             }
@@ -277,7 +314,7 @@
 HePpdu::GetTxDuration() const
 {
     Time ppduDuration = Seconds(0);
-    const WifiTxVector& txVector = GetTxVector();
+    const auto& txVector = GetTxVector();
     const auto length = m_lSig.GetLength();
     const auto tSymbol = NanoSeconds(12800 + txVector.GetGuardInterval());
     const auto preambleDuration = WifiPhy::CalculatePhyPreambleAndHeaderDuration(txVector);
@@ -378,10 +415,10 @@
 }
 
 uint16_t
-HePpdu::GetTransmissionChannelWidth() const
+HePpdu::GetTxChannelWidth() const
 {
-    const WifiTxVector& txVector = GetTxVector();
-    if (txVector.IsUlMu() && GetStaId() != SU_STA_ID)
+    if (const auto& txVector = GetTxVector();
+        txVector.IsValid() && txVector.IsUlMu() && GetStaId() != SU_STA_ID)
     {
         TxPsdFlag flag = GetTxPsdFlag();
         uint16_t ruWidth = HeRu::GetBandwidth(txVector.GetRu(GetStaId()).GetRuType());
@@ -392,7 +429,7 @@
     }
     else
     {
-        return OfdmPpdu::GetTransmissionChannelWidth();
+        return OfdmPpdu::GetTxChannelWidth();
     }
 }
 
@@ -446,17 +483,37 @@
 }
 
 std::pair<std::size_t, std::size_t>
-HePpdu::GetNumRusPerHeSigBContentChannel(uint16_t channelWidth, const RuAllocation& ruAllocation)
+HePpdu::GetNumRusPerHeSigBContentChannel(uint16_t channelWidth,
+                                         const RuAllocation& ruAllocation,
+                                         bool sigBCompression,
+                                         uint8_t numMuMimoUsers)
 {
-    // MU-MIMO is not handled for now, i.e. one station per RU
-    NS_ASSERT_MSG(!ruAllocation.empty(), "RU allocation is not set");
-    NS_ASSERT_MSG(ruAllocation.size() == channelWidth / 20,
-                  "RU allocation is not consistent with packet bandwidth");
-
     std::pair<std::size_t /* number of RUs in content channel 1 */,
               std::size_t /* number of RUs in content channel 2 */>
         chSize{0, 0};
 
+    if (sigBCompression)
+    {
+        // If the HE-SIG-B Compression field in the HE-SIG-A field of an HE MU PPDU is 1,
+        // for bandwidths larger than 20 MHz, the AP performs an equitable split of
+        // the User fields between two HE-SIG-B content channels
+        if (channelWidth == 20)
+        {
+            return {numMuMimoUsers, 0};
+        }
+        chSize.first = numMuMimoUsers / 2;
+        chSize.second = numMuMimoUsers / 2;
+        if (numMuMimoUsers != (chSize.first + chSize.second))
+        {
+            chSize.first++;
+        }
+        return chSize;
+    }
+
+    NS_ASSERT_MSG(!ruAllocation.empty(), "RU allocation is not set");
+    NS_ASSERT_MSG(ruAllocation.size() == channelWidth / 20,
+                  "RU allocation is not consistent with packet bandwidth");
+
     switch (channelWidth)
     {
     case 40:
@@ -505,19 +562,20 @@
     }
 
     const auto& orderedMap = txVector.GetUserInfoMapOrderedByRus(p20Index);
-    for (const auto& [ru, staId] : orderedMap)
+    for (const auto& [ru, staIds] : orderedMap)
     {
-        auto ruType = ru.GetRuType();
-        auto ruIdx = ru.GetIndex();
-        const auto& userInfo = txVector.GetHeMuUserInfo(staId);
-        NS_ASSERT(ru == userInfo.ru);
-
-        if (ruType > HeRu::RU_242_TONE)
+        const auto ruType = ru.GetRuType();
+        if ((ruType > HeRu::RU_242_TONE) && !txVector.IsSigBCompression())
         {
             for (auto i = 0; i < ((ruType == HeRu::RU_2x996_TONE) ? 2 : 1); ++i)
             {
-                contentChannels[0].push_back({staId, userInfo.nss, userInfo.mcs});
-                contentChannels[1].push_back({staId, userInfo.nss, userInfo.mcs});
+                for (auto staId : staIds)
+                {
+                    const auto& userInfo = txVector.GetHeMuUserInfo(staId);
+                    NS_ASSERT(ru == userInfo.ru);
+                    contentChannels[0].push_back({staId, userInfo.nss, userInfo.mcs});
+                    contentChannels[1].push_back({staId, userInfo.nss, userInfo.mcs});
+                }
             }
             continue;
         }
@@ -525,55 +583,84 @@
         std::size_t numRus = (ruType >= HeRu::RU_242_TONE)
                                  ? 1
                                  : HeRu::m_heRuSubcarrierGroups.at({20, ruType}).size();
-        if (((ruIdx - 1) / numRus) % 2 == 0)
-        {
-            contentChannels.at(0).push_back({staId, userInfo.nss, userInfo.mcs});
-        }
-        else
+        const auto ruIdx = ru.GetIndex();
+        for (auto staId : staIds)
         {
-            contentChannels.at(1).push_back({staId, userInfo.nss, userInfo.mcs});
+            const auto& userInfo = txVector.GetHeMuUserInfo(staId);
+            NS_ASSERT(ru == userInfo.ru);
+            std::size_t ccIndex{0};
+            if (channelWidth < 40)
+            {
+                // only one content channel
+                ccIndex = 0;
+            }
+            else if (txVector.IsSigBCompression())
+            {
+                // equal split
+                ccIndex = (contentChannels.at(0).size() <= contentChannels.at(1).size()) ? 0 : 1;
+            }
+            else // MU-MIMO
+            {
+                ccIndex = (((ruIdx - 1) / numRus) % 2 == 0) ? 0 : 1;
+            }
+            contentChannels.at(ccIndex).push_back({staId, userInfo.nss, userInfo.mcs});
         }
     }
 
-    // Add unassigned RUs
-    auto numNumRusPerHeSigBContentChannel =
-        GetNumRusPerHeSigBContentChannel(channelWidth, txVector.GetRuAllocation(p20Index));
-    std::size_t contentChannelIndex = 1;
-    for (auto& contentChannel : contentChannels)
+    const auto isSigBCompression = txVector.IsSigBCompression();
+    if (!isSigBCompression)
     {
-        const auto totalUsersInContentChannel = (contentChannelIndex == 1)
-                                                    ? numNumRusPerHeSigBContentChannel.first
-                                                    : numNumRusPerHeSigBContentChannel.second;
-        NS_ASSERT(contentChannel.size() <= totalUsersInContentChannel);
-        std::size_t unallocatedRus = totalUsersInContentChannel - contentChannel.size();
-        for (std::size_t i = 0; i < unallocatedRus; i++)
+        // Add unassigned RUs
+        auto numNumRusPerHeSigBContentChannel = GetNumRusPerHeSigBContentChannel(
+            channelWidth,
+            txVector.GetRuAllocation(p20Index),
+            isSigBCompression,
+            isSigBCompression ? txVector.GetHeMuUserInfoMap().size() : 0);
+        std::size_t contentChannelIndex = 1;
+        for (auto& contentChannel : contentChannels)
         {
-            contentChannel.push_back({NO_USER_STA_ID, 0, 0});
+            const auto totalUsersInContentChannel = (contentChannelIndex == 1)
+                                                        ? numNumRusPerHeSigBContentChannel.first
+                                                        : numNumRusPerHeSigBContentChannel.second;
+            NS_ASSERT(contentChannel.size() <= totalUsersInContentChannel);
+            std::size_t unallocatedRus = totalUsersInContentChannel - contentChannel.size();
+            for (std::size_t i = 0; i < unallocatedRus; i++)
+            {
+                contentChannel.push_back({NO_USER_STA_ID, 0, 0});
+            }
+            contentChannelIndex++;
         }
-        contentChannelIndex++;
     }
 
     return contentChannels;
 }
 
 uint32_t
-HePpdu::GetSigBFieldSize(uint16_t channelWidth, const RuAllocation& ruAllocation)
+HePpdu::GetSigBFieldSize(uint16_t channelWidth,
+                         const RuAllocation& ruAllocation,
+                         bool sigBCompression,
+                         std::size_t numMuMimoUsers)
 {
     // Compute the number of bits used by common field.
-    // Assume that compression bit in HE-SIG-A is not set (i.e. not
-    // full band MU-MIMO); the field is present.
-    auto commonFieldSize = 4 /* CRC */ + 6 /* tail */;
-    if (channelWidth <= 40)
-    {
-        commonFieldSize += 8; // only one allocation subfield
-    }
-    else
+    uint32_t commonFieldSize = 0;
+    if (!sigBCompression)
     {
-        commonFieldSize +=
-            8 * (channelWidth / 40) /* one allocation field per 40 MHz */ + 1 /* center RU */;
+        commonFieldSize = 4 /* CRC */ + 6 /* tail */;
+        if (channelWidth <= 40)
+        {
+            commonFieldSize += 8; // only one allocation subfield
+        }
+        else
+        {
+            commonFieldSize +=
+                8 * (channelWidth / 40) /* one allocation field per 40 MHz */ + 1 /* center RU */;
+        }
     }
 
-    auto numRusPerContentChannel = GetNumRusPerHeSigBContentChannel(channelWidth, ruAllocation);
+    auto numRusPerContentChannel = GetNumRusPerHeSigBContentChannel(channelWidth,
+                                                                    ruAllocation,
+                                                                    sigBCompression,
+                                                                    numMuMimoUsers);
     auto maxNumRusPerContentChannel =
         std::max(numRusPerContentChannel.first, numRusPerContentChannel.second);
     auto maxNumUserBlockFields = maxNumRusPerContentChannel /
@@ -698,4 +785,17 @@
     return nsts + 1;
 }
 
+uint8_t
+HePpdu::GetMuMimoUsersEncoding(uint8_t nUsers)
+{
+    NS_ASSERT(nUsers <= 8);
+    return (nUsers - 1);
+}
+
+uint8_t
+HePpdu::GetMuMimoUsersFromEncoding(uint8_t encoding)
+{
+    return (encoding + 1);
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/he/he-ppdu.h ns-3.40/src/wifi/model/he/he-ppdu.h
--- ns-3.39/src/wifi/model/he/he-ppdu.h	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/he/he-ppdu.h	2023-09-27 13:30:37.906839800 -0700
@@ -89,10 +89,12 @@
     struct HeMuSigHeader
     {
         // HE-SIG-A fields
-        uint8_t m_bssColor{0};  ///< BSS color field
-        uint8_t m_bandwidth{0}; ///< Bandwidth field
-        uint8_t m_sigBMcs{0};   ///< HE-SIG-B MCS
-        uint8_t m_giLtfSize{0}; ///< GI+LTF Size field
+        uint8_t m_bssColor{0};        ///< BSS color field
+        uint8_t m_bandwidth{0};       ///< Bandwidth field
+        uint8_t m_sigBMcs{0};         ///< HE-SIG-B MCS
+        uint8_t m_muMimoUsers;        ///< MU-MIMO users
+        uint8_t m_sigBCompression{0}; ///< SIG-B compression
+        uint8_t m_giLtfSize{0};       ///< GI+LTF Size field
 
         // HE-SIG-B fields
         RuAllocation m_ruAllocation; //!< RU allocations that are going to be carried in SIG-B
@@ -152,7 +154,7 @@
     Ptr<WifiPpdu> Copy() const override;
     WifiPpduType GetType() const override;
     uint16_t GetStaId() const override;
-    uint16_t GetTransmissionChannelWidth() const override;
+    uint16_t GetTxChannelWidth() const override;
 
     /**
      * Get the payload of the PPDU.
@@ -187,18 +189,21 @@
     void UpdateTxVectorForUlMu(const std::optional<WifiTxVector>& trigVector) const;
 
     /**
-     * Get the number of RUs per HE-SIG-B content channel.
-     * This is applicable only for MU. MU-MIMO (i.e. multiple stations
-     * per RU) is not supported yet.
+     * Get the number of STAs per HE-SIG-B content channel.
+     * This is applicable only for MU.
      * See section 27.3.10.8.3 of IEEE 802.11ax draft 4.0.
      *
      * \param channelWidth the channel width occupied by the PPDU (in MHz)
      * \param ruAllocation 8 bit RU_ALLOCATION per 20 MHz
+     * \param sigBCompression flag whether SIG-B compression is used by the PPDU
+     * \param numMuMimoUsers the number of MU-MIMO users addressed by the PPDU
      * \return a pair containing the number of RUs in each HE-SIG-B content channel (resp. 1 and 2)
      */
     static std::pair<std::size_t, std::size_t> GetNumRusPerHeSigBContentChannel(
         uint16_t channelWidth,
-        const RuAllocation& ruAllocation);
+        const RuAllocation& ruAllocation,
+        bool sigBCompression,
+        uint8_t numMuMimoUsers);
 
     /**
      * Get the HE SIG-B content channels for a given PPDU
@@ -215,9 +220,14 @@
      * Get variable length HE SIG-B field size
      * \param channelWidth the channel width occupied by the PPDU (in MHz)
      * \param ruAllocation 8 bit RU_ALLOCATION per 20 MHz
+     * \param sigBCompression flag whether SIG-B compression is used by the PPDU
+     * \param numMuMimoUsers the number of MU-MIMO users addressed by the PPDU
      * \return field size in bytes
      */
-    static uint32_t GetSigBFieldSize(uint16_t channelWidth, const RuAllocation& ruAllocation);
+    static uint32_t GetSigBFieldSize(uint16_t channelWidth,
+                                     const RuAllocation& ruAllocation,
+                                     bool sigBCompression,
+                                     std::size_t numMuMimoUsers);
 
   protected:
     /**
@@ -233,10 +243,14 @@
      * \param txVector the TXVECTOR to set its HeMuUserInfoMap
      * \param ruAllocation the RU_ALLOCATION per 20 MHz
      * \param contentChannels the HE-SIG-B content channels
+     * \param sigBCompression flag whether SIG-B compression is used by the PPDU
+     * \param numMuMimoUsers the number of MU-MIMO users addressed by the PPDU
      */
     void SetHeMuUserInfos(WifiTxVector& txVector,
                           const RuAllocation& ruAllocation,
-                          const HeSigBContentChannels& contentChannels) const;
+                          const HeSigBContentChannels& contentChannels,
+                          bool sigBCompression,
+                          uint8_t numMuMimoUsers) const;
 
     /**
      * Convert channel width expressed in MHz to bandwidth field encoding in HE-SIG-A.
@@ -287,6 +301,22 @@
      */
     static uint16_t GetGuardIntervalFromEncoding(uint8_t giAndNltfSize);
 
+    /**
+     * Convert number of MU-MIMO users to its encoding in HE-SIG-A.
+     *
+     * \param nUsers the number of MU-MIMO users
+     * \return the number of MU-MIMO users to its encoding in HE-SIG-A
+     */
+    static uint8_t GetMuMimoUsersEncoding(uint8_t nUsers);
+
+    /**
+     * Convert number of MU-MIMO users from its encoding in HE-SIG-A.
+     *
+     * \param encoding the number of MU-MIMO users encoded in HE-SIG-A
+     * \return the number of MU-MIMO users from its encoding in HE-SIG-A
+     */
+    static uint8_t GetMuMimoUsersFromEncoding(uint8_t encoding);
+
     mutable TxPsdFlag m_txPsdFlag; //!< the transmit power spectral density flag
 
   private:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/he/he-ru.cc ns-3.40/src/wifi/model/he/he-ru.cc
--- ns-3.39/src/wifi/model/he/he-ru.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/he/he-ru.cc	2023-09-27 13:30:37.906839800 -0700
@@ -23,6 +23,7 @@
 #include "ns3/assert.h"
 
 #include <optional>
+#include <tuple>
 
 namespace ns3
 {
@@ -890,4 +891,14 @@
     return !(*this == other);
 }
 
+bool
+HeRu::RuSpec::operator<(const RuSpec& other) const
+{
+    // we do not compare the RU PHY indices because they may be uninitialized for
+    // one of the compared RUs. This event should not cause the comparison to evaluate
+    // to false
+    return std::tie(m_ruType, m_index, m_primary80MHz) <
+           std::tie(other.m_ruType, other.m_index, other.m_primary80MHz);
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/he/he-ru.h ns-3.40/src/wifi/model/he/he-ru.h
--- ns-3.39/src/wifi/model/he/he-ru.h	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/he/he-ru.h	2023-09-27 13:30:37.906839800 -0700
@@ -119,6 +119,13 @@
          * \return true if this RU differs from the given RU, false otherwise
          */
         bool operator!=(const RuSpec& other) const;
+        /**
+         * Compare this RU to the given RU.
+         *
+         * \param other the given RU
+         * \return true if this RU is smaller than the given RU, false otherwise
+         */
+        bool operator<(const RuSpec& other) const;
 
       private:
         RuType m_ruType;     //!< RU type
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/he/rr-multi-user-scheduler.cc ns-3.40/src/wifi/model/he/rr-multi-user-scheduler.cc
--- ns-3.39/src/wifi/model/he/rr-multi-user-scheduler.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/he/rr-multi-user-scheduler.cc	2023-09-27 13:30:37.906839800 -0700
@@ -708,8 +708,17 @@
                     WifiTxVector suTxVector =
                         GetWifiRemoteStationManager(m_linkId)->GetDataTxVector(mpdu->GetHeader(),
                                                                                m_allowedWidth);
+
                     WifiTxVector txVectorCopy = m_txParams.m_txVector;
 
+                    // the first candidate STA determines the preamble type for the DL MU PPDU
+                    if (m_candidates.empty() &&
+                        suTxVector.GetPreambleType() == WIFI_PREAMBLE_EHT_MU)
+                    {
+                        m_txParams.m_txVector.SetPreambleType(WIFI_PREAMBLE_EHT_MU);
+                        m_txParams.m_txVector.SetEhtPpduType(0); // indicates DL OFDMA transmission
+                    }
+
                     m_txParams.m_txVector.SetHeMuUserInfo(staIt->aid,
                                                           {{currRuType, 1, true},
                                                            suTxVector.GetMode().GetMcsValue(),
@@ -737,17 +746,6 @@
             }
         }
 
-        // the first candidate STA determines the preamble type for the DL MU PPDU
-        if (m_candidates.size() == 1)
-        {
-            if (m_apMac->GetEhtSupported() && m_apMac->GetEhtSupported(staIt->address))
-            {
-                m_txParams.m_txVector.SetPreambleType(WIFI_PREAMBLE_EHT_MU);
-                m_txParams.m_txVector.SetEhtPpduType(0); // indicates DL OFDMA transmission
-            }
-            // TODO otherwise, make sure the TX width does not exceed 160 MHz
-        }
-
         // move to the next station in the list
         staIt++;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/ht/ht-frame-exchange-manager.cc ns-3.40/src/wifi/model/ht/ht-frame-exchange-manager.cc
--- ns-3.39/src/wifi/model/ht/ht-frame-exchange-manager.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/ht/ht-frame-exchange-manager.cc	2023-09-27 13:30:37.906839800 -0700
@@ -643,7 +643,7 @@
 
     if (acknowledgment->method == WifiAcknowledgment::BLOCK_ACK)
     {
-        WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*>(acknowledgment);
+        auto blockAcknowledgment = static_cast<WifiBlockAck*>(acknowledgment);
         Time baTxDuration = m_phy->CalculateTxDuration(GetBlockAckSize(blockAcknowledgment->baType),
                                                        blockAcknowledgment->blockAckTxVector,
                                                        m_phy->GetPhyBand());
@@ -651,7 +651,7 @@
     }
     else if (acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
     {
-        WifiBarBlockAck* barBlockAcknowledgment = static_cast<WifiBarBlockAck*>(acknowledgment);
+        auto barBlockAcknowledgment = static_cast<WifiBarBlockAck*>(acknowledgment);
         Time barTxDuration =
             m_phy->CalculateTxDuration(GetBlockAckRequestSize(barBlockAcknowledgment->barType),
                                        barBlockAcknowledgment->blockAckReqTxVector,
@@ -1007,8 +1007,7 @@
         // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
         // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
         // aRxPHYStartDelay equals the time to transmit the PHY header.
-        WifiBlockAck* blockAcknowledgment =
-            static_cast<WifiBlockAck*>(m_txParams.m_acknowledgment.get());
+        auto blockAcknowledgment = static_cast<WifiBlockAck*>(m_txParams.m_acknowledgment.get());
 
         Time timeout =
             txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
@@ -1016,6 +1015,7 @@
         NS_ASSERT(!m_txTimer.IsRunning());
         m_txTimer.Set(WifiTxTimer::WAIT_BLOCK_ACK,
                       timeout,
+                      {m_psdu->GetAddr1()},
                       &HtFrameExchangeManager::BlockAckTimeout,
                       this,
                       m_psdu,
@@ -1131,6 +1131,7 @@
     NS_LOG_DEBUG("Transmitting a PSDU: " << *psdu << " TXVECTOR: " << txVector);
     FinalizeMacHeader(psdu);
     NotifyTxToEdca(psdu);
+    m_allowedWidth = std::min(m_allowedWidth, txVector.GetChannelWidth());
 
     if (psdu->IsAggregate())
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/ht/ht-phy.cc ns-3.40/src/wifi/model/ht/ht-phy.cc
--- ns-3.39/src/wifi/model/ht/ht-phy.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/ht/ht-phy.cc	2023-09-27 13:30:37.906839800 -0700
@@ -60,7 +60,7 @@
     m_maxSupportedMcsIndexPerSs = m_maxMcsIndexPerSs;
     if (buildModeList)
     {
-        NS_ABORT_MSG_IF(maxNss == 0 || maxNss > 4,
+        NS_ABORT_MSG_IF(maxNss == 0 || maxNss > HT_MAX_NSS,
                         "Unsupported max Nss " << +maxNss << " for HT PHY");
         BuildModeList();
     }
@@ -146,7 +146,7 @@
     case WIFI_PPDU_FIELD_HT_SIG:
         return GetHtSigMode();
     default:
-        return PhyEntity::GetSigMode(field, txVector);
+        return OfdmPhy::GetSigMode(field, txVector);
     }
 }
 
@@ -196,7 +196,7 @@
 {
     NS_LOG_FUNCTION(this << +maxNss);
     NS_ASSERT(m_bssMembershipSelector == HT_PHY);
-    NS_ABORT_MSG_IF(maxNss == 0 || maxNss > 4, "Unsupported max Nss " << +maxNss << " for HT PHY");
+    maxNss = std::min(HT_MAX_NSS, maxNss);
     if (maxNss != m_maxSupportedNss)
     {
         NS_LOG_LOGIC("Rebuild mode list since max number of spatial streams has changed");
@@ -242,7 +242,7 @@
     case WIFI_PPDU_FIELD_HT_SIG:
         return GetHtSigDuration();
     default:
-        return PhyEntity::GetDuration(field, txVector);
+        return OfdmPhy::GetDuration(field, txVector);
     }
 }
 
@@ -300,7 +300,7 @@
     case FIRST_MPDU_IN_AGGREGATE: {
         // First packet in an A-MPDU
         numSymbols = (stbc * (service + size * 8.0 + 6 * nes) / (stbc * numDataBitsPerSymbol));
-        if (incFlag == 1)
+        if (incFlag)
         {
             totalAmpduSize += size;
             totalAmpduNumSymbols += numSymbols;
@@ -310,7 +310,7 @@
     case MIDDLE_MPDU_IN_AGGREGATE: {
         // consecutive packets in an A-MPDU
         numSymbols = (stbc * size * 8.0) / (stbc * numDataBitsPerSymbol);
-        if (incFlag == 1)
+        if (incFlag)
         {
             totalAmpduSize += size;
             totalAmpduNumSymbols += numSymbols;
@@ -324,7 +324,7 @@
             stbc * ceil((service + totalSize * 8.0 + 6 * nes) / (stbc * numDataBitsPerSymbol)));
         NS_ASSERT(totalAmpduNumSymbols <= numSymbols);
         numSymbols -= totalAmpduNumSymbols;
-        if (incFlag == 1)
+        if (incFlag)
         {
             totalAmpduSize = 0;
             totalAmpduNumSymbols = 0;
@@ -407,7 +407,7 @@
 HtPhy::EndReceiveHtSig(Ptr<Event> event)
 {
     NS_LOG_FUNCTION(this << *event);
-    NS_ASSERT(event->GetTxVector().GetPreambleType() == WIFI_PREAMBLE_HT_MF);
+    NS_ASSERT(event->GetPpdu()->GetTxVector().GetPreambleType() == WIFI_PREAMBLE_HT_MF);
     SnrPer snrPer = GetPhyHeaderSnrPer(WIFI_PPDU_FIELD_HT_SIG, event);
     NS_LOG_DEBUG("HT-SIG: SNR(dB)=" << RatioToDb(snrPer.snr) << ", PER=" << snrPer.per);
     PhyFieldRxStatus status(GetRandomValue() > snrPer.per);
@@ -441,7 +441,7 @@
 bool
 HtPhy::IsConfigSupported(Ptr<const WifiPpdu> ppdu) const
 {
-    const WifiTxVector& txVector = ppdu->GetTxVector();
+    const auto& txVector = ppdu->GetTxVector();
     if (txVector.GetNss() > m_wifiPhy->GetMaxSupportedRxSpatialStreams())
     {
         NS_LOG_DEBUG("Packet reception could not be started because not enough RX antennas");
@@ -824,7 +824,7 @@
     NS_LOG_FUNCTION(this);
     if (m_wifiPhy->GetChannelWidth() < 40)
     {
-        return PhyEntity::GetCcaIndication(ppdu);
+        return OfdmPhy::GetCcaIndication(ppdu);
     }
     double ccaThresholdDbm = GetCcaThreshold(ppdu, WIFI_CHANLIST_PRIMARY);
     Time delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThresholdDbm, GetPrimaryBand(20));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/ht/ht-phy.h ns-3.40/src/wifi/model/ht/ht-phy.h
--- ns-3.39/src/wifi/model/ht/ht-phy.h	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/ht/ht-phy.h	2023-09-27 13:30:37.906839800 -0700
@@ -37,6 +37,9 @@
  */
 #define HT_PHY 127
 
+/// Maximum number of supported NSS by HT PHY
+constexpr uint8_t HT_MAX_NSS = 4;
+
 /**
  * \brief PHY entity for HT (11n)
  * \ingroup wifi
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/ht/ht-ppdu.cc ns-3.40/src/wifi/model/ht/ht-ppdu.cc
--- ns-3.39/src/wifi/model/ht/ht-ppdu.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/ht/ht-ppdu.cc	2023-09-27 13:30:37.906839800 -0700
@@ -109,7 +109,7 @@
 Time
 HtPpdu::GetTxDuration() const
 {
-    const WifiTxVector& txVector = GetTxVector();
+    const auto& txVector = GetTxVector();
     const auto htLength = m_htSig.GetHtLength();
     NS_ASSERT(m_operatingChannel.IsSet());
     return WifiPhy::CalculateTxDuration(htLength, txVector, m_operatingChannel.GetPhyBand());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/interference-helper.cc ns-3.40/src/wifi/model/interference-helper.cc
--- ns-3.39/src/wifi/model/interference-helper.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/interference-helper.cc	2023-09-27 13:30:37.906839800 -0700
@@ -21,14 +21,15 @@
 #include "interference-helper.h"
 
 #include "error-rate-model.h"
+#include "wifi-phy-operating-channel.h"
 #include "wifi-phy.h"
 #include "wifi-psdu.h"
 #include "wifi-utils.h"
 
+#include "ns3/he-ppdu.h"
 #include "ns3/log.h"
 #include "ns3/packet.h"
 #include "ns3/simulator.h"
-#include "ns3/wifi-phy-operating-channel.h"
 
 #include <algorithm>
 #include <numeric>
@@ -44,12 +45,8 @@
  *       PHY event class
  ****************************************************************/
 
-Event::Event(Ptr<const WifiPpdu> ppdu,
-             const WifiTxVector& txVector,
-             Time duration,
-             RxPowerWattPerChannelBand&& rxPower)
+Event::Event(Ptr<const WifiPpdu> ppdu, Time duration, RxPowerWattPerChannelBand&& rxPower)
     : m_ppdu(ppdu),
-      m_txVector(txVector),
       m_startTime(Simulator::Now()),
       m_endTime(m_startTime + duration),
       m_rxPowerW(std::move(rxPower))
@@ -112,12 +109,6 @@
     return m_rxPowerW;
 }
 
-const WifiTxVector&
-Event::GetTxVector() const
-{
-    return m_txVector;
-}
-
 void
 Event::UpdateRxPowerW(const RxPowerWattPerChannelBand& rxPower)
 {
@@ -134,11 +125,17 @@
     }
 }
 
+void
+Event::UpdatePpdu(Ptr<const WifiPpdu> ppdu)
+{
+    m_ppdu = ppdu;
+}
+
 std::ostream&
 operator<<(std::ostream& os, const Event& event)
 {
     os << "start=" << event.GetStartTime() << ", end=" << event.GetEndTime()
-       << ", TXVECTOR=" << event.GetTxVector() << ", power=" << event.GetRxPowerW() << "W"
+       << ", power=" << event.GetRxPowerW() << "W"
        << ", PPDU=" << event.GetPpdu();
     return os;
 }
@@ -219,13 +216,12 @@
 
 Ptr<Event>
 InterferenceHelper::Add(Ptr<const WifiPpdu> ppdu,
-                        const WifiTxVector& txVector,
                         Time duration,
                         RxPowerWattPerChannelBand& rxPowerW,
-                        bool isStartOfdmaRxing)
+                        bool isStartHePortionRxing)
 {
-    Ptr<Event> event = Create<Event>(ppdu, txVector, duration, std::move(rxPowerW));
-    AppendEvent(event, isStartOfdmaRxing);
+    Ptr<Event> event = Create<Event>(ppdu, duration, std::move(rxPowerW));
+    AppendEvent(event, isStartHePortionRxing);
     return event;
 }
 
@@ -240,7 +236,7 @@
     Ptr<WifiPpdu> fakePpdu = Create<WifiPpdu>(Create<WifiPsdu>(Create<Packet>(0), hdr),
                                               WifiTxVector(),
                                               WifiPhyOperatingChannel());
-    Add(fakePpdu, WifiTxVector(), duration, rxPowerW);
+    Add(fakePpdu, duration, rxPowerW);
 }
 
 bool
@@ -354,9 +350,9 @@
 }
 
 void
-InterferenceHelper::AppendEvent(Ptr<Event> event, bool isStartOfdmaRxing)
+InterferenceHelper::AppendEvent(Ptr<Event> event, bool isStartHePortionRxing)
 {
-    NS_LOG_FUNCTION(this << event << isStartOfdmaRxing);
+    NS_LOG_FUNCTION(this << event << isStartHePortionRxing);
     for (const auto& [band, power] : event->GetRxPowerWPerBand())
     {
         auto niIt = m_niChanges.find(band);
@@ -372,11 +368,11 @@
             // Always leave the first zero power noise event in the list
             niIt->second.erase(++(niIt->second.begin()), ++previousPowerPosition);
         }
-        else if (isStartOfdmaRxing)
+        else if (isStartHePortionRxing)
         {
-            // When the first UL-OFDMA payload is received, we need to set m_firstPowers
+            // When the first HE portion is received, we need to set m_firstPowerPerBand
             // so that it takes into account interferences that arrived between the start of the
-            // UL MU transmission and the start of UL-OFDMA payload.
+            // HE TB PPDU transmission and the start of HE TB payload.
             m_firstPowers.find(band)->second = previousPowerStart;
         }
         auto first =
@@ -442,7 +438,7 @@
 
 double
 InterferenceHelper::CalculateNoiseInterferenceW(Ptr<Event> event,
-                                                NiChangesPerBand* nis,
+                                                NiChangesPerBand& nis,
                                                 const WifiSpectrumBandInfo& band) const
 {
     NS_LOG_FUNCTION(this << band);
@@ -452,9 +448,24 @@
     auto niIt = m_niChanges.find(band);
     NS_ABORT_IF(niIt == m_niChanges.end());
     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)
     {
-        noiseInterferenceW = it->second.GetPower() - event->GetRxPowerW(band);
+        if (IsSameMuMimoTransmission(event, it->second.GetEvent()) &&
+            (event != it->second.GetEvent()))
+        {
+            // Do not calculate noiseInterferenceW if events belong to the same MU-MIMO transmission
+            // unless this is the same event
+            continue;
+        }
+        noiseInterferenceW = it->second.GetPower() - event->GetRxPowerW(band) - muMimoPowerW;
+        if (std::abs(noiseInterferenceW) < std::numeric_limits<double>::epsilon())
+        {
+            // fix some possible rounding issues with double values
+            noiseInterferenceW = 0.0;
+        }
     }
     it = niIt->second.find(event->GetStartTime());
     NS_ABORT_IF(it == niIt->second.end());
@@ -469,13 +480,50 @@
         ni.insert(*it);
     }
     ni.emplace(event->GetEndTime(), NiChange(0, event));
-    nis->insert({band, ni});
-    NS_ASSERT_MSG(noiseInterferenceW >= 0,
+    nis.insert({band, ni});
+    NS_ASSERT_MSG(noiseInterferenceW >= 0.0,
                   "CalculateNoiseInterferenceW returns negative value " << noiseInterferenceW);
     return noiseInterferenceW;
 }
 
 double
+InterferenceHelper::CalculateMuMimoPowerW(Ptr<const Event> event,
+                                          const WifiSpectrumBandInfo& band) const
+{
+    auto niIt = m_niChanges.find(band);
+    NS_ASSERT(niIt != m_niChanges.end());
+    auto it = niIt->second.begin();
+    ++it;
+    double muMimoPowerW = 0.0;
+    for (; it != niIt->second.end() && it->first < Simulator::Now(); ++it)
+    {
+        if (IsSameMuMimoTransmission(event, it->second.GetEvent()))
+        {
+            auto hePpdu = DynamicCast<HePpdu>(it->second.GetEvent()->GetPpdu()->Copy());
+            NS_ASSERT(hePpdu);
+            HePpdu::TxPsdFlag psdFlag = hePpdu->GetTxPsdFlag();
+            if (psdFlag == HePpdu::PSD_HE_PORTION)
+            {
+                const auto staId =
+                    event->GetPpdu()->GetTxVector().GetHeMuUserInfoMap().cbegin()->first;
+                const auto otherStaId = it->second.GetEvent()
+                                            ->GetPpdu()
+                                            ->GetTxVector()
+                                            .GetHeMuUserInfoMap()
+                                            .cbegin()
+                                            ->first;
+                if (staId == otherStaId)
+                {
+                    break;
+                }
+                muMimoPowerW += it->second.GetEvent()->GetRxPowerW(band);
+            }
+        }
+    }
+    return muMimoPowerW;
+}
+
+double
 InterferenceHelper::CalculateChunkSuccessRate(double snir,
                                               Time duration,
                                               WifiMode mode,
@@ -487,7 +535,7 @@
         return 1.0;
     }
     uint64_t rate = mode.GetDataRate(txVector.GetChannelWidth());
-    uint64_t nbits = static_cast<uint64_t>(rate * duration.GetSeconds());
+    auto nbits = static_cast<uint64_t>(rate * duration.GetSeconds());
     double csr =
         m_errorRateModel->GetChunkSuccessRate(mode, txVector, snir, nbits, m_numRxAntennas, field);
     return csr;
@@ -505,7 +553,7 @@
     }
     WifiMode mode = txVector.GetMode(staId);
     uint64_t rate = mode.GetDataRate(txVector, staId);
-    uint64_t nbits = static_cast<uint64_t>(rate * duration.GetSeconds());
+    auto nbits = static_cast<uint64_t>(rate * duration.GetSeconds());
     nbits /= txVector.GetNss(staId); // divide effective number of bits by NSS to achieve same chunk
                                      // error rate as SISO for AWGN
     double csr = m_errorRateModel->GetChunkSuccessRate(mode,
@@ -531,14 +579,19 @@
     const auto& niIt = nis->find(band)->second;
     auto j = niIt.cbegin();
     Time previous = j->first;
-    WifiMode payloadMode = event->GetTxVector().GetMode(staId);
+    double muMimoPowerW = 0.0;
+    WifiMode payloadMode = event->GetPpdu()->GetTxVector().GetMode(staId);
     Time phyPayloadStart = j->first;
     if (event->GetPpdu()->GetType() != WIFI_PPDU_TYPE_UL_MU &&
         event->GetPpdu()->GetType() !=
-            WIFI_PPDU_TYPE_DL_MU) // j->first corresponds to the start of the OFDMA payload
+            WIFI_PPDU_TYPE_DL_MU) // j->first corresponds to the start of the MU payload
+    {
+        phyPayloadStart = j->first + WifiPhy::CalculatePhyPreambleAndHeaderDuration(
+                                         event->GetPpdu()->GetTxVector());
+    }
+    else
     {
-        phyPayloadStart =
-            j->first + WifiPhy::CalculatePhyPreambleAndHeaderDuration(event->GetTxVector());
+        muMimoPowerW = CalculateMuMimoPowerW(event, band);
     }
     Time windowStart = phyPayloadStart + window.first;
     Time windowEnd = phyPayloadStart + window.second;
@@ -553,13 +606,13 @@
         double snr = CalculateSnr(powerW,
                                   noiseInterferenceW,
                                   channelWidth,
-                                  event->GetTxVector().GetNss(staId));
+                                  event->GetPpdu()->GetTxVector().GetNss(staId));
         // Case 1: Both previous and current point to the windowed payload
         if (previous >= windowStart)
         {
             psr *= CalculatePayloadChunkSuccessRate(snr,
                                                     Min(windowEnd, current) - previous,
-                                                    event->GetTxVector(),
+                                                    event->GetPpdu()->GetTxVector(),
                                                     staId);
             NS_LOG_DEBUG("Both previous and current point to the windowed payload: mode="
                          << payloadMode << ", psr=" << psr);
@@ -569,13 +622,20 @@
         {
             psr *= CalculatePayloadChunkSuccessRate(snr,
                                                     Min(windowEnd, current) - windowStart,
-                                                    event->GetTxVector(),
+                                                    event->GetPpdu()->GetTxVector(),
                                                     staId);
             NS_LOG_DEBUG(
                 "previous is before windowed payload and current is in the windowed payload: mode="
                 << payloadMode << ", psr=" << psr);
         }
         noiseInterferenceW = j->second.GetPower() - powerW;
+        if (IsSameMuMimoTransmission(event, j->second.GetEvent()))
+        {
+            muMimoPowerW += j->second.GetEvent()->GetRxPowerW(band);
+            NS_LOG_DEBUG(
+                "PPDU belongs to same MU-MIMO transmission: muMimoPowerW=" << muMimoPowerW);
+        }
+        noiseInterferenceW -= muMimoPowerW;
         previous = j->first;
         if (previous > windowEnd)
         {
@@ -631,7 +691,7 @@
                     psr *= CalculateChunkSuccessRate(snr,
                                                      duration,
                                                      section.second.second,
-                                                     event->GetTxVector(),
+                                                     event->GetPpdu()->GetTxVector(),
                                                      section.first);
                     NS_LOG_DEBUG("Current NI change in "
                                  << section.first << " [" << start << ", " << stop << "] for "
@@ -661,11 +721,12 @@
 {
     NS_LOG_FUNCTION(this << band << header);
     auto niIt = nis->find(band)->second;
-    auto phyEntity = WifiPhy::GetStaticPhyEntity(event->GetTxVector().GetModulationClass());
+    auto phyEntity =
+        WifiPhy::GetStaticPhyEntity(event->GetPpdu()->GetTxVector().GetModulationClass());
 
     PhyEntity::PhyHeaderSections sections;
     for (const auto& section :
-         phyEntity->GetPhyHeaderSections(event->GetTxVector(), niIt.begin()->first))
+         phyEntity->GetPhyHeaderSections(event->GetPpdu()->GetTxVector(), niIt.begin()->first))
     {
         if (section.first == header)
         {
@@ -691,11 +752,11 @@
     NS_LOG_FUNCTION(this << channelWidth << band << staId << relativeMpduStartStop.first
                          << relativeMpduStartStop.second);
     NiChangesPerBand ni;
-    double noiseInterferenceW = CalculateNoiseInterferenceW(event, &ni, band);
+    double noiseInterferenceW = CalculateNoiseInterferenceW(event, ni, band);
     double snr = CalculateSnr(event->GetRxPowerW(band),
                               noiseInterferenceW,
                               channelWidth,
-                              event->GetTxVector().GetNss(staId));
+                              event->GetPpdu()->GetTxVector().GetNss(staId));
 
     /* calculate the SNIR at the start of the MPDU (located through windowing) and accumulate
      * all SNIR changes in the SNIR vector.
@@ -712,7 +773,7 @@
                                  const WifiSpectrumBandInfo& band) const
 {
     NiChangesPerBand ni;
-    double noiseInterferenceW = CalculateNoiseInterferenceW(event, &ni, band);
+    double noiseInterferenceW = CalculateNoiseInterferenceW(event, ni, band);
     double snr = CalculateSnr(event->GetRxPowerW(band), noiseInterferenceW, channelWidth, nss);
     return snr;
 }
@@ -725,7 +786,7 @@
 {
     NS_LOG_FUNCTION(this << band << header);
     NiChangesPerBand ni;
-    double noiseInterferenceW = CalculateNoiseInterferenceW(event, &ni, band);
+    double noiseInterferenceW = CalculateNoiseInterferenceW(event, ni, band);
     double snr = CalculateSnr(event->GetRxPowerW(band), noiseInterferenceW, channelWidth, 1);
 
     /* calculate the SNIR at the start of the PHY header and accumulate
@@ -792,4 +853,23 @@
             (band.frequencies.first < (freqRange.maxFrequency * 1e6)));
 }
 
+bool
+InterferenceHelper::IsSameMuMimoTransmission(Ptr<const Event> currentEvent,
+                                             Ptr<const Event> otherEvent) const
+{
+    if ((currentEvent->GetPpdu()->GetType() == WIFI_PPDU_TYPE_UL_MU) &&
+        (otherEvent->GetPpdu()->GetType() == WIFI_PPDU_TYPE_UL_MU) &&
+        (currentEvent->GetPpdu()->GetUid() == otherEvent->GetPpdu()->GetUid()))
+    {
+        const auto currentTxVector = currentEvent->GetPpdu()->GetTxVector();
+        const auto otherTxVector = otherEvent->GetPpdu()->GetTxVector();
+        NS_ASSERT(currentTxVector.GetHeMuUserInfoMap().size() == 1);
+        NS_ASSERT(otherTxVector.GetHeMuUserInfoMap().size() == 1);
+        const auto currentUserInfo = currentTxVector.GetHeMuUserInfoMap().cbegin();
+        const auto otherUserInfo = otherTxVector.GetHeMuUserInfoMap().cbegin();
+        return (currentUserInfo->second.ru == otherUserInfo->second.ru);
+    }
+    return false;
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/interference-helper.h ns-3.40/src/wifi/model/interference-helper.h
--- ns-3.39/src/wifi/model/interference-helper.h	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/interference-helper.h	2023-09-27 13:30:37.906839800 -0700
@@ -44,14 +44,10 @@
      * be moved into this object.
      *
      * \param ppdu the PPDU
-     * \param txVector the TXVECTOR
      * \param duration duration of the PPDU
      * \param rxPower the received power per band (W)
      */
-    Event(Ptr<const WifiPpdu> ppdu,
-          const WifiTxVector& txVector,
-          Time duration,
-          RxPowerWattPerChannelBand&& rxPower);
+    Event(Ptr<const WifiPpdu> ppdu, Time duration, RxPowerWattPerChannelBand&& rxPower);
     ~Event();
 
     /**
@@ -98,22 +94,24 @@
      */
     const RxPowerWattPerChannelBand& GetRxPowerWPerBand() const;
     /**
-     * Return the TXVECTOR of the PPDU.
-     *
-     * \return the TXVECTOR of the PPDU
-     */
-    const WifiTxVector& GetTxVector() const;
-    /**
      * Update the received power (W) for all bands, i.e. add up the received power
      * to the current received power, for each band.
      *
      * \param rxPower the received power (W) for all bands.
      */
     void UpdateRxPowerW(const RxPowerWattPerChannelBand& rxPower);
+    /**
+     * Update the PPDU that initially generated the event.
+     * This is needed to have the PPDU holding the correct TXVECTOR
+     * upon reception of multiple signals carring the same content
+     * but over different channel width (typically non-HT duplicates).
+     *
+     * \param ppdu the new PPDU to use for this event.
+     */
+    void UpdatePpdu(Ptr<const WifiPpdu> ppdu);
 
   private:
     Ptr<const WifiPpdu> m_ppdu;           //!< PPDU
-    WifiTxVector m_txVector;              //!< TXVECTOR
     Time m_startTime;                     //!< start time
     Time m_endTime;                       //!< end time
     RxPowerWattPerChannelBand m_rxPowerW; //!< received power in watts per band
@@ -209,20 +207,17 @@
      * Add the PPDU-related signal to interference helper.
      *
      * \param ppdu the PPDU
-     * \param txVector the TXVECTOR
      * \param duration the PPDU duration
      * \param rxPower received power per band (W)
-     * \param isStartOfdmaRxing flag whether the event corresponds to the start of the OFDMA payload
-     * reception (only used for UL-OFDMA) //TODO simplify this once WifiPpdu is subclassed by adding
-     * an attribute
+     * \param isStartHePortionRxing flag whether the event corresponds to the start of the HE
+     * portion reception (only used for MU)
      *
      * \return Event
      */
     Ptr<Event> Add(Ptr<const WifiPpdu> ppdu,
-                   const WifiTxVector& txVector,
                    Time duration,
                    RxPowerWattPerChannelBand& rxPower,
-                   bool isStartOfdmaRxing = false);
+                   bool isStartHePortionRxing = false);
 
     /**
      * Add a non-Wifi signal to interference helper.
@@ -428,10 +423,10 @@
      * Append the given Event.
      *
      * \param event the event to be appended
-     * \param isStartOfdmaRxing flag whether event corresponds to the start of the OFDMA payload
-     * reception (only used for UL-OFDMA)
+     * \param isStartHePortionRxing flag whether event corresponds to the start of the HE portion
+     * reception (only used for MU)
      */
-    void AppendEvent(Ptr<Event> event, bool isStartOfdmaRxing);
+    void AppendEvent(Ptr<Event> event, bool isStartHePortionRxing);
 
     /**
      * Calculate noise and interference power in W.
@@ -443,8 +438,21 @@
      * \return noise and interference power
      */
     double CalculateNoiseInterferenceW(Ptr<Event> event,
-                                       NiChangesPerBand* nis,
+                                       NiChangesPerBand& nis,
                                        const WifiSpectrumBandInfo& band) const;
+
+    /**
+     * Calculate power of all other events preceding a given event that belong to the same MU-MIMO
+     * transmission.
+     *
+     * \param event the event
+     * \param band the band
+     *
+     * \return the power of all other events preceding the event that belong to the same MU-MIMO
+     * transmission
+     */
+    double CalculateMuMimoPowerW(Ptr<const Event> event, const WifiSpectrumBandInfo& band) const;
+
     /**
      * Calculate the error rate of the given PHY payload only in the provided time
      * window (thus enabling per MPDU PER information). The PHY payload can be divided into
@@ -535,6 +543,17 @@
     NiChanges::iterator AddNiChangeEvent(Time moment,
                                          NiChange change,
                                          NiChangesPerBand::iterator niIt);
+
+    /**
+     * Return whether another event is a MU-MIMO event that belongs to the same transmission and to
+     * the same RU.
+     *
+     * \param currentEvent the current event that is being inspected
+     * \param otherEvent the other event to compare against
+     *
+     * \return whether both events belong to the same transmission and to the same RU
+     */
+    bool IsSameMuMimoTransmission(Ptr<const Event> currentEvent, Ptr<const Event> otherEvent) const;
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/mac-rx-middle.cc ns-3.40/src/wifi/model/mac-rx-middle.cc
--- ns-3.39/src/wifi/model/mac-rx-middle.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/mac-rx-middle.cc	2023-09-27 13:30:37.906839800 -0700
@@ -103,7 +103,7 @@
         m_fragments.push_back(packet);
         m_defragmenting = false;
         Ptr<Packet> full = Create<Packet>();
-        for (FragmentsCI i = m_fragments.begin(); i != m_fragments.end(); i++)
+        for (auto i = m_fragments.begin(); i != m_fragments.end(); i++)
         {
             full->AddAtEnd(*i);
         }
@@ -167,12 +167,12 @@
 MacRxMiddle::~MacRxMiddle()
 {
     NS_LOG_FUNCTION_NOARGS();
-    for (OriginatorsI i = m_originatorStatus.begin(); i != m_originatorStatus.end(); i++)
+    for (auto i = m_originatorStatus.begin(); i != m_originatorStatus.end(); i++)
     {
         delete (*i).second;
     }
     m_originatorStatus.erase(m_originatorStatus.begin(), m_originatorStatus.end());
-    for (QosOriginatorsI i = m_qosOriginatorStatus.begin(); i != m_qosOriginatorStatus.end(); i++)
+    for (auto i = m_qosOriginatorStatus.begin(); i != m_qosOriginatorStatus.end(); i++)
     {
         delete (*i).second;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/mac-rx-middle.h ns-3.40/src/wifi/model/mac-rx-middle.h
--- ns-3.39/src/wifi/model/mac-rx-middle.h	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/mac-rx-middle.h	2023-09-27 13:30:37.906839800 -0700
@@ -111,25 +111,21 @@
     /**
      * typedef for a map between address and OriginatorRxStatus
      */
-    typedef std::map<Mac48Address, OriginatorRxStatus*, std::less<Mac48Address>> Originators;
+    typedef std::map<Mac48Address, OriginatorRxStatus*, std::less<>> Originators;
     /**
      * typedef for a map between address, OriginatorRxStatus, and Traffic ID
      */
-    typedef std::map<std::pair<Mac48Address, uint8_t>,
-                     OriginatorRxStatus*,
-                     std::less<std::pair<Mac48Address, uint8_t>>>
+    typedef std::map<std::pair<Mac48Address, uint8_t>, OriginatorRxStatus*, std::less<>>
         QosOriginators;
     /**
      * typedef for an iterator for Originators
      */
-    typedef std::map<Mac48Address, OriginatorRxStatus*, std::less<Mac48Address>>::iterator
-        OriginatorsI;
+    typedef std::map<Mac48Address, OriginatorRxStatus*, std::less<>>::iterator OriginatorsI;
     /**
      * typedef for an iterator for QosOriginators
      */
-    typedef std::map<std::pair<Mac48Address, uint8_t>,
-                     OriginatorRxStatus*,
-                     std::less<std::pair<Mac48Address, uint8_t>>>::iterator QosOriginatorsI;
+    typedef std::map<std::pair<Mac48Address, uint8_t>, OriginatorRxStatus*, std::less<>>::iterator
+        QosOriginatorsI;
 
     Originators m_originatorStatus;       ///< originator status
     QosOriginators m_qosOriginatorStatus; ///< QOS originator status
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/mac-tx-middle.cc ns-3.40/src/wifi/model/mac-tx-middle.cc
--- ns-3.39/src/wifi/model/mac-tx-middle.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/mac-tx-middle.cc	2023-09-27 13:30:37.906839800 -0700
@@ -40,9 +40,7 @@
 MacTxMiddle::~MacTxMiddle()
 {
     NS_LOG_FUNCTION(this);
-    for (std::map<Mac48Address, uint16_t*>::const_iterator i = m_qosSequences.begin();
-         i != m_qosSequences.end();
-         i++)
+    for (auto i = m_qosSequences.begin(); i != m_qosSequences.end(); i++)
     {
         delete[] i->second;
     }
@@ -57,7 +55,7 @@
     {
         uint8_t tid = hdr->GetQosTid();
         NS_ASSERT(tid < 16);
-        std::map<Mac48Address, uint16_t*>::const_iterator it = m_qosSequences.find(hdr->GetAddr1());
+        auto it = m_qosSequences.find(hdr->GetAddr1());
         if (it != m_qosSequences.end())
         {
             retval = it->second[tid];
@@ -68,8 +66,7 @@
         {
             retval = 0;
             std::pair<Mac48Address, uint16_t*> newSeq(hdr->GetAddr1(), new uint16_t[16]);
-            std::pair<std::map<Mac48Address, uint16_t*>::const_iterator, bool> newIns =
-                m_qosSequences.insert(newSeq);
+            auto newIns = m_qosSequences.insert(newSeq);
             NS_ASSERT(newIns.second == true);
             for (uint8_t i = 0; i < 16; i++)
             {
@@ -96,7 +93,7 @@
     {
         uint8_t tid = hdr->GetQosTid();
         NS_ASSERT(tid < 16);
-        std::map<Mac48Address, uint16_t*>::const_iterator it = m_qosSequences.find(hdr->GetAddr1());
+        auto it = m_qosSequences.find(hdr->GetAddr1());
         if (it != m_qosSequences.end())
         {
             retval = it->second[tid];
@@ -119,7 +116,7 @@
     NS_LOG_FUNCTION(this);
     NS_ASSERT(tid < 16);
     uint16_t seq = 0;
-    std::map<Mac48Address, uint16_t*>::const_iterator it = m_qosSequences.find(addr);
+    auto it = m_qosSequences.find(addr);
     if (it != m_qosSequences.end())
     {
         return it->second[tid];
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/mgt-headers.cc ns-3.40/src/wifi/model/mgt-headers.cc
--- ns-3.39/src/wifi/model/mgt-headers.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/mgt-headers.cc	2023-09-27 13:30:37.906839800 -0700
@@ -1688,7 +1688,7 @@
 MgtDelBaHeader::GetTid() const
 {
     NS_ASSERT(m_tid < 16);
-    uint8_t tid = static_cast<uint8_t>(m_tid);
+    auto tid = static_cast<uint8_t>(m_tid);
     return tid;
 }
 
@@ -1731,26 +1731,26 @@
  *     EMLSR Operating Mode Notification
  ****************************************************/
 
-NS_OBJECT_ENSURE_REGISTERED(MgtEmlOperatingModeNotification);
+NS_OBJECT_ENSURE_REGISTERED(MgtEmlOmn);
 
 TypeId
-MgtEmlOperatingModeNotification::GetTypeId()
+MgtEmlOmn::GetTypeId()
 {
     static TypeId tid = TypeId("ns3::MgtEmlOperatingModeNotification")
                             .SetParent<Header>()
                             .SetGroupName("Wifi")
-                            .AddConstructor<MgtEmlOperatingModeNotification>();
+                            .AddConstructor<MgtEmlOmn>();
     return tid;
 }
 
 TypeId
-MgtEmlOperatingModeNotification::GetInstanceTypeId() const
+MgtEmlOmn::GetInstanceTypeId() const
 {
     return GetTypeId();
 }
 
 void
-MgtEmlOperatingModeNotification::Print(std::ostream& os) const
+MgtEmlOmn::Print(std::ostream& os) const
 {
     os << "EMLSR Mode=" << +m_emlControl.emlsrMode << " EMLMR Mode=" << +m_emlControl.emlmrMode
        << " EMLSR Parameter Update Control=" << +m_emlControl.emlsrParamUpdateCtrl;
@@ -1770,7 +1770,7 @@
 }
 
 uint32_t
-MgtEmlOperatingModeNotification::GetSerializedSize() const
+MgtEmlOmn::GetSerializedSize() const
 {
     uint32_t size = 2; // Dialog Token (1) + first byte of EML Control
     if (m_emlControl.linkBitmap)
@@ -1790,7 +1790,7 @@
 }
 
 void
-MgtEmlOperatingModeNotification::Serialize(Buffer::Iterator start) const
+MgtEmlOmn::Serialize(Buffer::Iterator start) const
 {
     start.WriteU8(m_dialogToken);
 
@@ -1825,7 +1825,7 @@
 }
 
 uint32_t
-MgtEmlOperatingModeNotification::Deserialize(Buffer::Iterator start)
+MgtEmlOmn::Deserialize(Buffer::Iterator start)
 {
     Buffer::Iterator i = start;
 
@@ -1858,7 +1858,7 @@
 }
 
 void
-MgtEmlOperatingModeNotification::SetLinkIdInBitmap(uint8_t linkId)
+MgtEmlOmn::SetLinkIdInBitmap(uint8_t linkId)
 {
     NS_ABORT_MSG_IF(linkId > 15, "Link ID must not exceed 15");
     if (!m_emlControl.linkBitmap)
@@ -1869,7 +1869,7 @@
 }
 
 std::list<uint8_t>
-MgtEmlOperatingModeNotification::GetLinkBitmap() const
+MgtEmlOmn::GetLinkBitmap() const
 {
     std::list<uint8_t> list;
     NS_ASSERT_MSG(m_emlControl.linkBitmap.has_value(), "No link bitmap");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/mgt-headers.h ns-3.40/src/wifi/model/mgt-headers.h
--- ns-3.39/src/wifi/model/mgt-headers.h	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/mgt-headers.h	2023-09-27 13:30:37.910839800 -0700
@@ -121,7 +121,7 @@
                                       std::optional<MultiLinkElement>,
                                       std::optional<EhtCapabilities>,
                                       std::optional<EhtOperation>,
-                                      std::optional<TidToLinkMapping>>;
+                                      std::vector<TidToLinkMapping>>;
 
 /// List of Information Elements included in Association Request frames
 using AssocRequestElems = std::tuple<Ssid,
@@ -133,7 +133,7 @@
                                      std::optional<HeCapabilities>,
                                      std::optional<MultiLinkElement>,
                                      std::optional<EhtCapabilities>,
-                                     std::optional<TidToLinkMapping>>;
+                                     std::vector<TidToLinkMapping>>;
 
 /// List of Information Elements included in Association Response frames
 using AssocResponseElems = std::tuple<SupportedRates,
@@ -150,7 +150,7 @@
                                       std::optional<MultiLinkElement>,
                                       std::optional<EhtCapabilities>,
                                       std::optional<EhtOperation>,
-                                      std::optional<TidToLinkMapping>>;
+                                      std::vector<TidToLinkMapping>>;
 
 /**
  * \ingroup wifi
@@ -1109,10 +1109,10 @@
  * \ingroup wifi
  * Implement the header for Action frames of type EML Operating Mode Notification.
  */
-class MgtEmlOperatingModeNotification : public Header
+class MgtEmlOmn : public Header
 {
   public:
-    MgtEmlOperatingModeNotification() = default;
+    MgtEmlOmn() = default;
 
     /**
      * Register this type.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/mpdu-aggregator.cc ns-3.40/src/wifi/model/mpdu-aggregator.cc
--- ns-3.39/src/wifi/model/mpdu-aggregator.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/mpdu-aggregator.cc	2023-09-27 13:30:37.910839800 -0700
@@ -195,7 +195,7 @@
     hdr.SetLength(mpduSize);
     if (isSingle)
     {
-        hdr.SetEof(1);
+        hdr.SetEof(true);
     }
     return hdr;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/non-ht/dsss-phy.cc ns-3.40/src/wifi/model/non-ht/dsss-phy.cc
--- ns-3.39/src/wifi/model/non-ht/dsss-phy.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/non-ht/dsss-phy.cc	2023-09-27 13:30:37.910839800 -0700
@@ -380,7 +380,7 @@
         NS_FATAL_ERROR("Incorrect modulation class, must specify either WIFI_MOD_CLASS_DSSS or "
                        "WIFI_MOD_CLASS_HR_DSSS!");
     }
-    uint16_t numberOfBitsPerSubcarrier = static_cast<uint16_t>(log2(constellationSize));
+    auto numberOfBitsPerSubcarrier = static_cast<uint16_t>(log2(constellationSize));
     uint64_t dataRate = ((11000000 / divisor) * numberOfBitsPerSubcarrier);
     return dataRate;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/non-ht/dsss-ppdu.cc ns-3.40/src/wifi/model/non-ht/dsss-ppdu.cc
--- ns-3.39/src/wifi/model/non-ht/dsss-ppdu.cc	2023-07-05 14:23:48.113428400 -0700
+++ ns-3.40/src/wifi/model/non-ht/dsss-ppdu.cc	2023-09-27 13:30:37.910839800 -0700
@@ -80,7 +80,7 @@
 Time
 DsssPpdu::GetTxDuration() const
 {
-    const WifiTxVector& txVector = GetTxVector();
+    const auto& txVector = GetTxVector();
     const auto length = m_dsssSig.GetLength();
     return (MicroSeconds(length) + WifiPhy::CalculatePhyPreambleAndHeaderDuration(txVector));
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/non-ht/ofdm-phy.cc ns-3.40/src/wifi/model/non-ht/ofdm-phy.cc
--- ns-3.39/src/wifi/model/non-ht/ofdm-phy.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/non-ht/ofdm-phy.cc	2023-09-27 13:30:37.910839800 -0700
@@ -684,6 +684,25 @@
     return PhyEntity::GetCcaThreshold(ppdu, channelType);
 }
 
+Ptr<const WifiPpdu>
+OfdmPhy::GetRxPpduFromTxPpdu(Ptr<const WifiPpdu> ppdu)
+{
+    const auto txWidth = ppdu->GetTxChannelWidth();
+    const auto& txVector = ppdu->GetTxVector();
+    // Update channel width in TXVECTOR for non-HT duplicate PPDUs.
+    if ((txVector.IsNonHtDuplicate() && (txWidth > m_wifiPhy->GetChannelWidth())))
+    {
+        // We also do a copy of the PPDU for non-HT duplicate PPDUs since other
+        // PHYs might set a different channel width in the reconstructed TXVECTOR.
+        auto rxPpdu = ppdu->Copy();
+        auto updatedTxVector = txVector;
+        updatedTxVector.SetChannelWidth(std::min(txWidth, m_wifiPhy->GetChannelWidth()));
+        rxPpdu->UpdateTxVector(updatedTxVector);
+        return rxPpdu;
+    }
+    return PhyEntity::GetRxPpduFromTxPpdu(ppdu);
+}
+
 } // namespace ns3
 
 namespace
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/non-ht/ofdm-phy.h ns-3.40/src/wifi/model/non-ht/ofdm-phy.h
--- ns-3.39/src/wifi/model/non-ht/ofdm-phy.h	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/non-ht/ofdm-phy.h	2023-09-27 13:30:37.910839800 -0700
@@ -89,6 +89,7 @@
                             Time ppduDuration) override;
     double GetCcaThreshold(const Ptr<const WifiPpdu> ppdu,
                            WifiChannelListType channelType) const override;
+    Ptr<const WifiPpdu> GetRxPpduFromTxPpdu(Ptr<const WifiPpdu> ppdu) override;
 
     /**
      * Initialize all OFDM modes (for all variants).
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/non-ht/ofdm-ppdu.cc ns-3.40/src/wifi/model/non-ht/ofdm-ppdu.cc
--- ns-3.39/src/wifi/model/non-ht/ofdm-ppdu.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/non-ht/ofdm-ppdu.cc	2023-09-27 13:30:37.910839800 -0700
@@ -83,7 +83,7 @@
 Time
 OfdmPpdu::GetTxDuration() const
 {
-    const WifiTxVector& txVector = GetTxVector();
+    const auto& txVector = GetTxVector();
     const auto length = m_lSig.GetLength();
     NS_ASSERT(m_operatingChannel.IsSet());
     return WifiPhy::CalculateTxDuration(length, txVector, m_operatingChannel.GetPhyBand());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/phy-entity.cc ns-3.40/src/wifi/model/phy-entity.cc
--- ns-3.39/src/wifi/model/phy-entity.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/phy-entity.cc	2023-09-27 13:30:37.910839800 -0700
@@ -295,7 +295,7 @@
     NS_ABORT_MSG_IF(!supported,
                     "Unknown field "
                         << field << " for this PHY entity"); // TODO see what to do if not supported
-    Time duration = GetDuration(field, event->GetTxVector());
+    Time duration = GetDuration(field, event->GetPpdu()->GetTxVector());
     m_wifiPhy->m_endPhyRxEvent =
         Simulator::Schedule(duration, &PhyEntity::EndReceiveField, this, field, event);
     m_wifiPhy->NotifyCcaBusy(
@@ -310,7 +310,7 @@
     NS_ASSERT(m_wifiPhy); // no sense if no owner WifiPhy instance
     NS_ASSERT(m_wifiPhy->m_endPhyRxEvent.IsExpired());
     PhyFieldRxStatus status = DoEndReceiveField(field, event);
-    WifiTxVector txVector = event->GetTxVector();
+    const auto& txVector = event->GetPpdu()->GetTxVector();
     if (status.isSuccess) // move to next field if reception succeeded
     {
         StartReceiveField(GetNextField(field, txVector.GetPreambleType()), event);
@@ -358,7 +358,7 @@
 Time
 PhyEntity::GetRemainingDurationAfterField(Ptr<const WifiPpdu> ppdu, WifiPpduField field) const
 {
-    const WifiTxVector& txVector = ppdu->GetTxVector();
+    const auto& txVector = ppdu->GetTxVector();
     return ppdu->GetTxDuration() -
            (GetDurationUpToField(field, txVector) + GetDuration(field, txVector));
 }
@@ -586,7 +586,7 @@
     m_signalNoiseMap.insert({std::make_pair(ppdu->GetUid(), staId), SignalNoiseDbm()});
     m_statusPerMpduMap.insert({std::make_pair(ppdu->GetUid(), staId), std::vector<bool>()});
     ScheduleEndOfMpdus(event);
-    const WifiTxVector& txVector = event->GetTxVector();
+    const auto& txVector = event->GetPpdu()->GetTxVector();
     Time payloadDuration = ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(txVector);
     m_wifiPhy->m_phyRxPayloadBeginTrace(
         txVector,
@@ -604,7 +604,7 @@
     NS_LOG_FUNCTION(this << *event);
     Ptr<const WifiPpdu> ppdu = event->GetPpdu();
     Ptr<const WifiPsdu> psdu = GetAddressedPsduInPpdu(ppdu);
-    const WifiTxVector& txVector = event->GetTxVector();
+    const auto& txVector = event->GetPpdu()->GetTxVector();
     uint16_t staId = GetStaId(ppdu);
     Time endOfMpduDuration = NanoSeconds(0);
     Time relativeStart = NanoSeconds(0);
@@ -668,8 +668,8 @@
                      Time mpduDuration)
 {
     NS_LOG_FUNCTION(this << *event << mpduIndex << relativeStart << mpduDuration);
-    Ptr<const WifiPpdu> ppdu = event->GetPpdu();
-    WifiTxVector txVector = event->GetTxVector();
+    const auto ppdu = event->GetPpdu();
+    const auto& txVector = ppdu->GetTxVector();
     uint16_t staId = GetStaId(ppdu);
 
     std::pair<bool, SignalNoiseDbm> rxInfo =
@@ -700,13 +700,14 @@
 void
 PhyEntity::EndReceivePayload(Ptr<Event> event)
 {
-    Ptr<const WifiPpdu> ppdu = event->GetPpdu();
-    WifiTxVector txVector = event->GetTxVector();
-    Time psduDuration = ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(txVector);
+    const auto ppdu = event->GetPpdu();
+    const auto& txVector = ppdu->GetTxVector();
+    const auto psduDuration =
+        ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(txVector);
     NS_LOG_FUNCTION(this << *event << psduDuration);
     NS_ASSERT(event->GetEndTime() == Simulator::Now());
-    uint16_t staId = GetStaId(ppdu);
-    const auto& channelWidthAndBand = GetChannelWidthAndBand(event->GetTxVector(), staId);
+    const auto staId = GetStaId(ppdu);
+    const auto channelWidthAndBand = GetChannelWidthAndBand(txVector, staId);
     double snr = m_wifiPhy->m_interference->CalculateSnr(event,
                                                          channelWidthAndBand.first,
                                                          txVector.GetNss(staId),
@@ -786,7 +787,7 @@
                               Time mpduDuration)
 {
     NS_LOG_FUNCTION(this << *psdu << *event << staId << relativeMpduStart << mpduDuration);
-    const auto& channelWidthAndBand = GetChannelWidthAndBand(event->GetTxVector(), staId);
+    const auto channelWidthAndBand = GetChannelWidthAndBand(event->GetPpdu()->GetTxVector(), staId);
     SnrPer snrPer = m_wifiPhy->m_interference->CalculatePayloadSnrPer(
         event,
         channelWidthAndBand.first,
@@ -794,8 +795,8 @@
         staId,
         std::make_pair(relativeMpduStart, relativeMpduStart + mpduDuration));
 
-    WifiMode mode = event->GetTxVector().GetMode(staId);
-    NS_LOG_DEBUG("rate=" << (mode.GetDataRate(event->GetTxVector(), staId))
+    WifiMode mode = event->GetPpdu()->GetTxVector().GetMode(staId);
+    NS_LOG_DEBUG("rate=" << (mode.GetDataRate(event->GetPpdu()->GetTxVector(), staId))
                          << ", SNR(dB)=" << RatioToDb(snrPer.snr) << ", PER=" << snrPer.per
                          << ", size=" << psdu->GetSize()
                          << ", relativeStart = " << relativeMpduStart.As(Time::NS)
@@ -847,7 +848,6 @@
 Ptr<Event>
 PhyEntity::DoGetEvent(Ptr<const WifiPpdu> ppdu, RxPowerWattPerChannelBand& rxPowersW)
 {
-    Ptr<Event> event;
     // We store all incoming preamble events, and a decision is made at the end of the preamble
     // detection window.
     const auto uidPreamblePair = std::make_pair(ppdu->GetUid(), ppdu->GetPreamble());
@@ -857,29 +857,13 @@
     {
         // received another signal with the same content
         NS_LOG_DEBUG("Received another PPDU for UID " << ppdu->GetUid());
-        event = it->second;
-        const auto maxDelay =
-            m_wifiPhy->GetPhyEntityForPpdu(ppdu)->GetMaxDelayPpduSameUid(ppdu->GetTxVector());
-        if (Simulator::Now() - event->GetStartTime() > maxDelay)
-        {
-            // This PPDU arrived too late to be decoded properly. The PPDU is dropped and added as
-            // interference
-            event = CreateInterferenceEvent(ppdu, ppdu->GetTxDuration(), rxPowersW);
-            NS_LOG_DEBUG("Drop PPDU that arrived too late");
-            m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(ppdu), PPDU_TOO_LATE);
-        }
-        else
-        {
-            // Update received power of the event associated to that transmission
-            UpdateInterferenceEvent(event, rxPowersW);
-        }
+        const auto foundEvent = it->second;
+        HandleRxPpduWithSameContent(foundEvent, ppdu, rxPowersW);
         return nullptr;
     }
-    else
-    {
-        event = CreateInterferenceEvent(ppdu, ppdu->GetTxDuration(), rxPowersW);
-        AddPreambleEvent(event);
-    }
+
+    auto event = CreateInterferenceEvent(ppdu, ppdu->GetTxDuration(), rxPowersW);
+    AddPreambleEvent(event);
     return event;
 }
 
@@ -887,19 +871,41 @@
 PhyEntity::CreateInterferenceEvent(Ptr<const WifiPpdu> ppdu,
                                    Time duration,
                                    RxPowerWattPerChannelBand& rxPower,
-                                   bool isStartOfdmaRxing /* = false */)
+                                   bool isStartHePortionRxing /* = false */)
 {
-    return m_wifiPhy->m_interference->Add(ppdu,
-                                          ppdu->GetTxVector(),
-                                          duration,
-                                          rxPower,
-                                          isStartOfdmaRxing);
+    return m_wifiPhy->m_interference->Add(ppdu, duration, rxPower, isStartHePortionRxing);
 }
 
 void
-PhyEntity::UpdateInterferenceEvent(Ptr<Event> event, const RxPowerWattPerChannelBand& rxPower)
+PhyEntity::HandleRxPpduWithSameContent(Ptr<Event> event,
+                                       Ptr<const WifiPpdu> ppdu,
+                                       RxPowerWattPerChannelBand& rxPower)
 {
+    if (const auto maxDelay =
+            m_wifiPhy->GetPhyEntityForPpdu(ppdu)->GetMaxDelayPpduSameUid(ppdu->GetTxVector());
+        Simulator::Now() - event->GetStartTime() > maxDelay)
+    {
+        // This PPDU arrived too late to be decoded properly. The PPDU is dropped and added as
+        // interference
+        event = CreateInterferenceEvent(ppdu, ppdu->GetTxDuration(), rxPower);
+        NS_LOG_DEBUG("Drop PPDU that arrived too late");
+        m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(ppdu), PPDU_TOO_LATE);
+        return;
+    }
+
+    // Update received power and TXVECTOR of the event associated to that transmission upon
+    // reception of a signal adding up constructively (in case of a UL MU PPDU or non-HT duplicate
+    // PPDU)
     m_wifiPhy->m_interference->UpdateEvent(event, rxPower);
+    const auto& txVector = ppdu->GetTxVector();
+    const auto& eventTxVector = event->GetPpdu()->GetTxVector();
+    auto updatedTxVector{eventTxVector};
+    updatedTxVector.SetChannelWidth(
+        std::max(eventTxVector.GetChannelWidth(), txVector.GetChannelWidth()));
+    if (updatedTxVector.GetChannelWidth() != eventTxVector.GetChannelWidth())
+    {
+        event->UpdatePpdu(ppdu);
+    }
 }
 
 void
@@ -1048,8 +1054,9 @@
         m_wifiPhy->m_timeLastPreambleDetected = Simulator::Now();
 
         // Continue receiving preamble
-        Time durationTillEnd = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, event->GetTxVector()) -
-                               m_wifiPhy->GetPreambleDetectionDuration();
+        Time durationTillEnd =
+            GetDuration(WIFI_PPDU_FIELD_PREAMBLE, event->GetPpdu()->GetTxVector()) -
+            m_wifiPhy->GetPreambleDetectionDuration();
         m_wifiPhy->NotifyCcaBusy(event->GetPpdu(),
                                  durationTillEnd); // will be prolonged by next field
         m_wifiPhy->m_endPhyRxEvent = Simulator::Schedule(durationTillEnd,
@@ -1333,8 +1340,6 @@
     txParams->duration = txDuration;
     txParams->psd = txPowerSpectrum;
     txParams->ppdu = ppdu;
-    txParams->txWidth = ppdu->GetTxVector().GetChannelWidth();
-    ;
     NS_LOG_DEBUG("Starting " << type << " with power " << txPowerDbm << " dBm on channel "
                              << +m_wifiPhy->GetChannelNumber() << " for "
                              << txParams->duration.As(Time::MS));
@@ -1369,7 +1374,7 @@
 }
 
 bool
-PhyEntity::CanStartRx(Ptr<const WifiPpdu> ppdu, uint16_t txChannelWidth) const
+PhyEntity::CanStartRx(Ptr<const WifiPpdu> ppdu) const
 {
     // The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU that does
     // not overlap the primary channel
@@ -1383,6 +1388,7 @@
     const auto p20MinFreq = p20CenterFreq - (primaryWidth / 2);
     const auto p20MaxFreq = p20CenterFreq + (primaryWidth / 2);
     const auto txCenterFreq = ppdu->GetTxCenterFreq();
+    const auto txChannelWidth = ppdu->GetTxChannelWidth();
     const auto minTxFreq = txCenterFreq - txChannelWidth / 2;
     const auto maxTxFreq = txCenterFreq + txChannelWidth / 2;
     return p20MinFreq >= minTxFreq && p20MaxFreq <= maxTxFreq;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/phy-entity.h ns-3.40/src/wifi/model/phy-entity.h
--- ns-3.39/src/wifi/model/phy-entity.h	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/phy-entity.h	2023-09-27 13:30:37.910839800 -0700
@@ -31,7 +31,6 @@
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
 #include "ns3/simple-ref-count.h"
-#include "ns3/wifi-spectrum-value-helper.h"
 
 #include <list>
 #include <map>
@@ -458,11 +457,10 @@
      * given PPDU.
      *
      * \param ppdu the PPDU
-     * \param txChannelWidth the channel width (MHz) used to transmit the PPDU
      * \return true if the PHY shall issue a PHY-RXSTART.indication primitive in response to a PPDU,
      * false otherwise
      */
-    virtual bool CanStartRx(Ptr<const WifiPpdu> ppdu, uint16_t txChannelWidth) const;
+    virtual bool CanStartRx(Ptr<const WifiPpdu> ppdu) const;
 
     /**
      * Check if PHY state should move to CCA busy state based on current
@@ -839,22 +837,30 @@
      * \param ppdu the PPDU
      * \param duration the PPDU duration
      * \param rxPower received power per band (W)
-     * \param isStartOfdmaRxing flag whether the event corresponds to the start of the OFDMA payload
-     * reception (only used for UL-OFDMA)
-     * \return the created event
+     * \param isStartHePortionRxing flag whether the event corresponds to the start of the OFDMA
+     * payload reception (only used for UL-OFDMA) \return the created event
      */
     Ptr<Event> CreateInterferenceEvent(Ptr<const WifiPpdu> ppdu,
                                        Time duration,
                                        RxPowerWattPerChannelBand& rxPower,
-                                       bool isStartOfdmaRxing = false);
+                                       bool isStartHePortionRxing = false);
     /**
-     * Update an event in WifiPhy's InterferenceHelper class.
-     * Wrapper used by child classes.
-     *
-     * \param event the event to be updated
-     * \param rxPower the received power (W) per band to be added to the current event
-     */
-    void UpdateInterferenceEvent(Ptr<Event> event, const RxPowerWattPerChannelBand& rxPower);
+     * Handle reception of a PPDU that carries the same content of another PPDU.
+     * This is typically called upon reception of preambles of HE MU PPDUs or reception
+     * of non-HT duplicate control frames that carries the exact same content sent from different
+     * STAs. If the delay between the PPDU and the first PPDU carrying the same content is small
+     * enough, PPDU can be decoded and its power is added constructively, and the TXVECTOR is
+     * updated accordingly. Otherwise, a new interference event is created and PPDU is dropped by
+     * the PHY.
+     *
+     * \param event the event of the ongoing reception
+     * \param ppdu the newly received PPDU (UL MU or non-HT duplicate)
+     * \param rxPower the received power (W) per band of the newly received PPDU
+     */
+    virtual void HandleRxPpduWithSameContent(Ptr<Event> event,
+                                             Ptr<const WifiPpdu> ppdu,
+                                             RxPowerWattPerChannelBand& rxPower);
+
     /**
      * Notify WifiPhy's InterferenceHelper of the end of the reception,
      * clear maps and end of MPDU event, and eventually reset WifiPhy.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/qos-frame-exchange-manager.cc ns-3.40/src/wifi/model/qos-frame-exchange-manager.cc
--- ns-3.39/src/wifi/model/qos-frame-exchange-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/qos-frame-exchange-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -99,15 +99,15 @@
 
     WifiTxVector cfEndTxVector = GetWifiRemoteStationManager()->GetRtsTxVector(cfEnd.GetAddr1());
 
-    Time txDuration = m_phy->CalculateTxDuration(cfEnd.GetSize() + WIFI_MAC_FCS_LENGTH,
-                                                 cfEndTxVector,
-                                                 m_phy->GetPhyBand());
+    auto mpdu = Create<WifiMpdu>(Create<Packet>(), cfEnd);
+    auto txDuration =
+        m_phy->CalculateTxDuration(mpdu->GetSize(), cfEndTxVector, m_phy->GetPhyBand());
 
     // Send the CF-End frame if the remaining duration is long enough to transmit this frame
     if (m_edca->GetRemainingTxop(m_linkId) > txDuration)
     {
         NS_LOG_DEBUG("Send CF-End frame");
-        m_phy->Send(Create<WifiPsdu>(Create<Packet>(), cfEnd), cfEndTxVector);
+        ForwardMpduDown(mpdu, cfEndTxVector);
         Simulator::Schedule(txDuration,
                             &QosFrameExchangeManager::NotifyChannelReleased,
                             this,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/qos-txop.cc ns-3.40/src/wifi/model/qos-txop.cc
--- ns-3.39/src/wifi/model/qos-txop.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/qos-txop.cc	2023-09-27 13:30:37.910839800 -0700
@@ -640,9 +640,9 @@
         m_baManager->NotifyOriginatorAgreementRejected(recipient, tid);
     }
 
-    for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
+    for (const auto& [id, link] : GetLinks())
     {
-        StartAccessIfNeeded(linkId);
+        StartAccessIfNeeded(id);
     }
 }
 
@@ -662,9 +662,9 @@
     m_baManager->NotifyOriginatorAgreementNoReply(recipient, tid);
     // the recipient has been "unblocked" and transmissions can resume using normal
     // acknowledgment, hence start access (if needed) on all the links
-    for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
+    for (const auto& [id, link] : GetLinks())
     {
-        StartAccessIfNeeded(linkId);
+        StartAccessIfNeeded(id);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/aarfcd-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/aarfcd-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/aarfcd-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/aarfcd-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -151,7 +151,7 @@
 AarfcdWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    AarfcdWifiRemoteStation* station = new AarfcdWifiRemoteStation();
+    auto station = new AarfcdWifiRemoteStation();
 
     // AARF fields below
     station->m_successThreshold = m_minSuccessThreshold;
@@ -182,7 +182,7 @@
 AarfcdWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    AarfcdWifiRemoteStation* station = static_cast<AarfcdWifiRemoteStation*>(st);
+    auto station = static_cast<AarfcdWifiRemoteStation*>(st);
     station->m_timer++;
     station->m_failed++;
     station->m_success = 0;
@@ -269,7 +269,7 @@
                                  double rtsSnr)
 {
     NS_LOG_FUNCTION(this << st << ctsSnr << ctsMode << rtsSnr);
-    AarfcdWifiRemoteStation* station = static_cast<AarfcdWifiRemoteStation*>(st);
+    auto station = static_cast<AarfcdWifiRemoteStation*>(st);
     NS_LOG_DEBUG("station=" << station << " rts ok");
     station->m_rtsCounter--;
 }
@@ -283,7 +283,7 @@
                                   uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    AarfcdWifiRemoteStation* station = static_cast<AarfcdWifiRemoteStation*>(st);
+    auto station = static_cast<AarfcdWifiRemoteStation*>(st);
     station->m_timer++;
     station->m_success++;
     station->m_failed = 0;
@@ -328,7 +328,7 @@
 AarfcdWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    AarfcdWifiRemoteStation* station = static_cast<AarfcdWifiRemoteStation*>(st);
+    auto station = static_cast<AarfcdWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -359,7 +359,7 @@
     NS_LOG_FUNCTION(this << st);
     /// \todo we could/should implement the AARF algorithm for
     /// RTS only by picking a single rate within the BasicRateSet.
-    AarfcdWifiRemoteStation* station = static_cast<AarfcdWifiRemoteStation*>(st);
+    auto station = static_cast<AarfcdWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -390,7 +390,7 @@
 AarfcdWifiManager::DoNeedRts(WifiRemoteStation* st, uint32_t size, bool normally)
 {
     NS_LOG_FUNCTION(this << st << size << normally);
-    AarfcdWifiRemoteStation* station = static_cast<AarfcdWifiRemoteStation*>(st);
+    auto station = static_cast<AarfcdWifiRemoteStation*>(st);
     NS_LOG_INFO("" << station << " rate=" << station->m_rate
                    << " rts=" << (station->m_rtsOn ? "RTS" : "BASIC")
                    << " rtsCounter=" << station->m_rtsCounter);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/aarf-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/aarf-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/aarf-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/aarf-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -123,7 +123,7 @@
 AarfWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    AarfWifiRemoteStation* station = new AarfWifiRemoteStation();
+    auto station = new AarfWifiRemoteStation();
 
     station->m_successThreshold = m_minSuccessThreshold;
     station->m_timerTimeout = m_minTimerThreshold;
@@ -157,7 +157,7 @@
 AarfWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    AarfWifiRemoteStation* station = static_cast<AarfWifiRemoteStation*>(st);
+    auto station = static_cast<AarfWifiRemoteStation*>(st);
     station->m_timer++;
     station->m_failed++;
     station->m_success = 0;
@@ -224,7 +224,7 @@
                                 uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    AarfWifiRemoteStation* station = static_cast<AarfWifiRemoteStation*>(st);
+    auto station = static_cast<AarfWifiRemoteStation*>(st);
     station->m_timer++;
     station->m_success++;
     station->m_failed = 0;
@@ -259,7 +259,7 @@
 AarfWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    AarfWifiRemoteStation* station = static_cast<AarfWifiRemoteStation*>(st);
+    auto station = static_cast<AarfWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -290,7 +290,7 @@
     NS_LOG_FUNCTION(this << st);
     /// \todo we could/should implement the AARF algorithm for
     /// RTS only by picking a single rate within the BasicRateSet.
-    AarfWifiRemoteStation* station = static_cast<AarfWifiRemoteStation*>(st);
+    auto station = static_cast<AarfWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/amrr-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/amrr-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/amrr-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/amrr-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -129,7 +129,7 @@
 AmrrWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    AmrrWifiRemoteStation* station = new AmrrWifiRemoteStation();
+    auto station = new AmrrWifiRemoteStation();
     station->m_nextModeUpdate = Simulator::Now() + m_updatePeriod;
     station->m_tx_ok = 0;
     station->m_tx_err = 0;
@@ -158,7 +158,7 @@
 AmrrWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    AmrrWifiRemoteStation* station = static_cast<AmrrWifiRemoteStation*>(st);
+    auto station = static_cast<AmrrWifiRemoteStation*>(st);
     station->m_retry++;
     station->m_tx_retr++;
 }
@@ -181,7 +181,7 @@
                                 uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    AmrrWifiRemoteStation* station = static_cast<AmrrWifiRemoteStation*>(st);
+    auto station = static_cast<AmrrWifiRemoteStation*>(st);
     station->m_retry = 0;
     station->m_tx_ok++;
 }
@@ -196,7 +196,7 @@
 AmrrWifiManager::DoReportFinalDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    AmrrWifiRemoteStation* station = static_cast<AmrrWifiRemoteStation*>(st);
+    auto station = static_cast<AmrrWifiRemoteStation*>(st);
     station->m_retry = 0;
     station->m_tx_err++;
 }
@@ -334,7 +334,7 @@
 AmrrWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    AmrrWifiRemoteStation* station = static_cast<AmrrWifiRemoteStation*>(st);
+    auto station = static_cast<AmrrWifiRemoteStation*>(st);
     UpdateMode(station);
     NS_ASSERT(station->m_txrate < GetNSupported(station));
     uint8_t rateIndex;
@@ -403,7 +403,7 @@
 AmrrWifiManager::DoGetRtsTxVector(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    AmrrWifiRemoteStation* station = static_cast<AmrrWifiRemoteStation*>(st);
+    auto station = static_cast<AmrrWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/aparf-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/aparf-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/aparf-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/aparf-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -160,7 +160,7 @@
 AparfWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    AparfWifiRemoteStation* station = new AparfWifiRemoteStation();
+    auto station = new AparfWifiRemoteStation();
 
     station->m_successThreshold = m_successMax1;
     station->m_failThreshold = m_failMax;
@@ -189,7 +189,7 @@
         station->m_critRateIndex = 0;
         WifiMode mode = GetSupported(station, station->m_rateIndex);
         uint16_t channelWidth = GetChannelWidth(station);
-        DataRate rate = DataRate(mode.GetDataRate(channelWidth));
+        DataRate rate(mode.GetDataRate(channelWidth));
         double power = GetPhy()->GetPowerDbm(m_maxPower);
         m_powerChange(power, power, station->m_state->m_address);
         m_rateChange(rate, rate, station->m_state->m_address);
@@ -207,7 +207,7 @@
 AparfWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    AparfWifiRemoteStation* station = static_cast<AparfWifiRemoteStation*>(st);
+    auto station = static_cast<AparfWifiRemoteStation*>(st);
     CheckInit(station);
     station->m_nFailed++;
     station->m_nSuccess = 0;
@@ -271,7 +271,7 @@
                                  uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    AparfWifiRemoteStation* station = static_cast<AparfWifiRemoteStation*>(st);
+    auto station = static_cast<AparfWifiRemoteStation*>(st);
     CheckInit(station);
     station->m_nSuccess++;
     station->m_nFailed = 0;
@@ -354,7 +354,7 @@
 AparfWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    AparfWifiRemoteStation* station = static_cast<AparfWifiRemoteStation*>(st);
+    auto station = static_cast<AparfWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -362,9 +362,8 @@
     }
     CheckInit(station);
     WifiMode mode = GetSupported(station, station->m_rateIndex);
-    DataRate rate = DataRate(mode.GetDataRate(channelWidth));
-    DataRate prevRate =
-        DataRate(GetSupported(station, station->m_prevRateIndex).GetDataRate(channelWidth));
+    DataRate rate(mode.GetDataRate(channelWidth));
+    DataRate prevRate(GetSupported(station, station->m_prevRateIndex).GetDataRate(channelWidth));
     double power = GetPhy()->GetPowerDbm(station->m_powerLevel);
     double prevPower = GetPhy()->GetPowerDbm(station->m_prevPowerLevel);
     if (station->m_prevPowerLevel != station->m_powerLevel)
@@ -395,7 +394,7 @@
     NS_LOG_FUNCTION(this << st);
     /// \todo we could/should implement the ARF algorithm for
     /// RTS only by picking a single rate within the BasicRateSet.
-    AparfWifiRemoteStation* station = static_cast<AparfWifiRemoteStation*>(st);
+    auto station = static_cast<AparfWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/arf-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/arf-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/arf-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/arf-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -107,7 +107,7 @@
 ArfWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    ArfWifiRemoteStation* station = new ArfWifiRemoteStation();
+    auto station = new ArfWifiRemoteStation();
 
     station->m_successThreshold = m_successThreshold;
     station->m_timerTimeout = m_timerThreshold;
@@ -141,7 +141,7 @@
 ArfWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    ArfWifiRemoteStation* station = static_cast<ArfWifiRemoteStation*>(st);
+    auto station = static_cast<ArfWifiRemoteStation*>(st);
     station->m_timer++;
     station->m_failed++;
     station->m_success = 0;
@@ -202,7 +202,7 @@
                                uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    ArfWifiRemoteStation* station = static_cast<ArfWifiRemoteStation*>(st);
+    auto station = static_cast<ArfWifiRemoteStation*>(st);
     station->m_timer++;
     station->m_success++;
     station->m_failed = 0;
@@ -236,7 +236,7 @@
 ArfWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    ArfWifiRemoteStation* station = static_cast<ArfWifiRemoteStation*>(st);
+    auto station = static_cast<ArfWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -267,7 +267,7 @@
     NS_LOG_FUNCTION(this << st);
     /// \todo we could/should implement the ARF algorithm for
     /// RTS only by picking a single rate within the BasicRateSet.
-    ArfWifiRemoteStation* station = static_cast<ArfWifiRemoteStation*>(st);
+    auto station = static_cast<ArfWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/cara-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/cara-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/cara-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/cara-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -115,7 +115,7 @@
 CaraWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    CaraWifiRemoteStation* station = new CaraWifiRemoteStation();
+    auto station = new CaraWifiRemoteStation();
     station->m_rate = 0;
     station->m_success = 0;
     station->m_failed = 0;
@@ -133,7 +133,7 @@
 CaraWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    CaraWifiRemoteStation* station = static_cast<CaraWifiRemoteStation*>(st);
+    auto station = static_cast<CaraWifiRemoteStation*>(st);
     station->m_timer++;
     station->m_failed++;
     station->m_success = 0;
@@ -173,7 +173,7 @@
                                 uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    CaraWifiRemoteStation* station = static_cast<CaraWifiRemoteStation*>(st);
+    auto station = static_cast<CaraWifiRemoteStation*>(st);
     station->m_timer++;
     station->m_success++;
     station->m_failed = 0;
@@ -207,7 +207,7 @@
 CaraWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    CaraWifiRemoteStation* station = static_cast<CaraWifiRemoteStation*>(st);
+    auto station = static_cast<CaraWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -236,7 +236,7 @@
 CaraWifiManager::DoGetRtsTxVector(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    CaraWifiRemoteStation* station = static_cast<CaraWifiRemoteStation*>(st);
+    auto station = static_cast<CaraWifiRemoteStation*>(st);
     /// \todo we could/should implement the Arf algorithm for
     /// RTS only by picking a single rate within the BasicRateSet.
     uint16_t channelWidth = GetChannelWidth(station);
@@ -269,7 +269,7 @@
 CaraWifiManager::DoNeedRts(WifiRemoteStation* st, uint32_t size, bool normally)
 {
     NS_LOG_FUNCTION(this << st << size << normally);
-    CaraWifiRemoteStation* station = static_cast<CaraWifiRemoteStation*>(st);
+    auto station = static_cast<CaraWifiRemoteStation*>(st);
     return normally || station->m_failed >= m_probeThreshold;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/constant-rate-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/constant-rate-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/constant-rate-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/constant-rate-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -69,7 +69,7 @@
 ConstantRateWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    WifiRemoteStation* station = new WifiRemoteStation();
+    auto station = new WifiRemoteStation();
     return station;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/ideal-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/ideal-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/ideal-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/ideal-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -224,7 +224,7 @@
 IdealWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    IdealWifiRemoteStation* station = new IdealWifiRemoteStation();
+    auto station = new IdealWifiRemoteStation();
     Reset(station);
     return station;
 }
@@ -233,7 +233,7 @@
 IdealWifiManager::Reset(WifiRemoteStation* station) const
 {
     NS_LOG_FUNCTION(this << station);
-    IdealWifiRemoteStation* st = static_cast<IdealWifiRemoteStation*>(station);
+    auto st = static_cast<IdealWifiRemoteStation*>(station);
     st->m_lastSnrObserved = 0.0;
     st->m_lastChannelWidthObserved = 0;
     st->m_lastNssObserved = 1;
@@ -268,7 +268,7 @@
                                 double rtsSnr)
 {
     NS_LOG_FUNCTION(this << st << ctsSnr << ctsMode.GetUniqueName() << rtsSnr);
-    IdealWifiRemoteStation* station = static_cast<IdealWifiRemoteStation*>(st);
+    auto station = static_cast<IdealWifiRemoteStation*>(st);
     station->m_lastSnrObserved = rtsSnr;
     station->m_lastChannelWidthObserved =
         GetPhy()->GetChannelWidth() >= 40 ? 20 : GetPhy()->GetChannelWidth();
@@ -285,7 +285,7 @@
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode.GetUniqueName() << dataSnr << dataChannelWidth
                          << +dataNss);
-    IdealWifiRemoteStation* station = static_cast<IdealWifiRemoteStation*>(st);
+    auto station = static_cast<IdealWifiRemoteStation*>(st);
     if (dataSnr == 0)
     {
         NS_LOG_WARN("DataSnr reported to be zero; not saving this report.");
@@ -307,7 +307,7 @@
 {
     NS_LOG_FUNCTION(this << st << nSuccessfulMpdus << nFailedMpdus << rxSnr << dataSnr
                          << dataChannelWidth << +dataNss);
-    IdealWifiRemoteStation* station = static_cast<IdealWifiRemoteStation*>(st);
+    auto station = static_cast<IdealWifiRemoteStation*>(st);
     if (dataSnr == 0)
     {
         NS_LOG_WARN("DataSnr reported to be zero; not saving this report.");
@@ -336,7 +336,7 @@
 IdealWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    IdealWifiRemoteStation* station = static_cast<IdealWifiRemoteStation*>(st);
+    auto station = static_cast<IdealWifiRemoteStation*>(st);
     // We search within the Supported rate set the mode with the
     // highest data rate for which the SNR threshold is smaller than m_lastSnr
     // to ensure correct packet delivery.
@@ -586,7 +586,7 @@
 IdealWifiManager::DoGetRtsTxVector(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    IdealWifiRemoteStation* station = static_cast<IdealWifiRemoteStation*>(st);
+    auto station = static_cast<IdealWifiRemoteStation*>(st);
     // We search within the Basic rate set the mode with the highest
     // SNR threshold possible which is smaller than m_lastSnr to
     // ensure correct packet delivery.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/minstrel-ht-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/minstrel-ht-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/minstrel-ht-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/minstrel-ht-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -437,7 +437,7 @@
     txvector.SetGuardInterval(gi);
     txvector.SetChannelWidth(chWidth);
     txvector.SetNess(0);
-    txvector.SetStbc(0);
+    txvector.SetStbc(false);
     txvector.SetMode(mode);
     txvector.SetPreambleType(WIFI_PREAMBLE_HT_MF);
     return WifiPhy::CalculatePhyPreambleAndHeaderDuration(txvector) +
@@ -480,7 +480,7 @@
 MinstrelHtWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    MinstrelHtWifiRemoteStation* station = new MinstrelHtWifiRemoteStation();
+    auto station = new MinstrelHtWifiRemoteStation();
 
     // Initialize variables common to both stations.
     station->m_nextStatsUpdate = Simulator::Now() + m_updateStats;
@@ -572,7 +572,7 @@
 MinstrelHtWifiManager::DoReportRtsFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
     CheckInit(station);
     if (!station->m_initialized)
     {
@@ -595,7 +595,7 @@
 MinstrelHtWifiManager::DoReportFinalRtsFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
     NS_LOG_DEBUG("Final RTS failed");
     CheckInit(station);
     if (!station->m_initialized)
@@ -609,7 +609,7 @@
 MinstrelHtWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
 
     CheckInit(station);
     if (!station->m_initialized)
@@ -644,7 +644,7 @@
                                       uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
 
     CheckInit(station);
     if (!station->m_initialized)
@@ -716,7 +716,7 @@
 MinstrelHtWifiManager::DoReportFinalDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
 
     CheckInit(station);
     if (!station->m_initialized)
@@ -770,7 +770,7 @@
 {
     NS_LOG_FUNCTION(this << st << nSuccessfulMpdus << nFailedMpdus << rxSnr << dataSnr
                          << dataChannelWidth << +dataNss);
-    MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
 
     CheckInit(station);
     if (!station->m_initialized)
@@ -1023,7 +1023,7 @@
 MinstrelHtWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
 
     if (!station->m_initialized)
     {
@@ -1096,7 +1096,7 @@
 MinstrelHtWifiManager::DoGetRtsTxVector(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
 
     if (!station->m_initialized)
     {
@@ -1182,7 +1182,7 @@
 {
     NS_LOG_FUNCTION(this << st << packet << normally);
 
-    MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
 
     CheckInit(station);
     if (!station->m_initialized)
@@ -2229,33 +2229,24 @@
 WifiModeList
 MinstrelHtWifiManager::GetHeDeviceMcsList() const
 {
-    WifiModeList heMcsList;
-    for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_HE))
-    {
-        heMcsList.push_back(mode);
-    }
+    const auto& mcsList = GetPhy()->GetMcsList(WIFI_MOD_CLASS_HE);
+    WifiModeList heMcsList(mcsList.begin(), mcsList.end());
     return heMcsList;
 }
 
 WifiModeList
 MinstrelHtWifiManager::GetVhtDeviceMcsList() const
 {
-    WifiModeList vhtMcsList;
-    for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_VHT))
-    {
-        vhtMcsList.push_back(mode);
-    }
+    const auto& mcsList = GetPhy()->GetMcsList(WIFI_MOD_CLASS_VHT);
+    WifiModeList vhtMcsList(mcsList.begin(), mcsList.end());
     return vhtMcsList;
 }
 
 WifiModeList
 MinstrelHtWifiManager::GetHtDeviceMcsList() const
 {
-    WifiModeList htMcsList;
-    for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_HT))
-    {
-        htMcsList.push_back(mode);
-    }
+    const auto& mcsList = GetPhy()->GetMcsList(WIFI_MOD_CLASS_HT);
+    WifiModeList htMcsList(mcsList.begin(), mcsList.end());
     return htMcsList;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/minstrel-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/minstrel-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/minstrel-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/minstrel-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -178,7 +178,7 @@
 MinstrelWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    MinstrelWifiRemoteStation* station = new MinstrelWifiRemoteStation();
+    auto station = new MinstrelWifiRemoteStation();
 
     station->m_nextStatsUpdate = Simulator::Now() + m_updateStats;
     station->m_col = 0;
@@ -779,7 +779,7 @@
 MinstrelWifiManager::DoReportRtsFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    MinstrelWifiRemoteStation* station = static_cast<MinstrelWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelWifiRemoteStation*>(st);
     NS_LOG_DEBUG("DoReportRtsFailed m_txrate=" << station->m_txrate);
     station->m_shortRetry++;
 }
@@ -797,7 +797,7 @@
 MinstrelWifiManager::DoReportFinalRtsFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    MinstrelWifiRemoteStation* station = static_cast<MinstrelWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelWifiRemoteStation*>(st);
     UpdateRetry(station);
 }
 
@@ -805,7 +805,7 @@
 MinstrelWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    MinstrelWifiRemoteStation* station = static_cast<MinstrelWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelWifiRemoteStation*>(st);
     NS_LOG_DEBUG("DoReportDataFailed " << station << "\t rate " << station->m_txrate
                                        << "\tlongRetry \t" << station->m_longRetry);
     CheckInit(station);
@@ -826,7 +826,7 @@
                                     uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    MinstrelWifiRemoteStation* station = static_cast<MinstrelWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelWifiRemoteStation*>(st);
 
     CheckInit(station);
     if (!station->m_initialized)
@@ -865,7 +865,7 @@
 MinstrelWifiManager::DoReportFinalDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    MinstrelWifiRemoteStation* station = static_cast<MinstrelWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelWifiRemoteStation*>(st);
 
     CheckInit(station);
     if (!station->m_initialized)
@@ -939,7 +939,7 @@
 MinstrelWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    MinstrelWifiRemoteStation* station = static_cast<MinstrelWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelWifiRemoteStation*>(st);
     return GetDataTxVector(station);
 }
 
@@ -947,7 +947,7 @@
 MinstrelWifiManager::DoGetRtsTxVector(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    MinstrelWifiRemoteStation* station = static_cast<MinstrelWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelWifiRemoteStation*>(st);
     return GetRtsTxVector(station);
 }
 
@@ -957,7 +957,7 @@
                                           bool normally)
 {
     NS_LOG_FUNCTION(this << st << packet << normally);
-    MinstrelWifiRemoteStation* station = static_cast<MinstrelWifiRemoteStation*>(st);
+    auto station = static_cast<MinstrelWifiRemoteStation*>(st);
 
     CheckInit(station);
     if (!station->m_initialized)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/onoe-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/onoe-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/onoe-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/onoe-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -115,7 +115,7 @@
 OnoeWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    OnoeWifiRemoteStation* station = new OnoeWifiRemoteStation();
+    auto station = new OnoeWifiRemoteStation();
     station->m_nextModeUpdate = Simulator::Now() + m_updatePeriod;
     station->m_rateBlocked = false;
     station->m_shortRetry = 0;
@@ -138,7 +138,7 @@
 OnoeWifiManager::DoReportRtsFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    OnoeWifiRemoteStation* station = static_cast<OnoeWifiRemoteStation*>(st);
+    auto station = static_cast<OnoeWifiRemoteStation*>(st);
     station->m_shortRetry++;
     station->m_rateBlocked = true; // do not change rate for retransmission
 }
@@ -147,7 +147,7 @@
 OnoeWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    OnoeWifiRemoteStation* station = static_cast<OnoeWifiRemoteStation*>(st);
+    auto station = static_cast<OnoeWifiRemoteStation*>(st);
     station->m_longRetry++;
     station->m_rateBlocked = true; // do not change rate for retransmission
 }
@@ -159,7 +159,7 @@
                                double rtsSnr)
 {
     NS_LOG_FUNCTION(this << st << ctsSnr << ctsMode << rtsSnr);
-    OnoeWifiRemoteStation* station = static_cast<OnoeWifiRemoteStation*>(st);
+    auto station = static_cast<OnoeWifiRemoteStation*>(st);
     station->m_rateBlocked = true; // do not change rate
 }
 
@@ -172,7 +172,7 @@
                                 uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    OnoeWifiRemoteStation* station = static_cast<OnoeWifiRemoteStation*>(st);
+    auto station = static_cast<OnoeWifiRemoteStation*>(st);
     UpdateRetry(station);
     station->m_tx_ok++;
     station->m_rateBlocked = false; // we can change the rate for next packet
@@ -182,7 +182,7 @@
 OnoeWifiManager::DoReportFinalRtsFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    OnoeWifiRemoteStation* station = static_cast<OnoeWifiRemoteStation*>(st);
+    auto station = static_cast<OnoeWifiRemoteStation*>(st);
     UpdateRetry(station);
     station->m_tx_err++;
     station->m_rateBlocked = false; // we can change the rate for next packet
@@ -192,7 +192,7 @@
 OnoeWifiManager::DoReportFinalDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    OnoeWifiRemoteStation* station = static_cast<OnoeWifiRemoteStation*>(st);
+    auto station = static_cast<OnoeWifiRemoteStation*>(st);
     UpdateRetry(station);
     station->m_tx_err++;
     station->m_rateBlocked = false; // we can change the rate for next packet
@@ -222,9 +222,8 @@
      */
 
     int dir = 0;
-    int enough;
     uint8_t nrate;
-    enough = (station->m_tx_ok + station->m_tx_err >= 10);
+    bool enough = (station->m_tx_ok + station->m_tx_err >= 10);
 
     /* no packet reached -> down */
     if (station->m_tx_err > 0 && station->m_tx_ok == 0)
@@ -294,7 +293,7 @@
 OnoeWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    OnoeWifiRemoteStation* station = static_cast<OnoeWifiRemoteStation*>(st);
+    auto station = static_cast<OnoeWifiRemoteStation*>(st);
     UpdateMode(station);
     NS_ASSERT(station->m_txrate < GetNSupported(station));
     uint8_t rateIndex;
@@ -363,7 +362,7 @@
 OnoeWifiManager::DoGetRtsTxVector(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    OnoeWifiRemoteStation* station = static_cast<OnoeWifiRemoteStation*>(st);
+    auto station = static_cast<OnoeWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/parf-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/parf-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/parf-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/parf-wifi-manager.cc	2023-09-27 13:30:37.910839800 -0700
@@ -126,7 +126,7 @@
 ParfWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    ParfWifiRemoteStation* station = new ParfWifiRemoteStation();
+    auto station = new ParfWifiRemoteStation();
 
     station->m_nSuccess = 0;
     station->m_nFail = 0;
@@ -155,7 +155,7 @@
         station->m_prevPowerLevel = m_maxPower;
         WifiMode mode = GetSupported(station, station->m_rateIndex);
         uint16_t channelWidth = GetChannelWidth(station);
-        DataRate rate = DataRate(mode.GetDataRate(channelWidth));
+        DataRate rate(mode.GetDataRate(channelWidth));
         double power = GetPhy()->GetPowerDbm(m_maxPower);
         m_powerChange(power, power, station->m_state->m_address);
         m_rateChange(rate, rate, station->m_state->m_address);
@@ -182,7 +182,7 @@
 ParfWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    ParfWifiRemoteStation* station = static_cast<ParfWifiRemoteStation*>(st);
+    auto station = static_cast<ParfWifiRemoteStation*>(st);
     CheckInit(station);
     station->m_nAttempt++;
     station->m_nFail++;
@@ -273,7 +273,7 @@
                                 uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    ParfWifiRemoteStation* station = static_cast<ParfWifiRemoteStation*>(st);
+    auto station = static_cast<ParfWifiRemoteStation*>(st);
     CheckInit(station);
     station->m_nAttempt++;
     station->m_nSuccess++;
@@ -323,7 +323,7 @@
 ParfWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    ParfWifiRemoteStation* station = static_cast<ParfWifiRemoteStation*>(st);
+    auto station = static_cast<ParfWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -331,9 +331,8 @@
     }
     CheckInit(station);
     WifiMode mode = GetSupported(station, station->m_rateIndex);
-    DataRate rate = DataRate(mode.GetDataRate(channelWidth));
-    DataRate prevRate =
-        DataRate(GetSupported(station, station->m_prevRateIndex).GetDataRate(channelWidth));
+    DataRate rate(mode.GetDataRate(channelWidth));
+    DataRate prevRate(GetSupported(station, station->m_prevRateIndex).GetDataRate(channelWidth));
     double power = GetPhy()->GetPowerDbm(station->m_powerLevel);
     double prevPower = GetPhy()->GetPowerDbm(station->m_prevPowerLevel);
     if (station->m_prevPowerLevel != station->m_powerLevel)
@@ -364,7 +363,7 @@
     NS_LOG_FUNCTION(this << st);
     /// \todo we could/should implement the ARF algorithm for
     /// RTS only by picking a single rate within the BasicRateSet.
-    ParfWifiRemoteStation* station = static_cast<ParfWifiRemoteStation*>(st);
+    auto station = static_cast<ParfWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/rraa-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/rraa-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/rraa-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/rraa-wifi-manager.cc	2023-09-27 13:30:37.914839700 -0700
@@ -169,7 +169,7 @@
 RraaWifiManager::GetCalcTxTime(WifiMode mode) const
 {
     NS_LOG_FUNCTION(this << mode);
-    for (TxTime::const_iterator i = m_calcTxTime.begin(); i != m_calcTxTime.end(); i++)
+    for (auto i = m_calcTxTime.begin(); i != m_calcTxTime.end(); i++)
     {
         if (mode == i->second)
         {
@@ -192,9 +192,7 @@
 {
     NS_LOG_FUNCTION(this << station << mode);
     WifiRraaThresholds threshold;
-    for (RraaThresholdsTable::const_iterator i = station->m_thresholds.begin();
-         i != station->m_thresholds.end();
-         i++)
+    for (auto i = station->m_thresholds.begin(); i != station->m_thresholds.end(); i++)
     {
         if (mode == i->second)
         {
@@ -208,7 +206,7 @@
 WifiRemoteStation*
 RraaWifiManager::DoCreateStation() const
 {
-    RraaWifiRemoteStation* station = new RraaWifiRemoteStation();
+    auto station = new RraaWifiRemoteStation();
     station->m_initialized = false;
     station->m_adaptiveRtsWnd = 0;
     station->m_rtsCounter = 0;
@@ -303,7 +301,7 @@
 RraaWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    RraaWifiRemoteStation* station = static_cast<RraaWifiRemoteStation*>(st);
+    auto station = static_cast<RraaWifiRemoteStation*>(st);
     station->m_lastFrameFail = true;
     CheckTimeout(station);
     station->m_counter--;
@@ -335,7 +333,7 @@
                                 uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    RraaWifiRemoteStation* station = static_cast<RraaWifiRemoteStation*>(st);
+    auto station = static_cast<RraaWifiRemoteStation*>(st);
     station->m_lastFrameFail = false;
     CheckTimeout(station);
     station->m_counter--;
@@ -358,7 +356,7 @@
 RraaWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    RraaWifiRemoteStation* station = static_cast<RraaWifiRemoteStation*>(st);
+    auto station = static_cast<RraaWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -388,7 +386,7 @@
 RraaWifiManager::DoGetRtsTxVector(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    RraaWifiRemoteStation* station = static_cast<RraaWifiRemoteStation*>(st);
+    auto station = static_cast<RraaWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -419,7 +417,7 @@
 RraaWifiManager::DoNeedRts(WifiRemoteStation* st, uint32_t size, bool normally)
 {
     NS_LOG_FUNCTION(this << st << size << normally);
-    RraaWifiRemoteStation* station = static_cast<RraaWifiRemoteStation*>(st);
+    auto station = static_cast<RraaWifiRemoteStation*>(st);
     CheckInit(station);
     if (m_basic)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/rrpaa-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/rrpaa-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/rrpaa-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/rrpaa-wifi-manager.cc	2023-09-27 13:30:37.914839700 -0700
@@ -198,7 +198,7 @@
 RrpaaWifiManager::GetCalcTxTime(WifiMode mode) const
 {
     NS_LOG_FUNCTION(this << mode);
-    for (TxTime::const_iterator i = m_calcTxTime.begin(); i != m_calcTxTime.end(); i++)
+    for (auto i = m_calcTxTime.begin(); i != m_calcTxTime.end(); i++)
     {
         if (mode == i->second)
         {
@@ -221,9 +221,7 @@
 {
     NS_LOG_FUNCTION(this << station << mode);
     WifiRrpaaThresholds threshold;
-    for (RrpaaThresholdsTable::const_iterator i = station->m_thresholds.begin();
-         i != station->m_thresholds.end();
-         i++)
+    for (auto i = station->m_thresholds.begin(); i != station->m_thresholds.end(); i++)
     {
         if (mode == i->second)
         {
@@ -238,7 +236,7 @@
 RrpaaWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    RrpaaWifiRemoteStation* station = new RrpaaWifiRemoteStation();
+    auto station = new RrpaaWifiRemoteStation();
     station->m_adaptiveRtsWnd = 0;
     station->m_rtsCounter = 0;
     station->m_adaptiveRtsOn = false;
@@ -264,7 +262,7 @@
         station->m_powerLevel = m_maxPowerLevel;
         WifiMode mode = GetSupported(station, 0);
         uint16_t channelWidth = GetChannelWidth(station);
-        DataRate rate = DataRate(mode.GetDataRate(channelWidth));
+        DataRate rate(mode.GetDataRate(channelWidth));
         double power = GetPhy()->GetPowerDbm(station->m_powerLevel);
         m_rateChange(rate, rate, station->m_state->m_address);
         m_powerChange(power, power, station->m_state->m_address);
@@ -345,7 +343,7 @@
 RrpaaWifiManager::DoReportDataFailed(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    RrpaaWifiRemoteStation* station = static_cast<RrpaaWifiRemoteStation*>(st);
+    auto station = static_cast<RrpaaWifiRemoteStation*>(st);
     CheckInit(station);
     station->m_lastFrameFail = true;
     CheckTimeout(station);
@@ -378,7 +376,7 @@
                                  uint8_t dataNss)
 {
     NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
-    RrpaaWifiRemoteStation* station = static_cast<RrpaaWifiRemoteStation*>(st);
+    auto station = static_cast<RrpaaWifiRemoteStation*>(st);
     CheckInit(station);
     station->m_lastFrameFail = false;
     CheckTimeout(station);
@@ -402,7 +400,7 @@
 RrpaaWifiManager::DoGetDataTxVector(WifiRemoteStation* st, uint16_t allowedWidth)
 {
     NS_LOG_FUNCTION(this << st << allowedWidth);
-    RrpaaWifiRemoteStation* station = static_cast<RrpaaWifiRemoteStation*>(st);
+    auto station = static_cast<RrpaaWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -410,9 +408,8 @@
     }
     CheckInit(station);
     WifiMode mode = GetSupported(station, station->m_rateIndex);
-    DataRate rate = DataRate(mode.GetDataRate(channelWidth));
-    DataRate prevRate =
-        DataRate(GetSupported(station, station->m_prevRateIndex).GetDataRate(channelWidth));
+    DataRate rate(mode.GetDataRate(channelWidth));
+    DataRate prevRate(GetSupported(station, station->m_prevRateIndex).GetDataRate(channelWidth));
     double power = GetPhy()->GetPowerDbm(station->m_powerLevel);
     double prevPower = GetPhy()->GetPowerDbm(station->m_prevPowerLevel);
     if (station->m_prevRateIndex != station->m_rateIndex)
@@ -441,7 +438,7 @@
 RrpaaWifiManager::DoGetRtsTxVector(WifiRemoteStation* st)
 {
     NS_LOG_FUNCTION(this << st);
-    RrpaaWifiRemoteStation* station = static_cast<RrpaaWifiRemoteStation*>(st);
+    auto station = static_cast<RrpaaWifiRemoteStation*>(st);
     uint16_t channelWidth = GetChannelWidth(station);
     if (channelWidth > 20 && channelWidth != 22)
     {
@@ -472,7 +469,7 @@
 RrpaaWifiManager::DoNeedRts(WifiRemoteStation* st, uint32_t size, bool normally)
 {
     NS_LOG_FUNCTION(this << st << size << normally);
-    RrpaaWifiRemoteStation* station = static_cast<RrpaaWifiRemoteStation*>(st);
+    auto station = static_cast<RrpaaWifiRemoteStation*>(st);
     CheckInit(station);
     if (m_basic)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/rate-control/thompson-sampling-wifi-manager.cc ns-3.40/src/wifi/model/rate-control/thompson-sampling-wifi-manager.cc
--- ns-3.39/src/wifi/model/rate-control/thompson-sampling-wifi-manager.cc	2023-07-05 14:23:48.117428300 -0700
+++ ns-3.40/src/wifi/model/rate-control/thompson-sampling-wifi-manager.cc	2023-09-27 13:30:37.914839700 -0700
@@ -105,7 +105,7 @@
 ThompsonSamplingWifiManager::DoCreateStation() const
 {
     NS_LOG_FUNCTION(this);
-    ThompsonSamplingWifiRemoteStation* station = new ThompsonSamplingWifiRemoteStation();
+    auto station = new ThompsonSamplingWifiRemoteStation();
     station->m_nextMode = 0;
     station->m_lastMode = 0;
     return station;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/spectrum-wifi-phy.cc ns-3.40/src/wifi/model/spectrum-wifi-phy.cc
--- ns-3.39/src/wifi/model/spectrum-wifi-phy.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/spectrum-wifi-phy.cc	2023-09-27 13:30:37.914839700 -0700
@@ -25,6 +25,7 @@
 #include "spectrum-wifi-phy.h"
 
 #include "interference-helper.h"
+#include "wifi-net-device.h"
 #include "wifi-psdu.h"
 #include "wifi-spectrum-phy-interface.h"
 #include "wifi-spectrum-signal-parameters.h"
@@ -37,7 +38,6 @@
 #include "ns3/node.h"
 #include "ns3/simulator.h"
 #include "ns3/spectrum-channel.h"
-#include "ns3/wifi-net-device.h"
 
 #include <algorithm>
 
@@ -64,7 +64,7 @@
             .AddAttribute(
                 "TrackSignalsFromInactiveInterfaces",
                 "Enable or disable tracking signals coming from inactive spectrum PHY interfaces",
-                BooleanValue(false),
+                BooleanValue(true),
                 MakeBooleanAccessor(&SpectrumWifiPhy::m_trackSignalsInactiveInterfaces),
                 MakeBooleanChecker())
             .AddAttribute(
@@ -111,6 +111,7 @@
     m_spectrumPhyInterfaces.clear();
     m_currentSpectrumPhyInterface = nullptr;
     m_antenna = nullptr;
+    m_channelSwitchedCallback.Nullify();
     WifiPhy::DoDispose();
 }
 
@@ -121,16 +122,15 @@
     WifiPhy::DoInitialize();
 }
 
-void
-SpectrumWifiPhy::UpdateInterferenceHelperBands()
+WifiSpectrumBands
+SpectrumWifiPhy::ComputeBands(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface)
 {
-    NS_LOG_FUNCTION(this);
-    NS_ASSERT(!m_spectrumPhyInterfaces.empty());
-    uint16_t channelWidth = GetChannelWidth();
-    WifiSpectrumPhyInterface::WifiSpectrumBands bands{};
+    NS_LOG_FUNCTION(this << spectrumPhyInterface);
+    WifiSpectrumBands bands{};
+    const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
     if (channelWidth < 20)
     {
-        bands.push_back(GetBand(channelWidth));
+        bands.push_back(GetBandForInterface(spectrumPhyInterface, channelWidth));
     }
     else
     {
@@ -138,26 +138,79 @@
         {
             for (uint32_t i = 0; i < (channelWidth / bw); ++i)
             {
-                bands.push_back(GetBand(bw, i));
+                bands.push_back(GetBandForInterface(spectrumPhyInterface, bw, i));
+            }
+        }
+    }
+    return bands;
+}
+
+HeRuBands
+SpectrumWifiPhy::GetHeRuBands(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
+                              uint16_t guardBandwidth)
+{
+    HeRuBands heRuBands{};
+    const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
+    for (uint16_t bw = 160; bw >= 20; bw = bw / 2)
+    {
+        for (uint32_t i = 0; i < (channelWidth / bw); ++i)
+        {
+            for (uint32_t type = 0; type < 7; type++)
+            {
+                auto ruType = static_cast<HeRu::RuType>(type);
+                std::size_t nRus = HeRu::GetNRus(bw, ruType);
+                for (std::size_t phyIndex = 1; phyIndex <= nRus; phyIndex++)
+                {
+                    HeRu::SubcarrierGroup group = HeRu::GetSubcarrierGroup(bw, ruType, phyIndex);
+                    HeRu::SubcarrierRange subcarrierRange =
+                        std::make_pair(group.front().first, group.back().second);
+                    const auto bandIndices = HePhy::ConvertHeRuSubcarriers(bw,
+                                                                           guardBandwidth,
+                                                                           GetSubcarrierSpacing(),
+                                                                           subcarrierRange,
+                                                                           i);
+                    const auto bandFrequencies =
+                        ConvertIndicesToFrequenciesForInterface(spectrumPhyInterface, bandIndices);
+                    WifiSpectrumBandInfo band = {bandIndices, bandFrequencies};
+                    std::size_t index =
+                        (bw == 160 && phyIndex > nRus / 2 ? phyIndex - nRus / 2 : phyIndex);
+                    const auto p20Index = GetOperatingChannel().GetPrimaryChannelIndex(20);
+                    bool primary80IsLower80 = (p20Index < bw / 40);
+                    bool primary80 = (bw < 160 || ruType == HeRu::RU_2x996_TONE ||
+                                      (primary80IsLower80 && phyIndex <= nRus / 2) ||
+                                      (!primary80IsLower80 && phyIndex > nRus / 2));
+                    HeRu::RuSpec ru(ruType, index, primary80);
+                    NS_ABORT_IF(ru.GetPhyIndex(bw, p20Index) != phyIndex);
+                    heRuBands.insert({band, ru});
+                }
             }
         }
     }
-    WifiSpectrumPhyInterface::WifiSpectrumBands allBands{bands};
+    return heRuBands;
+}
+
+void
+SpectrumWifiPhy::UpdateInterferenceHelperBands(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface)
+{
+    NS_LOG_FUNCTION(this << spectrumPhyInterface);
+    auto&& bands = ComputeBands(spectrumPhyInterface);
+    WifiSpectrumBands allBands{bands};
     if (GetStandard() >= WIFI_STANDARD_80211ax)
     {
-        auto&& ruBands = HePhy::GetRuBands(this, channelWidth, GetGuardBandwidth(channelWidth));
-        for (const auto& bandRuPair : ruBands)
+        const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
+        auto&& heRuBands = GetHeRuBands(spectrumPhyInterface, GetGuardBandwidth(channelWidth));
+        for (const auto& bandRuPair : heRuBands)
         {
             allBands.push_back(bandRuPair.first);
         }
-        m_currentSpectrumPhyInterface->SetRuBands(std::move(ruBands));
+        spectrumPhyInterface->SetHeRuBands(std::move(heRuBands));
     }
 
-    m_currentSpectrumPhyInterface->SetBands(std::move(bands));
+    spectrumPhyInterface->SetBands(std::move(bands));
 
     if (m_interference->HasBands())
     {
-        m_interference->UpdateBands(allBands, GetCurrentFrequencyRange());
+        m_interference->UpdateBands(allBands, spectrumPhyInterface->GetFrequencyRange());
     }
     else
     {
@@ -205,9 +258,11 @@
 }
 
 void
-SpectrumWifiPhy::ResetSpectrumModelIfNeeded()
+SpectrumWifiPhy::ResetSpectrumModel(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
+                                    uint16_t centerFrequency,
+                                    uint16_t channelWidth)
 {
-    NS_LOG_FUNCTION(this);
+    NS_LOG_FUNCTION(this << spectrumPhyInterface << centerFrequency << channelWidth);
 
     // We have to reset the spectrum model because we changed RF channel. Consequently,
     // we also have to add the spectrum interface to the spectrum channel again because
@@ -217,31 +272,15 @@
     // duplicated spectrum interfaces (the latter removes the spectrum interface and adds
     // it again in the entry associated with the new RX spectrum model UID)
 
-    const auto channelWidth = GetChannelWidth();
-    const auto centerFrequency = GetFrequency();
-    if (m_currentSpectrumPhyInterface->GetCenterFrequency() == centerFrequency)
-    {
-        // Center frequency has not changed for that interface, hence we do not need to
-        // reset the spectrum model nor update any band stored in the interference helper
-        if (!m_trackSignalsInactiveInterfaces)
-        {
-            // If we are not tracking signals from inactive interface,
-            // this means the spectrum interface has been disconnected
-            // from the spectrum channel and has to be connected back
-            m_currentSpectrumPhyInterface->GetChannel()->AddRx(m_currentSpectrumPhyInterface);
-        }
-        return;
-    }
-
     // Replace existing spectrum model with new one
-    m_currentSpectrumPhyInterface->SetRxSpectrumModel(centerFrequency,
-                                                      channelWidth,
-                                                      GetSubcarrierSpacing(),
-                                                      GetGuardBandwidth(channelWidth));
+    spectrumPhyInterface->SetRxSpectrumModel(centerFrequency,
+                                             channelWidth,
+                                             GetSubcarrierSpacing(),
+                                             GetGuardBandwidth(channelWidth));
 
-    m_currentSpectrumPhyInterface->GetChannel()->AddRx(m_currentSpectrumPhyInterface);
+    spectrumPhyInterface->GetChannel()->AddRx(spectrumPhyInterface);
 
-    UpdateInterferenceHelperBands();
+    UpdateInterferenceHelperBands(spectrumPhyInterface);
 }
 
 void
@@ -282,18 +321,79 @@
     }
 
     m_currentSpectrumPhyInterface = newSpectrumPhyInterface;
-    ResetSpectrumModelIfNeeded();
+
+    auto reset = true;
+    if (m_currentSpectrumPhyInterface->GetCenterFrequency() == frequencyAfter)
+    {
+        // Center frequency has not changed for that interface, hence we do not need to
+        // reset the spectrum model nor update any band stored in the interference helper
+        if (!m_trackSignalsInactiveInterfaces)
+        {
+            // If we are not tracking signals from inactive interface,
+            // this means the spectrum interface has been disconnected
+            // from the spectrum channel and has to be connected back
+            m_currentSpectrumPhyInterface->GetChannel()->AddRx(m_currentSpectrumPhyInterface);
+        }
+        reset = false;
+    }
+
+    if (reset)
+    {
+        ResetSpectrumModel(m_currentSpectrumPhyInterface, frequencyAfter, widthAfter);
+    }
 
     if (IsInitialized())
     {
         SwitchMaybeToCcaBusy(nullptr);
     }
+
+    Simulator::ScheduleNow(&SpectrumWifiPhy::NotifyChannelSwitched, this);
+}
+
+void
+SpectrumWifiPhy::NotifyChannelSwitched()
+{
+    if (!m_channelSwitchedCallback.IsNull())
+    {
+        m_channelSwitchedCallback();
+    }
+}
+
+void
+SpectrumWifiPhy::ConfigureInterface(uint16_t frequency, uint16_t width)
+{
+    NS_LOG_FUNCTION(this << frequency << width);
+
+    if (!m_trackSignalsInactiveInterfaces)
+    {
+        NS_LOG_DEBUG("Tracking of signals on inactive interfaces is not enabled");
+        return;
+    }
+
+    auto spectrumPhyInterface = GetInterfaceCoveringChannelBand(frequency, width);
+
+    NS_ABORT_MSG_IF(!spectrumPhyInterface,
+                    "No spectrum channel covers frequency range ["
+                        << frequency - (width / 2) << " MHz - " << frequency + (width / 2)
+                        << " MHz]");
+
+    NS_ABORT_MSG_IF(spectrumPhyInterface == m_currentSpectrumPhyInterface,
+                    "This method should not be called for the current interface");
+
+    if ((frequency == spectrumPhyInterface->GetCenterFrequency()) &&
+        (width == spectrumPhyInterface->GetChannelWidth()))
+    {
+        NS_LOG_DEBUG("Same RF channel as before on that interface, do nothing");
+        return;
+    }
+
+    ResetSpectrumModel(spectrumPhyInterface, frequency, width);
 }
 
 bool
-SpectrumWifiPhy::CanStartRx(Ptr<const WifiPpdu> ppdu, uint16_t txWidth) const
+SpectrumWifiPhy::CanStartRx(Ptr<const WifiPpdu> ppdu) const
 {
-    return GetLatestPhyEntity()->CanStartRx(ppdu, txWidth);
+    return GetLatestPhyEntity()->CanStartRx(ppdu);
 }
 
 void
@@ -348,10 +448,10 @@
 
     if (GetStandard() >= WIFI_STANDARD_80211ax)
     {
-        const auto& ruBands =
-            interface ? interface->GetRuBands() : m_currentSpectrumPhyInterface->GetRuBands();
-        NS_ASSERT(!ruBands.empty());
-        for (const auto& [band, ru] : ruBands)
+        const auto& heRuBands =
+            interface ? interface->GetHeRuBands() : m_currentSpectrumPhyInterface->GetHeRuBands();
+        NS_ASSERT(!heRuBands.empty());
+        for (const auto& [band, ru] : heRuBands)
         {
             double rxPowerPerBandW =
                 WifiSpectrumValueHelper::GetBandPowerW(receivedSignalPsd, band.indices);
@@ -405,23 +505,21 @@
     // 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
-    const auto txWidth = wifiRxParams->txWidth;
-    const auto& ppdu = GetRxPpduFromTxPpdu(wifiRxParams->ppdu);
-    const auto& txVector = ppdu->GetTxVector();
-    if (totalRxPowerW < DbmToW(GetRxSensitivity()) * (txWidth / 20.0))
+    const auto ppdu = GetRxPpduFromTxPpdu(wifiRxParams->ppdu);
+    if (totalRxPowerW < DbmToW(GetRxSensitivity()) * (ppdu->GetTxChannelWidth() / 20.0))
     {
         NS_LOG_INFO("Received signal too weak to process: " << WToDbm(totalRxPowerW) << " dBm");
-        m_interference->Add(ppdu, txVector, rxDuration, rxPowerW);
+        m_interference->Add(ppdu, rxDuration, rxPowerW);
         SwitchMaybeToCcaBusy(nullptr);
         return;
     }
 
     if (wifiRxParams->txPhy)
     {
-        if (!CanStartRx(ppdu, txWidth))
+        if (!CanStartRx(ppdu))
         {
             NS_LOG_INFO("Cannot start reception of the PPDU, consider it as interference");
-            m_interference->Add(ppdu, txVector, rxDuration, rxPowerW);
+            m_interference->Add(ppdu, rxDuration, rxPowerW);
             SwitchMaybeToCcaBusy(ppdu);
             return;
         }
@@ -499,18 +597,19 @@
 }
 
 WifiSpectrumBandInfo
-SpectrumWifiPhy::GetBand(uint16_t bandWidth, uint8_t bandIndex /* = 0 */)
-{
-    auto channelWidth = GetChannelWidth();
-    auto subcarrierSpacing = GetSubcarrierSpacing();
+SpectrumWifiPhy::GetBandForInterface(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
+                                     uint16_t bandWidth,
+                                     uint8_t bandIndex /* = 0 */)
+{
+    const auto subcarrierSpacing = GetSubcarrierSpacing();
+    const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
+    const auto numBandsInBand = static_cast<size_t>(bandWidth * 1e6 / subcarrierSpacing);
     auto numBandsInChannel = static_cast<size_t>(channelWidth * 1e6 / subcarrierSpacing);
-    auto numBandsInBand = static_cast<size_t>(bandWidth * 1e6 / subcarrierSpacing);
     if (numBandsInBand % 2 == 0)
     {
         numBandsInChannel += 1; // symmetry around center frequency
     }
-    NS_ABORT_IF(!m_currentSpectrumPhyInterface);
-    auto rxSpectrumModel = m_currentSpectrumPhyInterface->GetRxSpectrumModel();
+    auto rxSpectrumModel = spectrumPhyInterface->GetRxSpectrumModel();
     size_t totalNumBands = rxSpectrumModel->GetNumBands();
     NS_ASSERT_MSG((numBandsInChannel % 2 == 1) && (totalNumBands % 2 == 1),
                   "Should have odd number of bands");
@@ -518,8 +617,9 @@
     NS_ASSERT(totalNumBands >= numBandsInChannel);
     auto startIndex = ((totalNumBands - numBandsInChannel) / 2) + (bandIndex * numBandsInBand);
     auto stopIndex = startIndex + numBandsInBand - 1;
-    auto frequencies = ConvertIndicesToFrequencies({startIndex, stopIndex});
-    auto freqRange = m_currentSpectrumPhyInterface->GetFrequencyRange();
+    auto frequencies =
+        ConvertIndicesToFrequenciesForInterface(spectrumPhyInterface, {startIndex, stopIndex});
+    auto freqRange = spectrumPhyInterface->GetFrequencyRange();
     NS_ASSERT(frequencies.first >= (freqRange.minFrequency * 1e6));
     NS_ASSERT(frequencies.second <= (freqRange.maxFrequency * 1e6));
     NS_ASSERT((frequencies.second - frequencies.first) == (bandWidth * 1e6));
@@ -531,11 +631,27 @@
     return {{startIndex, stopIndex}, frequencies};
 }
 
+WifiSpectrumBandInfo
+SpectrumWifiPhy::GetBand(uint16_t bandWidth, uint8_t bandIndex /* = 0 */)
+{
+    NS_ABORT_IF(!m_currentSpectrumPhyInterface);
+    return GetBandForInterface(m_currentSpectrumPhyInterface, bandWidth, bandIndex);
+}
+
 WifiSpectrumBandFrequencies
 SpectrumWifiPhy::ConvertIndicesToFrequencies(const WifiSpectrumBandIndices& indices) const
 {
     NS_ABORT_IF(!m_currentSpectrumPhyInterface);
-    auto rxSpectrumModel = m_currentSpectrumPhyInterface->GetRxSpectrumModel();
+    return ConvertIndicesToFrequenciesForInterface(m_currentSpectrumPhyInterface, indices);
+}
+
+WifiSpectrumBandFrequencies
+SpectrumWifiPhy::ConvertIndicesToFrequenciesForInterface(
+    Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
+    const WifiSpectrumBandIndices& indices) const
+{
+    NS_ABORT_IF(!spectrumPhyInterface);
+    auto rxSpectrumModel = spectrumPhyInterface->GetRxSpectrumModel();
     auto startGuardBand = rxSpectrumModel->Begin();
     auto startChannel = std::next(startGuardBand, indices.first);
     auto endChannel = std::next(startGuardBand, indices.second + 1);
@@ -559,6 +675,12 @@
     return m_currentSpectrumPhyInterface->GetFrequencyRange();
 }
 
+const std::map<FrequencyRange, Ptr<WifiSpectrumPhyInterface>>&
+SpectrumWifiPhy::GetSpectrumPhyInterfaces() const
+{
+    return m_spectrumPhyInterfaces;
+}
+
 Ptr<WifiSpectrumPhyInterface>
 SpectrumWifiPhy::GetInterfaceCoveringChannelBand(uint16_t frequency, uint16_t width) const
 {
@@ -583,4 +705,10 @@
     return m_currentSpectrumPhyInterface;
 }
 
+void
+SpectrumWifiPhy::SetChannelSwitchedCallback(Callback<void> callback)
+{
+    m_channelSwitchedCallback = callback;
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/spectrum-wifi-phy.h ns-3.40/src/wifi/model/spectrum-wifi-phy.h
--- ns-3.39/src/wifi/model/spectrum-wifi-phy.h	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/spectrum-wifi-phy.h	2023-09-27 13:30:37.914839700 -0700
@@ -42,6 +42,9 @@
 class WifiSpectrumPhyInterface;
 struct WifiSpectrumSignalParameters;
 
+/// Map a spectrum band associated with an RU to the RU specification
+using HeRuBands = std::map<WifiSpectrumBandInfo, HeRu::RuSpec>;
+
 /**
  * \brief 802.11 PHY layer model
  * \ingroup wifi
@@ -131,9 +134,17 @@
                                           double rxPower,
                                           Time duration);
 
-    // The following method calls the base WifiPhy class method
-    // but also generates a new SpectrumModel if called during runtime
-    void DoChannelSwitch() override;
+    /**
+     * Configure a non-active spectrum PHY interface to operate on a given frequency with a given
+     * width. The function searches for the non-active PHY interface that operates on the frequency
+     * range corresponding to the spectrum portion specified by the caller. It takes care to
+     * configure the RX spectrum model of the PHY interface and to update the bands tracked in
+     * interference helper.
+     *
+     * \param frequency the center frequency in MHz the PHY interface should use
+     * \param width the channel width in MHz the PHY interface should use
+     */
+    void ConfigureInterface(uint16_t frequency, uint16_t width);
 
     /**
      * This function is sending the signal to the Spectrum channel
@@ -158,10 +169,26 @@
      */
     Ptr<WifiSpectrumPhyInterface> GetCurrentInterface() const;
 
+    /**
+     * Get the map of interfaces attached to this spectrum PHY
+     *
+     * \return the map of interfaces attached to this spectrum PHY
+     */
+    const std::map<FrequencyRange, Ptr<WifiSpectrumPhyInterface>>& GetSpectrumPhyInterfaces() const;
+
+    /**
+     * \param callback the callback to invoke when operating channel has switched.
+     */
+    void SetChannelSwitchedCallback(Callback<void> callback);
+
   protected:
     void DoDispose() override;
     void DoInitialize() override;
 
+    // The following method calls the base WifiPhy class method
+    // but also generates a new SpectrumModel if called during runtime
+    void DoChannelSwitch() override;
+
     std::map<FrequencyRange, Ptr<WifiSpectrumPhyInterface>>
         m_spectrumPhyInterfaces; //!< Spectrum PHY interfaces
 
@@ -171,26 +198,72 @@
 
   private:
     /**
-     * Perform run-time spectrum model change if the one used by the current Spectrum PHY interface
-     * has changed
-     */
-    void ResetSpectrumModelIfNeeded();
+     * Perform run-time spectrum model change
+     * \param spectrumPhyInterface the spectrum PHY interface for which the spectrum model should be
+     * changed \param centerFrequency the center frequency in MHz the PHY interface should use
+     * \param channelWidth the channel width in MHz the PHY interface should use
+     */
+    void ResetSpectrumModel(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
+                            uint16_t centerFrequency,
+                            uint16_t channelWidth);
 
     /**
      * This function is called to update the bands handled by the InterferenceHelper.
+     * \param spectrumPhyInterface the spectrum PHY interface for which the bands should be updated
      */
-    void UpdateInterferenceHelperBands();
+    void UpdateInterferenceHelperBands(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface);
+
+    /**
+     * This function computes the RU bands that belong to a given spectrum PHY interface.
+     *
+     * \param spectrumPhyInterface the spectrum PHY interface to consider to compute the RU bands
+     * \param guardBandwidth width of the guard band in MHz
+     * \returns the computed RU bands for the spectrum PHY interface
+     */
+    HeRuBands GetHeRuBands(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
+                           uint16_t guardBandwidth);
+
+    /**
+     * This function computes the bands that belong to a given spectrum PHY interface.
+     *
+     * \param spectrumPhyInterface the spectrum PHY interface to consider to compute the bands
+     * \returns the computed bands for the spectrum PHY interface
+     */
+    WifiSpectrumBands ComputeBands(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface);
+
+    /**
+     * Get the info of a given band that belongs to a given spectrum PHY interface
+     *
+     * \param spectrumPhyInterface the spectrum PHY interface
+     * \param bandWidth the width of the band to be returned (MHz)
+     * \param bandIndex the index of the band to be returned
+     *
+     * \return the info that defines the band
+     */
+    WifiSpectrumBandInfo GetBandForInterface(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
+                                             uint16_t bandWidth,
+                                             uint8_t bandIndex = 0);
+
+    /**
+     * This is a helper function to convert start and stop indices to start and stop frequencies.
+     *
+     * \param spectrumPhyInterface the spectrum PHY interface to consider for the calculations
+     * \param indices the start/stop indices to convert
+     * \return the converted frequencies
+     */
+    WifiSpectrumBandFrequencies ConvertIndicesToFrequenciesForInterface(
+        Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
+        const WifiSpectrumBandIndices& indices) const;
 
     /**
      * Determine whether the PHY shall issue a PHY-RXSTART.indication primitive in response to a
      * given PPDU.
      *
      * \param ppdu the PPDU
-     * \param txChannelWidth the channel width (MHz) used to transmit the PPDU
      * \return true if the PHY shall issue a PHY-RXSTART.indication primitive in response to a PPDU,
      * false otherwise
      */
-    bool CanStartRx(Ptr<const WifiPpdu> ppdu, uint16_t txChannelWidth) const;
+    bool CanStartRx(Ptr<const WifiPpdu> ppdu) const;
 
     /**
      * Get the spectrum PHY interface that covers a band portion of the RF channel
@@ -202,6 +275,11 @@
     Ptr<WifiSpectrumPhyInterface> GetInterfaceCoveringChannelBand(uint16_t frequency,
                                                                   uint16_t width) const;
 
+    /**
+     * Notify the spectrum channel has switched
+     */
+    void NotifyChannelSwitched();
+
     Ptr<AntennaModel> m_antenna; //!< antenna model
 
     bool m_disableWifiReception;           //!< forces this PHY to fail to sync on any signal
@@ -216,6 +294,8 @@
                                               //!< of the transmit spectrum mask
     double m_txMaskOuterBandMaximumRejection; //!< The maximum rejection (in dBr) for the outer band
                                               //!< of the transmit spectrum mask
+
+    Callback<void> m_channelSwitchedCallback; //!< Callback when channel switched
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/sta-wifi-mac.cc ns-3.40/src/wifi/model/sta-wifi-mac.cc
--- ns-3.39/src/wifi/model/sta-wifi-mac.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/sta-wifi-mac.cc	2023-09-27 13:30:37.914839700 -0700
@@ -31,6 +31,7 @@
 #include "wifi-net-device.h"
 #include "wifi-phy.h"
 
+#include "ns3/attribute-container.h"
 #include "ns3/eht-configuration.h"
 #include "ns3/emlsr-manager.h"
 #include "ns3/he-configuration.h"
@@ -162,6 +163,20 @@
 StaWifiMac::DoInitialize()
 {
     NS_LOG_FUNCTION(this);
+    // an EMLSR client must perform ML setup by using its main PHY
+    if (m_assocManager && m_emlsrManager)
+    {
+        auto mainPhyId = m_emlsrManager->GetMainPhyId();
+        auto linkId = GetLinkForPhy(mainPhyId);
+        NS_ASSERT(linkId);
+        m_assocManager->SetAttribute(
+            "AllowedLinks",
+            AttributeContainerValue<UintegerValue>(std::list<uint8_t>{*linkId}));
+    }
+    if (m_emlsrManager)
+    {
+        m_emlsrManager->Initialize();
+    }
     StartScanning();
     NS_ABORT_IF(!TraceConnectWithoutContext("AckedMpdu", MakeCallback(&StaWifiMac::TxOk, this)));
     WifiMac::DoInitialize();
@@ -206,6 +221,12 @@
     return static_cast<StaLinkEntity&>(WifiMac::GetLink(linkId));
 }
 
+StaWifiMac::StaLinkEntity&
+StaWifiMac::GetStaLink(const std::unique_ptr<WifiMac::LinkEntity>& link) const
+{
+    return static_cast<StaLinkEntity&>(*link);
+}
+
 int64_t
 StaWifiMac::AssignStreams(int64_t stream)
 {
@@ -283,6 +304,39 @@
 }
 
 void
+StaWifiMac::NotifyEmlsrModeChanged(const std::set<uint8_t>& linkIds)
+{
+    NS_LOG_FUNCTION(this << linkIds.size());
+
+    for (const auto& [linkId, lnk] : GetLinks())
+    {
+        auto& link = GetStaLink(lnk);
+
+        if (linkIds.count(linkId) > 0)
+        {
+            // EMLSR mode enabled
+            link.emlsrEnabled = true;
+            link.pmMode = WIFI_PM_ACTIVE;
+        }
+        else
+        {
+            // EMLSR mode disabled
+            if (link.emlsrEnabled)
+            {
+                link.pmMode = WIFI_PM_POWERSAVE;
+            }
+            link.emlsrEnabled = false;
+        }
+    }
+}
+
+bool
+StaWifiMac::IsEmlsrLink(uint8_t linkId) const
+{
+    return GetLink(linkId).emlsrEnabled;
+}
+
+void
 StaWifiMac::SendProbeRequest(uint8_t linkId)
 {
     NS_LOG_FUNCTION(this << linkId);
@@ -411,14 +465,32 @@
         // (Section 9.4.2.312.2.3 of 802.11be D2.3)
     }
 
+    // The MLD Capabilities And Operations subfield is present in the Common Info field of the
+    // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
+    // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
+    auto& mldCapabilities = multiLinkElement.GetCommonInfoBasic().m_mldCapabilities;
+    mldCapabilities.emplace();
+    mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
+    mldCapabilities->srsSupport = 0;
+
+    auto ehtConfiguration = GetEhtConfiguration();
+    NS_ASSERT(ehtConfiguration);
+    EnumValue negSupport;
+    ehtConfiguration->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
+
+    mldCapabilities->tidToLinkMappingSupport = negSupport.Get();
+    mldCapabilities->freqSepForStrApMld = 0; // not supported yet
+    mldCapabilities->aarSupport = 0;         // not supported yet
+
     // For each requested link in addition to the link on which the (Re)Association Request
     // frame is transmitted, the Link Info field of the Basic Multi-Link element carried
     // in the (Re)Association Request frame shall contain the corresponding Per-STA Profile
     // subelement(s).
-    for (uint8_t index = 0; index < GetNLinks(); index++)
+    for (const auto& [index, link] : GetLinks())
     {
-        auto& link = GetLink(index);
-        if (index != linkId && link.apLinkId.has_value())
+        const auto& staLink = GetStaLink(link);
+
+        if (index != linkId && staLink.bssid.has_value())
         {
             multiLinkElement.AddPerStaProfileSubelement();
             auto& perStaProfile = multiLinkElement.GetPerStaProfile(
@@ -427,7 +499,7 @@
             // for the corresponding non-AP STA that requests a link for multi-link (re)setup
             // with the AP MLD is set to the link ID of the AP affiliated with the AP MLD that
             // is operating on that link. The link ID is obtained during multi-link discovery
-            perStaProfile.SetLinkId(link.apLinkId.value());
+            perStaProfile.SetLinkId(index);
             // For each Per-STA Profile subelement included in the Link Info field, the
             // Complete Profile subfield of the STA Control field shall be set to 1
             perStaProfile.SetCompleteProfile();
@@ -435,7 +507,7 @@
             // subfield in the STA Info field and is set to 1 if the STA MAC Address subfield
             // is present in the STA Info field; otherwise set to 0. An STA sets this subfield
             // to 1 when the element carries complete profile.
-            perStaProfile.SetStaMacAddress(link.feManager->GetAddress());
+            perStaProfile.SetStaMacAddress(staLink.feManager->GetAddress());
             perStaProfile.SetAssocRequest(GetAssociationRequest(isReassoc, index));
         }
     }
@@ -443,20 +515,92 @@
     return multiLinkElement;
 }
 
+std::vector<TidToLinkMapping>
+StaWifiMac::GetTidToLinkMappingElements(uint8_t apNegSupport)
+{
+    NS_LOG_FUNCTION(this << apNegSupport);
+
+    auto ehtConfig = GetEhtConfiguration();
+    NS_ASSERT(ehtConfig);
+
+    EnumValue negSupport;
+    ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
+
+    NS_ABORT_MSG_IF(negSupport.Get() == 0,
+                    "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
+    m_dlTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::DOWNLINK);
+    m_ulTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::UPLINK);
+
+    bool mappingValidForNegType1 = TidToLinkMappingValidForNegType1(m_dlTidLinkMappingInAssocReq,
+                                                                    m_ulTidLinkMappingInAssocReq);
+    NS_ABORT_MSG_IF(
+        negSupport.Get() == 1 && !mappingValidForNegType1,
+        "Mapping TIDs to distinct link sets is incompatible with negotiation support of 1");
+
+    if (apNegSupport == 1 && !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
+        // peer MLD shall send only the TID-to-link Mapping element where all TIDs are mapped to
+        // the same link set (Sec. 35.3.7.1.3 of 802.11be D3.1). We use default mapping to meet
+        // this requirement.
+        NS_LOG_DEBUG("Using default mapping because AP MLD advertised negotiation support of 1");
+        m_dlTidLinkMappingInAssocReq.clear();
+        m_ulTidLinkMappingInAssocReq.clear();
+    }
+
+    std::vector<TidToLinkMapping> ret(1);
+
+    ret.back().m_control.direction = WifiDirection::DOWNLINK;
+
+    // lambda to fill the last TID-to-Link Mapping IE in the vector to return
+    auto fillIe = [&ret](const auto& mapping) {
+        ret.back().m_control.defaultMapping = mapping.empty();
+
+        for (const auto& [tid, linkSet] : mapping)
+        {
+            // At any point in time, a TID shall always be mapped to at least one setup link both
+            // in DL and UL, which means that a TID-to-link mapping change is only valid and
+            // successful if it will not result in having any TID for which the link set for DL
+            // or UL is made of zero setup links (Sec. 35.3.7.1.1 of 802.11be D3.1)
+            NS_ABORT_MSG_IF(linkSet.empty(), "Cannot map a TID to an empty link set");
+            ret.back().SetLinkMappingOfTid(tid, linkSet);
+        }
+    };
+
+    fillIe(m_dlTidLinkMappingInAssocReq);
+
+    if (m_ulTidLinkMappingInAssocReq == m_dlTidLinkMappingInAssocReq)
+    {
+        ret.back().m_control.direction = WifiDirection::BOTH_DIRECTIONS;
+        return ret;
+    }
+
+    ret.emplace_back();
+    ret.back().m_control.direction = WifiDirection::UPLINK;
+    fillIe(m_ulTidLinkMappingInAssocReq);
+
+    return ret;
+}
+
 void
 StaWifiMac::SendAssociationRequest(bool isReassoc)
 {
     // find the link where the (Re)Association Request has to be sent
-    uint8_t linkId = 0;
-    while (linkId < GetNLinks())
+    auto it = GetLinks().cbegin();
+    while (it != GetLinks().cend())
     {
-        if (GetLink(linkId).sendAssocReq)
+        if (GetStaLink(it->second).sendAssocReq)
         {
             break;
         }
-        linkId++;
+        it++;
     }
-    NS_ABORT_MSG_IF(linkId == GetNLinks(), "No link selected to send the (Re)Association Request");
+    NS_ABORT_MSG_IF(it == GetLinks().cend(),
+                    "No link selected to send the (Re)Association Request");
+    uint8_t linkId = it->first;
     auto& link = GetLink(linkId);
     NS_ABORT_MSG_IF(!link.bssid.has_value(),
                     "No BSSID set for the link on which the (Re)Association Request is to be sent");
@@ -474,7 +618,9 @@
     auto frame = GetAssociationRequest(isReassoc, linkId);
 
     // include a Multi-Link Element if this device has multiple links (independently
-    // of how many links will be setup) and the AP is a multi-link device
+    // of how many links will be setup) and the AP is a multi-link device;
+    // if the AP MLD  has indicated a support of TID-to-link mapping negotiation, also
+    // include the TID-to-link Mapping element(s)
     if (GetNLinks() > 1 &&
         GetWifiRemoteStationManager(linkId)->GetMldAddress(*link.bssid).has_value())
     {
@@ -482,6 +628,17 @@
             frame.template Get<MultiLinkElement>() = GetMultiLinkElement(isReassoc, linkId);
         };
         std::visit(addMle, frame);
+
+        uint8_t negSupport;
+        if (const auto& mldCapabilities =
+                GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(*link.bssid);
+            mldCapabilities && (negSupport = mldCapabilities->get().tidToLinkMappingSupport) > 0)
+        {
+            auto addTlm = [&](auto&& frame) {
+                frame.template Get<TidToLinkMapping>() = GetTidToLinkMappingElements(negSupport);
+            };
+            std::visit(addTlm, frame);
+        }
     }
 
     if (!isReassoc)
@@ -567,12 +724,11 @@
 
     WifiScanParams scanParams;
     scanParams.ssid = GetSsid();
-    for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
+    for (const auto& [id, link] : GetLinks())
     {
         WifiScanParams::ChannelList channel{
-            (GetWifiPhy(linkId)->HasFixedPhyBand())
-                ? WifiScanParams::Channel{0, GetWifiPhy(linkId)->GetPhyBand()}
-                : WifiScanParams::Channel{0, WIFI_PHY_BAND_UNSPECIFIED}};
+            (link->phy->HasFixedPhyBand()) ? WifiScanParams::Channel{0, link->phy->GetPhyBand()}
+                                           : WifiScanParams::Channel{0, WIFI_PHY_BAND_UNSPECIFIED}};
 
         scanParams.channelList.push_back(channel);
     }
@@ -606,34 +762,37 @@
     NS_LOG_DEBUG("Attempting to associate with AP: " << *bestAp);
     UpdateApInfo(bestAp->m_frame, bestAp->m_apAddr, bestAp->m_bssid, bestAp->m_linkId);
     // reset info on links to setup
-    for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
+    for (auto& [id, link] : GetLinks())
     {
-        auto& link = GetLink(linkId);
-        link.sendAssocReq = false;
-        link.apLinkId = std::nullopt;
-        link.bssid = std::nullopt;
+        auto& staLink = GetStaLink(link);
+        staLink.sendAssocReq = false;
+        staLink.bssid = std::nullopt;
     }
     // send Association Request on the link where the Beacon/Probe Response was received
     GetLink(bestAp->m_linkId).sendAssocReq = true;
     GetLink(bestAp->m_linkId).bssid = bestAp->m_bssid;
+    std::shared_ptr<CommonInfoBasicMle> mleCommonInfo;
     // update info on links to setup (11be MLDs only)
-    for (const auto& [localLinkId, apLinkId] : bestAp->m_setupLinks)
+    const auto& mle =
+        std::visit([](auto&& frame) { return frame.template Get<MultiLinkElement>(); },
+                   bestAp->m_frame);
+    std::map<uint8_t, uint8_t> swapInfo;
+    for (const auto& [localLinkId, apLinkId, bssid] : bestAp->m_setupLinks)
     {
+        NS_ASSERT_MSG(mle, "We get here only for ML setup");
         NS_LOG_DEBUG("Setting up link (local ID=" << +localLinkId << ", AP ID=" << +apLinkId
                                                   << ")");
-        GetLink(localLinkId).apLinkId = apLinkId;
-        if (localLinkId == bestAp->m_linkId)
+        GetLink(localLinkId).bssid = bssid;
+        if (!mleCommonInfo)
         {
-            continue;
+            mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
         }
-        auto mldAddress =
-            GetWifiRemoteStationManager(bestAp->m_linkId)->GetMldAddress(bestAp->m_bssid);
-        NS_ABORT_MSG_IF(!mldAddress.has_value(), "AP MLD address not set");
-        auto bssid = GetWifiRemoteStationManager(localLinkId)->GetAffiliatedStaAddress(*mldAddress);
-        NS_ABORT_MSG_IF(!mldAddress.has_value(),
-                        "AP link address not set for local link " << +localLinkId);
-        GetLink(localLinkId).bssid = *bssid;
+        GetWifiRemoteStationManager(localLinkId)->AddStationMleCommonInfo(bssid, mleCommonInfo);
+        swapInfo.emplace(localLinkId, apLinkId);
     }
+
+    SwapLinks(swapInfo);
+
     // lambda to get beacon interval from Beacon or Probe Response
     auto getBeaconInterval = [](auto&& frame) {
         using T = std::decay_t<decltype(frame)>;
@@ -651,11 +810,11 @@
     Time beaconInterval = std::visit(getBeaconInterval, bestAp->m_frame);
     Time delay = beaconInterval * m_maxMissedBeacons;
     // restart beacon watchdog for all links to setup
-    for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
+    for (const auto& [id, link] : GetLinks())
     {
-        if (GetLink(linkId).apLinkId.has_value() || GetNLinks() == 1)
+        if (GetStaLink(link).bssid.has_value() || GetNLinks() == 1)
         {
-            RestartBeaconWatchdog(delay, linkId);
+            RestartBeaconWatchdog(delay, id);
         }
     }
     SetState(WAIT_ASSOC_RESP);
@@ -705,20 +864,19 @@
     NS_LOG_FUNCTION(this << +linkId);
 
     auto& link = GetLink(linkId);
-    if (link.apLinkId.has_value())
+    if (link.bssid.has_value())
     {
         // this is a link setup in an ML setup
         m_setupCanceled(linkId, GetBssid(linkId));
     }
 
     // disable the given link
-    link.apLinkId = std::nullopt;
     link.bssid = std::nullopt;
     link.phy->SetOffMode();
 
-    for (uint8_t id = 0; id < GetNLinks(); id++)
+    for (const auto& [id, lnk] : GetLinks())
     {
-        if (GetLink(id).apLinkId.has_value())
+        if (GetStaLink(lnk).bssid.has_value())
         {
             // found an enabled link
             return;
@@ -741,9 +899,9 @@
     }
     m_aid = 0; // reset AID
     // ensure all links are on
-    for (uint8_t id = 0; id < GetNLinks(); id++)
+    for (const auto& [id, lnk] : GetLinks())
     {
-        GetLink(id).phy->ResumeFromOff();
+        lnk->phy->ResumeFromOff();
     }
     TryToEnsureAssociated();
 }
@@ -782,22 +940,16 @@
     }
 
     std::set<uint8_t> linkIds;
-    for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
+    for (const auto& [id, link] : GetLinks())
     {
-        if (GetLink(linkId).bssid)
+        if (GetStaLink(link).bssid)
         {
-            linkIds.insert(linkId);
+            linkIds.insert(id);
         }
     }
     return linkIds;
 }
 
-std::optional<uint8_t>
-StaWifiMac::GetApLinkId(uint8_t linkId) const
-{
-    return GetLink(linkId).apLinkId;
-}
-
 Mac48Address
 StaWifiMac::DoGetLocalAddress(const Mac48Address& remoteAddr) const
 {
@@ -899,6 +1051,50 @@
 }
 
 void
+StaWifiMac::BlockTxOnLink(uint8_t linkId, WifiQueueBlockedReason reason)
+{
+    NS_LOG_FUNCTION(this << linkId << reason);
+
+    auto bssid = GetBssid(linkId);
+    auto apAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
+
+    BlockUnicastTxOnLinks(reason, apAddress, {linkId});
+    // the only type of broadcast frames that a non-AP STA can send are management frames
+    for (const auto [acIndex, ac] : wifiAcList)
+    {
+        GetMacQueueScheduler()->BlockQueues(reason,
+                                            acIndex,
+                                            {WIFI_MGT_QUEUE},
+                                            Mac48Address::GetBroadcast(),
+                                            GetFrameExchangeManager(linkId)->GetAddress(),
+                                            {},
+                                            {linkId});
+    }
+}
+
+void
+StaWifiMac::UnblockTxOnLink(uint8_t linkId, WifiQueueBlockedReason reason)
+{
+    NS_LOG_FUNCTION(this << linkId << reason);
+
+    auto bssid = GetBssid(linkId);
+    auto apAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
+
+    UnblockUnicastTxOnLinks(reason, apAddress, {linkId});
+    // the only type of broadcast frames that a non-AP STA can send are management frames
+    for (const auto [acIndex, ac] : wifiAcList)
+    {
+        GetMacQueueScheduler()->UnblockQueues(reason,
+                                              acIndex,
+                                              {WIFI_MGT_QUEUE},
+                                              Mac48Address::GetBroadcast(),
+                                              GetFrameExchangeManager(linkId)->GetAddress(),
+                                              {},
+                                              {linkId});
+    }
+}
+
+void
 StaWifiMac::Receive(Ptr<const WifiMpdu> mpdu, uint8_t linkId)
 {
     NS_LOG_FUNCTION(this << *mpdu << +linkId);
@@ -1128,22 +1324,57 @@
         UpdateApInfo(assocResp, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
         NS_ASSERT(GetLink(linkId).bssid.has_value() && *GetLink(linkId).bssid == hdr.GetAddr3());
         SetBssid(hdr.GetAddr3(), linkId);
+        SetState(ASSOCIATED);
         if ((GetNLinks() > 1) && assocResp.Get<MultiLinkElement>().has_value())
         {
             // this is an ML setup, trace the setup link
             m_setupCompleted(linkId, hdr.GetAddr3());
             apMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(hdr.GetAddr3());
+            NS_ASSERT(apMldAddress);
+
+            if (const auto& mldCapabilities =
+                    GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(hdr.GetAddr3());
+                mldCapabilities && mldCapabilities->get().tidToLinkMappingSupport > 0)
+            {
+                // the AP MLD supports TID-to-Link Mapping negotiation, hence we included
+                // TID-to-Link Mapping element(s) in the Association Request.
+                if (assocResp.Get<TidToLinkMapping>().empty())
+                {
+                    // The AP MLD did not include a TID-to-Link Mapping element in the Association
+                    // Response, hence it accepted the mapping, which we can now store.
+                    UpdateTidToLinkMapping(*apMldAddress,
+                                           WifiDirection::DOWNLINK,
+                                           m_dlTidLinkMappingInAssocReq);
+                    UpdateTidToLinkMapping(*apMldAddress,
+                                           WifiDirection::UPLINK,
+                                           m_ulTidLinkMappingInAssocReq);
+
+                    // Apply the negotiated TID-to-Link Mapping (if any) for UL direction
+                    ApplyTidLinkMapping(*apMldAddress, WifiDirection::UPLINK);
+                }
+            }
         }
         else
         {
             m_assocLogger(hdr.GetAddr3());
         }
-        SetState(ASSOCIATED);
         if (!m_linkUp.IsNull())
         {
             m_linkUp();
         }
     }
+    else
+    {
+        // If the link on which the (Re)Association Request frame was received cannot be
+        // accepted by the AP MLD, the AP MLD shall treat the multi-link (re)setup as a
+        // failure and shall not accept any requested links. If the link on which the
+        // (Re)Association Request frame was received is accepted by the AP MLD, the
+        // multi-link (re)setup is successful. (Sec. 35.3.5.1 of 802.11be D3.1)
+        NS_LOG_DEBUG("association refused");
+        SetState(REFUSED);
+        StartScanning();
+        return;
+    }
 
     // if this is an MLD, check if we can setup (other) links
     if (GetNLinks() > 1)
@@ -1151,8 +1382,11 @@
         // create a list of all local Link IDs. IDs are removed as we find a corresponding
         // Per-STA Profile Subelements indicating successful association. Links with
         // remaining IDs are not setup
-        std::list<uint8_t> setupLinks(GetNLinks());
-        std::iota(setupLinks.begin(), setupLinks.end(), 0);
+        std::list<uint8_t> setupLinks;
+        for (const auto& [id, link] : GetLinks())
+        {
+            setupLinks.push_back(id);
+        }
         if (assocResp.GetStatusCode().IsSuccess())
         {
             setupLinks.remove(linkId);
@@ -1161,10 +1395,10 @@
         // if a Multi-Link Element is present, check its content
         if (const auto& mle = assocResp.Get<MultiLinkElement>())
         {
-            NS_ABORT_MSG_IF(!GetLink(linkId).apLinkId.has_value(),
+            NS_ABORT_MSG_IF(!GetLink(linkId).bssid.has_value(),
                             "The link on which the Association Response was received "
                             "is not a link we requested to setup");
-            NS_ABORT_MSG_IF(*GetLink(linkId).apLinkId != mle->GetLinkIdInfo(),
+            NS_ABORT_MSG_IF(linkId != mle->GetLinkIdInfo(),
                             "The link ID of the AP that transmitted the Association "
                             "Response does not match the stored link ID");
             NS_ABORT_MSG_IF(GetWifiRemoteStationManager(linkId)->GetMldAddress(hdr.GetAddr2()) !=
@@ -1177,18 +1411,11 @@
             {
                 auto& perStaProfile = mle->GetPerStaProfile(elem);
                 uint8_t apLinkId = perStaProfile.GetLinkId();
+                auto it = GetLinks().find(apLinkId);
                 uint8_t staLinkid = 0;
-                while (staLinkid < GetNLinks())
-                {
-                    if (GetLink(staLinkid).apLinkId == apLinkId)
-                    {
-                        break;
-                    }
-                    staLinkid++;
-                }
                 std::optional<Mac48Address> bssid;
-                NS_ABORT_MSG_IF(staLinkid == GetNLinks() ||
-                                    !(bssid = GetLink(staLinkid).bssid).has_value(),
+                NS_ABORT_MSG_IF(it == GetLinks().cend() ||
+                                    !(bssid = GetLink((staLinkid = it->first)).bssid).has_value(),
                                 "Setup for AP link ID " << apLinkId << " was not requested");
                 NS_ABORT_MSG_IF(*bssid != perStaProfile.GetStaMacAddress(),
                                 "The BSSID in the Per-STA Profile for link ID "
@@ -1224,13 +1451,8 @@
         // remaining links in setupLinks are not setup and hence must be disabled
         for (const auto& id : setupLinks)
         {
-            GetLink(id).apLinkId = std::nullopt;
             GetLink(id).bssid = std::nullopt;
-            // if at least one link was setup, disable the links that were not setup (if any)
-            if (m_state == ASSOCIATED)
-            {
-                GetLink(id).phy->SetOffMode();
-            }
+            GetLink(id).phy->SetOffMode();
         }
         if (apMldAddress)
         {
@@ -1239,15 +1461,6 @@
         }
     }
 
-    if (m_state == WAIT_ASSOC_RESP)
-    {
-        // if we didn't transition to ASSOCIATED, the request was refused
-        NS_LOG_DEBUG("association refused");
-        SetState(REFUSED);
-        StartScanning();
-        return;
-    }
-
     SetPmModeAfterAssociation(linkId);
 }
 
@@ -1268,9 +1481,9 @@
             auto ackDuration =
                 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
 
-            for (uint8_t id = 0; id < GetNLinks(); id++)
+            for (const auto& [id, lnk] : GetLinks())
             {
-                auto& link = GetLink(id);
+                auto& link = GetStaLink(lnk);
 
                 if (!link.bssid)
                 {
@@ -1753,6 +1966,83 @@
     }
 }
 
+/**
+ * Initial configuration:
+ *
+ *        ┌───┬───┬───┐        ┌────┐       ┌───────┐
+ * Link A │FEM│RSM│CAM│◄──────►│Main├──────►│Channel│
+ *        │   │   │   │        │PHY │       │   A   │
+ *        └───┴───┴───┘        └────┘       └───────┘
+ *
+ *        ┌───┬───┬───┐        ┌────┐       ┌───────┐
+ * Link B │FEM│RSM│CAM│        │Aux │       │Channel│
+ *        │   │   │   │◄──────►│PHY ├──────►│   B   │
+ *        └───┴───┴───┘        └────┘       └───────┘
+ *
+ * A link switching/swapping is notified by the EMLSR Manager and the Channel Access Manager
+ * (CAM) notifies us that a first PHY (i.e., the Main PHY) switches to Channel B. We connect
+ * the Main PHY to the MAC stack B:
+ *
+ *
+ *        ┌───┬───┬───┐        ┌────┐       ┌───────┐
+ * Link A │FEM│RSM│CAM│   ┌───►│Main├───┐   │Channel│
+ *        │   │   │   │   │    │PHY │   │   │   A   │
+ *        └───┴───┴───┘   │    └────┘   │   └───────┘
+ *                        │             │
+ *        ┌───┬───┬───┐   │    ┌────┐   │   ┌───────┐
+ * Link B │FEM│RSM│CAM│◄──┘    │Aux │   └──►│Channel│
+ *        │   │   │   │◄─ ─ ─ ─│PHY ├──────►│   B   │
+ *        └───┴───┴───┘INACTIVE└────┘       └───────┘
+ *
+ * MAC stack B keeps a PHY listener associated with the Aux PHY, even though it is inactive,
+ * meaning that the PHY listener will only notify channel switches (no CCA, no RX).
+ * If the EMLSR Manager requested a link switching, this configuration will be kept until
+ * further requests. If the EMLSR Manager requested a link swapping, link B's CAM will be
+ * notified by its (inactive) PHY listener upon the channel switch performed by the Aux PHY.
+ * In this case, we remove the inactive PHY listener and connect the Aux PHY to MAC stack A:
+ *
+ *        ┌───┬───┬───┐        ┌────┐       ┌───────┐
+ * Link A │FEM│RSM│CAM│◄─┐ ┌──►│Main├───┐   │Channel│
+ *        │   │   │   │  │ │   │PHY │ ┌─┼──►│   A   │
+ *        └───┴───┴───┘  │ │   └────┘ │ │   └───────┘
+ *                       │ │          │ │
+ *        ┌───┬───┬───┐  │ │   ┌────┐ │ │   ┌───────┐
+ * Link B │FEM│RSM│CAM│◄─┼─┘   │Aux │ │ └──►│Channel│
+ *        │   │   │   │  └────►│PHY ├─┘     │   B   │
+ *        └───┴───┴───┘        └────┘       └───────┘
+ */
+
+void
+StaWifiMac::NotifySwitchingEmlsrLink(Ptr<WifiPhy> phy, uint8_t linkId)
+{
+    NS_LOG_FUNCTION(this << phy << linkId);
+
+    // if any link points to the PHY that switched channel, reset the phy pointer
+    for (auto& [id, link] : GetLinks())
+    {
+        // auto& link = GetStaLink(lnk);
+        if (link->phy == phy)
+        {
+            link->phy = nullptr;
+        }
+    }
+
+    auto& newLink = GetLink(linkId);
+    // The MAC stack associated with the new link uses the given PHY
+    newLink.phy = phy;
+    // Setup a PHY listener for the given PHY on the CAM associated with the new link
+    newLink.channelAccessManager->SetupPhyListener(phy);
+    NS_ASSERT(m_emlsrManager);
+    if (m_emlsrManager->GetCamStateReset())
+    {
+        newLink.channelAccessManager->ResetState();
+    }
+    // Disconnect the FEM on the new link from the current PHY
+    newLink.feManager->ResetPhy();
+    // Connect the FEM on the new link to the given PHY
+    newLink.feManager->SetWifiPhy(phy);
+}
+
 void
 StaWifiMac::NotifyChannelSwitching(uint8_t linkId)
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/sta-wifi-mac.h ns-3.40/src/wifi/model/sta-wifi-mac.h
--- ns-3.39/src/wifi/model/sta-wifi-mac.h	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/sta-wifi-mac.h	2023-09-27 13:30:37.914839700 -0700
@@ -162,14 +162,24 @@
      */
     struct ApInfo
     {
+        /**
+         * Information about links to setup
+         */
+        struct SetupLinksInfo
+        {
+            uint8_t localLinkId; ///< local link ID
+            uint8_t apLinkId;    ///< AP link ID
+            Mac48Address bssid;  ///< BSSID
+        };
+
         Mac48Address m_bssid;  ///< BSSID
         Mac48Address m_apAddr; ///< AP MAC address
         double m_snr;          ///< SNR in linear scale
         MgtFrameType m_frame;  ///< The body of the management frame used to update AP info
         WifiScanParams::Channel m_channel; ///< The channel the management frame was received on
         uint8_t m_linkId;                  ///< ID of the link used to communicate with the AP
-        /// list of (local link ID, AP link ID) pairs identifying the links to setup between MLDs
-        std::list<std::pair<uint8_t, uint8_t>> m_setupLinks;
+        std::list<SetupLinksInfo>
+            m_setupLinks; ///< information about the links to setup between MLDs
     };
 
     /**
@@ -247,12 +257,6 @@
     std::set<uint8_t> GetSetupLinkIds() const;
 
     /**
-     * \param linkId the IO of the given link
-     * \return the ID (as set by the AP) of the given link, if the given link has been setup
-     */
-    std::optional<uint8_t> GetApLinkId(uint8_t linkId) const;
-
-    /**
      * Return the association ID.
      *
      * \return the association ID
@@ -291,6 +295,44 @@
     void NotifyChannelSwitching(uint8_t linkId) override;
 
     /**
+     * Notify the MAC that EMLSR mode has changed on the given set of links.
+     *
+     * \param linkIds the IDs of the links that are now EMLSR links (EMLSR mode is disabled
+     *                on other links)
+     */
+    void NotifyEmlsrModeChanged(const std::set<uint8_t>& linkIds);
+
+    /**
+     * \param linkId the ID of the given link
+     * \return whether the EMLSR mode is enabled on the given link
+     */
+    bool IsEmlsrLink(uint8_t linkId) const;
+
+    /**
+     * Notify that the given PHY switched channel to operate on another EMLSR link.
+     *
+     * \param phy the given PHY
+     * \param linkId the ID of the EMLSR link on which the given PHY is operating
+     */
+    void NotifySwitchingEmlsrLink(Ptr<WifiPhy> phy, uint8_t linkId);
+
+    /**
+     * Block transmissions on the given link for the given reason.
+     *
+     * \param linkId the ID of the given link
+     * \param reason the reason for blocking transmissions on the given link
+     */
+    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.
@@ -314,14 +356,13 @@
 
         bool sendAssocReq;                 //!< whether this link is used to send the
                                            //!< Association Request frame
-        std::optional<uint8_t> apLinkId;   //!< ID (as set by the AP) of the link we have
-                                           //!< setup or are setting up
         std::optional<Mac48Address> bssid; //!< BSSID of the AP to associate with over this link
         EventId beaconWatchdog;            //!< beacon watchdog
         Time beaconWatchdogEnd{0};         //!< beacon watchdog end
         WifiPowerManagementMode pmMode{WIFI_PM_ACTIVE}; /**< the current PM mode, if the STA is
                                                              associated, or the PM mode to switch
                                                              to upon association, otherwise */
+        bool emlsrEnabled{false}; //!< whether EMLSR mode is enabled on this link
     };
 
     /**
@@ -332,7 +373,15 @@
      */
     StaLinkEntity& GetLink(uint8_t linkId) const;
 
-  private:
+    /**
+     * Cast the given LinkEntity object to StaLinkEntity.
+     *
+     * \param link the given LinkEntity object
+     * \return a reference to the object casted to StaLinkEntity
+     */
+    StaLinkEntity& GetStaLink(const std::unique_ptr<WifiMac::LinkEntity>& link) const;
+
+  public:
     /**
      * The current MAC state of the STA.
      */
@@ -345,6 +394,7 @@
         REFUSED
     };
 
+  private:
     /**
      * Enable or disable active probing.
      *
@@ -494,6 +544,13 @@
      * \return the Multi-Link Element
      */
     MultiLinkElement GetMultiLinkElement(bool isReassoc, uint8_t linkId) const;
+
+    /**
+     * \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);
+
     /**
      * Set the current MAC state.
      *
@@ -580,6 +637,11 @@
                                             ///< of the first Probe Response on each channel
     Time m_pmModeSwitchTimeout;             ///< PM mode switch timeout
 
+    /// store the DL TID-to-Link Mapping included in the Association Request frame
+    WifiTidLinkMapping m_dlTidLinkMappingInAssocReq;
+    /// store the UL TID-to-Link Mapping included in the Association Request frame
+    WifiTidLinkMapping m_ulTidLinkMappingInAssocReq;
+
     TracedCallback<Mac48Address> m_assocLogger;             ///< association logger
     TracedCallback<uint8_t, Mac48Address> m_setupCompleted; ///< link setup completed logger
     TracedCallback<Mac48Address> m_deAssocLogger;           ///< disassociation logger
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/supported-rates.cc ns-3.40/src/wifi/model/supported-rates.cc
--- ns-3.39/src/wifi/model/supported-rates.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/supported-rates.cc	2023-09-27 13:30:37.914839700 -0700
@@ -21,6 +21,8 @@
 
 #include "ns3/log.h"
 
+#include <algorithm>
+
 namespace ns3
 {
 
@@ -95,7 +97,7 @@
 {
     NS_LOG_FUNCTION(this << bs);
     NS_ASSERT_MSG(IsBssMembershipSelectorRate(bs) == false, "Invalid rate");
-    uint8_t rate = static_cast<uint8_t>(bs / 500000);
+    auto rate = static_cast<uint8_t>(bs / 500000);
     for (uint8_t i = 0; i < GetNRates(); i++)
     {
         auto& currRate = i < 8 ? rates.m_rates[i] : extendedRates->m_rates[i - 8];
@@ -121,7 +123,7 @@
     NS_ASSERT_MSG(bs == BSS_MEMBERSHIP_SELECTOR_HT_PHY || bs == BSS_MEMBERSHIP_SELECTOR_VHT_PHY ||
                       bs == BSS_MEMBERSHIP_SELECTOR_HE_PHY || bs == BSS_MEMBERSHIP_SELECTOR_EHT_PHY,
                   "Value " << bs << " not a BSS Membership Selector");
-    uint8_t rate = static_cast<uint8_t>(bs / 500000);
+    auto rate = static_cast<uint8_t>(bs / 500000);
     for (std::size_t i = 0; i < rates.m_rates.size(); i++)
     {
         if (rate == rates.m_rates[i])
@@ -158,7 +160,7 @@
 AllSupportedRates::IsSupportedRate(uint64_t bs) const
 {
     NS_LOG_FUNCTION(this << bs);
-    uint8_t rate = static_cast<uint8_t>(bs / 500000);
+    auto rate = static_cast<uint8_t>(bs / 500000);
     for (std::size_t i = 0; i < rates.m_rates.size(); i++)
     {
         if (rate == rates.m_rates[i] || (rate | 0x80) == rates.m_rates[i])
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/txop.cc ns-3.40/src/wifi/model/txop.cc
--- ns-3.39/src/wifi/model/txop.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/txop.cc	2023-09-27 13:30:37.914839700 -0700
@@ -169,15 +169,33 @@
 Txop::LinkEntity&
 Txop::GetLink(uint8_t linkId) const
 {
-    NS_ASSERT(linkId < m_links.size());
-    NS_ASSERT(m_links.at(linkId)); // check that the pointer owns an object
-    return *m_links.at(linkId);
+    auto it = m_links.find(linkId);
+    NS_ASSERT(it != m_links.cend());
+    NS_ASSERT(it->second); // check that the pointer owns an object
+    return *it->second;
 }
 
-uint8_t
-Txop::GetNLinks() const
+const std::map<uint8_t, std::unique_ptr<Txop::LinkEntity>>&
+Txop::GetLinks() const
+{
+    return m_links;
+}
+
+void
+Txop::SwapLinks(std::map<uint8_t, uint8_t> links)
 {
-    return m_links.size();
+    NS_LOG_FUNCTION(this);
+
+    decltype(m_links) tmp;
+    tmp.swap(m_links); // move all links to temporary map
+    for (const auto& [from, to] : links)
+    {
+        auto nh = tmp.extract(from);
+        nh.key() = to;
+        m_links.insert(std::move(nh));
+    }
+    // move links remaining in tmp to m_links
+    m_links.merge(tmp);
 }
 
 void
@@ -192,12 +210,9 @@
 {
     NS_LOG_FUNCTION(this << mac);
     m_mac = mac;
-    m_links.resize(m_mac->GetNLinks());
-    uint8_t linkId = 0;
-    for (auto& link : m_links)
+    for (const auto linkId : m_mac->GetLinkIds())
     {
-        link = CreateLinkEntity();
-        link->id = linkId++;
+        m_links.emplace(linkId, CreateLinkEntity());
     }
 }
 
@@ -229,9 +244,10 @@
 Txop::SetMinCws(std::vector<uint32_t> minCws)
 {
     NS_ABORT_IF(minCws.size() != m_links.size());
-    for (std::size_t linkId = 0; linkId < minCws.size(); linkId++)
+    std::size_t i = 0;
+    for (const auto& [id, link] : m_links)
     {
-        SetMinCw(minCws[linkId], linkId);
+        SetMinCw(minCws[i++], id);
     }
 }
 
@@ -258,9 +274,10 @@
 Txop::SetMaxCws(std::vector<uint32_t> maxCws)
 {
     NS_ABORT_IF(maxCws.size() != m_links.size());
-    for (std::size_t linkId = 0; linkId < maxCws.size(); linkId++)
+    std::size_t i = 0;
+    for (const auto& [id, link] : m_links)
     {
-        SetMaxCw(maxCws[linkId], linkId);
+        SetMaxCw(maxCws[i++], id);
     }
 }
 
@@ -355,9 +372,10 @@
 Txop::SetAifsns(std::vector<uint8_t> aifsns)
 {
     NS_ABORT_IF(aifsns.size() != m_links.size());
-    for (std::size_t linkId = 0; linkId < aifsns.size(); linkId++)
+    std::size_t i = 0;
+    for (const auto& [id, link] : m_links)
     {
-        SetAifsn(aifsns[linkId], linkId);
+        SetAifsn(aifsns[i++], id);
     }
 }
 
@@ -381,9 +399,10 @@
                     "The size of the given vector (" << txopLimits.size()
                                                      << ") does not match the number of links ("
                                                      << m_links.size() << ")");
-    for (std::size_t linkId = 0; linkId < txopLimits.size(); linkId++)
+    std::size_t i = 0;
+    for (const auto& [id, link] : m_links)
     {
-        SetTxopLimit(txopLimits[linkId], linkId);
+        SetTxopLimit(txopLimits[i++], id);
     }
 }
 
@@ -406,9 +425,10 @@
 Txop::GetMinCws() const
 {
     std::vector<uint32_t> ret;
-    for (std::size_t linkId = 0; linkId < m_links.size(); linkId++)
+    ret.reserve(m_links.size());
+    for (const auto& [id, link] : m_links)
     {
-        ret.push_back(GetMinCw(linkId));
+        ret.push_back(link->cwMin);
     }
     return ret;
 }
@@ -429,9 +449,10 @@
 Txop::GetMaxCws() const
 {
     std::vector<uint32_t> ret;
-    for (std::size_t linkId = 0; linkId < m_links.size(); linkId++)
+    ret.reserve(m_links.size());
+    for (const auto& [id, link] : m_links)
     {
-        ret.push_back(GetMaxCw(linkId));
+        ret.push_back(link->cwMax);
     }
     return ret;
 }
@@ -452,9 +473,10 @@
 Txop::GetAifsns() const
 {
     std::vector<uint8_t> ret;
-    for (std::size_t linkId = 0; linkId < m_links.size(); linkId++)
+    ret.reserve(m_links.size());
+    for (const auto& [id, link] : m_links)
     {
-        ret.push_back(GetAifsn(linkId));
+        ret.push_back(link->aifsn);
     }
     return ret;
 }
@@ -475,9 +497,10 @@
 Txop::GetTxopLimits() const
 {
     std::vector<Time> ret;
-    for (std::size_t linkId = 0; linkId < m_links.size(); linkId++)
+    ret.reserve(m_links.size());
+    for (const auto& [id, link] : m_links)
     {
-        ret.push_back(GetTxopLimit(linkId));
+        ret.push_back(link->txopLimit);
     }
     return ret;
 }
@@ -548,10 +571,10 @@
 Txop::DoInitialize()
 {
     NS_LOG_FUNCTION(this);
-    for (std::size_t linkId = 0; linkId < m_links.size(); linkId++)
+    for (const auto& [id, link] : m_links)
     {
-        ResetCw(linkId);
-        GenerateBackoff(linkId);
+        ResetCw(id);
+        GenerateBackoff(id);
     }
 }
 
@@ -630,9 +653,9 @@
 Txop::NotifyOn()
 {
     NS_LOG_FUNCTION(this);
-    for (std::size_t linkId = 0; linkId < m_links.size(); linkId++)
+    for (const auto& [id, link] : m_links)
     {
-        StartAccessIfNeeded(linkId);
+        StartAccessIfNeeded(id);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/txop.h ns-3.40/src/wifi/model/txop.h
--- ns-3.39/src/wifi/model/txop.h	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/txop.h	2023-09-27 13:30:37.914839700 -0700
@@ -26,6 +26,7 @@
 #include "ns3/object.h"
 #include "ns3/traced-value.h"
 
+#include <map>
 #include <memory>
 #include <vector>
 
@@ -408,6 +409,16 @@
      */
     virtual bool HasFramesToTransmit(uint8_t linkId);
 
+    /**
+     * Swap the links based on the information included in the given map. This method
+     * is normally called by the WifiMac of a non-AP MLD upon completing ML setup to have
+     * its link IDs match AP MLD's link IDs.
+     *
+     * \param links a set of pairs (from, to) each mapping a current link ID to the
+     *              link ID it has to become (i.e., link 'from' becomes link 'to')
+     */
+    void SwapLinks(std::map<uint8_t, uint8_t> links);
+
   protected:
     ///< ChannelAccessManager associated class
     friend class ChannelAccessManager;
@@ -483,7 +494,6 @@
         /// Destructor (a virtual method is needed to make this struct polymorphic)
         virtual ~LinkEntity() = default;
 
-        uint8_t id{0};                             //!< Link ID (starting at 0)
         uint32_t backoffSlots{0};                  //!< the number of backoff slots
         Time backoffStart{0};                      /**< the backoffStart variable is used to keep
                                                         track of the time at which a backoff was
@@ -504,12 +514,11 @@
      * \return a reference to the link associated with the given ID
      */
     LinkEntity& GetLink(uint8_t linkId) const;
+
     /**
-     * Get the number of links.
-     *
-     * \return the number of links
+     * \return a const reference to the map of link entities
      */
-    uint8_t GetNLinks() const;
+    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
@@ -533,7 +542,8 @@
      */
     virtual std::unique_ptr<LinkEntity> CreateLinkEntity() const;
 
-    std::vector<std::unique_ptr<LinkEntity>> m_links; //!< vector of LinkEntity objects
+    std::map<uint8_t, std::unique_ptr<LinkEntity>>
+        m_links; //!< ID-indexed map of LinkEntity objects
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/vht/vht-phy.cc ns-3.40/src/wifi/model/vht/vht-phy.cc
--- ns-3.39/src/wifi/model/vht/vht-phy.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/vht/vht-phy.cc	2023-09-27 13:30:37.914839700 -0700
@@ -314,7 +314,7 @@
 VhtPhy::ProcessSig(Ptr<Event> event, PhyFieldRxStatus status, WifiPpduField field)
 {
     NS_LOG_FUNCTION(this << *event << status << field);
-    NS_ASSERT(event->GetTxVector().GetPreambleType() >= WIFI_PREAMBLE_VHT_SU);
+    NS_ASSERT(event->GetPpdu()->GetTxVector().GetPreambleType() >= WIFI_PREAMBLE_VHT_SU);
     // TODO see if something should be done here once MU-MIMO is supported
     return status; // nothing special for VHT
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/vht/vht-ppdu.cc ns-3.40/src/wifi/model/vht/vht-ppdu.cc
--- ns-3.39/src/wifi/model/vht/vht-ppdu.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/vht/vht-ppdu.cc	2023-09-27 13:30:37.914839700 -0700
@@ -111,7 +111,7 @@
 Time
 VhtPpdu::GetTxDuration() const
 {
-    const WifiTxVector& txVector = GetTxVector();
+    const auto& txVector = GetTxVector();
     const auto length = m_lSig.GetLength();
     const auto sgi = m_vhtSig.GetShortGuardInterval();
     const auto sgiDisambiguation = m_vhtSig.GetShortGuardIntervalDisambiguation();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-assoc-manager.cc ns-3.40/src/wifi/model/wifi-assoc-manager.cc
--- ns-3.39/src/wifi/model/wifi-assoc-manager.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-assoc-manager.cc	2023-09-27 13:30:37.914839700 -0700
@@ -22,6 +22,9 @@
 
 #include "sta-wifi-mac.h"
 
+#include "ns3/attribute-container.h"
+#include "ns3/eht-configuration.h"
+#include "ns3/enum.h"
 #include "ns3/log.h"
 
 #include <algorithm>
@@ -65,7 +68,17 @@
 TypeId
 WifiAssocManager::GetTypeId()
 {
-    static TypeId tid = TypeId("ns3::WifiAssocManager").SetParent<Object>().SetGroupName("Wifi");
+    static TypeId tid =
+        TypeId("ns3::WifiAssocManager")
+            .SetParent<Object>()
+            .SetGroupName("Wifi")
+            .AddAttribute(
+                "AllowedLinks",
+                "Only Beacon and Probe Response frames received on a link belonging to the given "
+                "set are processed. An empty set is equivalent to the set of all links.",
+                AttributeContainerValue<UintegerValue>(),
+                MakeAttributeContainerAccessor<UintegerValue>(&WifiAssocManager::m_allowedLinks),
+                MakeAttributeContainerChecker<UintegerValue>(MakeUintegerChecker<uint8_t>()));
     return tid;
 }
 
@@ -164,10 +177,12 @@
     NS_LOG_FUNCTION(this);
     m_scanParams = std::move(scanParams);
 
-    // remove stored AP information not matching the scanning parameters
+    // remove stored AP information not matching the scanning parameters or related to APs
+    // that are not reachable on an allowed link
     for (auto ap = m_apList.begin(); ap != m_apList.end();)
     {
-        if (!MatchScanParams(*ap))
+        if (!MatchScanParams(*ap) ||
+            (!m_allowedLinks.empty() && m_allowedLinks.count(ap->m_linkId) == 0))
         {
             // remove AP info from list
             m_apListIt.erase(ap->m_bssid);
@@ -187,7 +202,8 @@
 {
     NS_LOG_FUNCTION(this << apInfo);
 
-    if (!CanBeInserted(apInfo) || !MatchScanParams(apInfo))
+    if (!CanBeInserted(apInfo) || !MatchScanParams(apInfo) ||
+        (!m_allowedLinks.empty() && m_allowedLinks.count(apInfo.m_linkId) == 0))
     {
         return;
     }
@@ -234,10 +250,10 @@
     m_mac->ScanningTimeout(std::move(bestAp));
 }
 
-std::list<std::pair<uint8_t, uint8_t>>&
+std::list<StaWifiMac::ApInfo::SetupLinksInfo>&
 WifiAssocManager::GetSetupLinks(const StaWifiMac::ApInfo& apInfo)
 {
-    return const_cast<std::list<std::pair<uint8_t, uint8_t>>&>(apInfo.m_setupLinks);
+    return const_cast<std::list<StaWifiMac::ApInfo::SetupLinksInfo>&>(apInfo.m_setupLinks);
 }
 
 bool
@@ -285,6 +301,26 @@
         return false;
     }
 
+    if (const auto& mldCapabilities = mle->get().GetCommonInfoBasic().m_mldCapabilities)
+    {
+        auto ehtConfig = m_mac->GetEhtConfiguration();
+        NS_ASSERT(ehtConfig);
+        EnumValue negSupport;
+        ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
+
+        // A non-AP MLD that performs multi-link (re)setup on at least two links with an AP MLD
+        // that sets the TID-To-Link Mapping Negotiation Support subfield of the MLD Capabilities
+        // field of the Basic Multi-Link element to a nonzero value shall support TID-to-link
+        // 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)
+        {
+            NS_LOG_DEBUG("AP MLD supports TID-to-Link Mapping negotiation, while we don't");
+            return false;
+        }
+    }
+
     return true;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-assoc-manager.h ns-3.40/src/wifi/model/wifi-assoc-manager.h
--- ns-3.39/src/wifi/model/wifi-assoc-manager.h	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-assoc-manager.h	2023-09-27 13:30:37.914839700 -0700
@@ -178,7 +178,7 @@
      * \param apInfo the info about the given AP
      * \return a reference to the list of the links to setup with the given AP
      */
-    std::list<std::pair<uint8_t, uint8_t>>& GetSetupLinks(const StaWifiMac::ApInfo& apInfo);
+    std::list<StaWifiMac::ApInfo::SetupLinksInfo>& GetSetupLinks(const StaWifiMac::ApInfo& apInfo);
 
     /**
      * \return the scanning parameters.
@@ -233,7 +233,9 @@
      */
     bool CanSetupMultiLink(OptMleConstRef& mle, OptRnrConstRef& rnr);
 
-    Ptr<StaWifiMac> m_mac; ///< pointer to the STA wifi MAC
+    Ptr<StaWifiMac> m_mac;            ///< pointer to the STA wifi MAC
+    std::set<uint8_t> m_allowedLinks; /**< "Only Beacon and Probe Response frames received on a
+                                            link belonging to the this set are processed */
 
   private:
     /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-bandwidth-filter.cc ns-3.40/src/wifi/model/wifi-bandwidth-filter.cc
--- ns-3.39/src/wifi/model/wifi-bandwidth-filter.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-bandwidth-filter.cc	2023-09-27 13:30:37.914839700 -0700
@@ -61,12 +61,17 @@
         return false;
     }
 
-    // WifiSpectrumPhyInterface (passed in) can be used to fetch SpectrumWifiPhy
-
     auto interface = DynamicCast<const WifiSpectrumPhyInterface>(receiverPhy);
-    auto wifiPhy = interface->GetSpectrumWifiPhy();
+    if (!interface)
+    {
+        NS_LOG_DEBUG("Sending a Wi-Fi signal to a non Wi-Fi device; do not filter");
+        return false;
+    }
 
-    NS_ASSERT_MSG(wifiPhy, "WifiPhy should be valid if WifiSpectrumSignalParameters was found");
+    auto wifiPhy = interface->GetSpectrumWifiPhy();
+    NS_ASSERT_MSG(wifiPhy,
+                  "WifiPhy should be valid if WifiSpectrumSignalParameters was found and sending "
+                  "to a WifiSpectrumPhyInterface");
 
     BooleanValue trackSignalsInactiveInterfaces;
     wifiPhy->GetAttribute("TrackSignalsFromInactiveInterfaces", trackSignalsInactiveInterfaces);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-default-assoc-manager.cc ns-3.40/src/wifi/model/wifi-default-assoc-manager.cc
--- ns-3.39/src/wifi/model/wifi-default-assoc-manager.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-default-assoc-manager.cc	2023-09-27 13:30:37.914839700 -0700
@@ -133,15 +133,12 @@
     }
 
     auto& bestAp = *GetSortedList().begin();
-
-    // store AP MLD MAC address in the WifiRemoteStationManager associated with
-    // the link on which the Beacon/Probe Response was received
-    m_mac->GetWifiRemoteStationManager(bestAp.m_linkId)
-        ->SetMldAddress(bestAp.m_apAddr, mle->get().GetMldMacAddress());
     auto& setupLinks = GetSetupLinks(bestAp);
 
     setupLinks.clear();
-    setupLinks.emplace_back(bestAp.m_linkId, mle->get().GetLinkIdInfo());
+    setupLinks.emplace_back(StaWifiMac::ApInfo::SetupLinksInfo{bestAp.m_linkId,
+                                                               mle->get().GetLinkIdInfo(),
+                                                               bestAp.m_bssid});
 
     // sort local PHY objects so that radios with constrained PHY band comes first,
     // then radios with no constraint
@@ -203,14 +200,10 @@
             // if we get here, it means we can setup a link with this affiliated AP
             // set the BSSID for this link
             Mac48Address bssid = rnr->get().GetBssid(apIt->m_nbrApInfoId, apIt->m_tbttInfoFieldId);
-            // store AP MLD MAC address in the WifiRemoteStationManager associated with
-            // the link requested to setup
-            m_mac->GetWifiRemoteStationManager(linkId)->SetMldAddress(
-                bssid,
-                mle->get().GetMldMacAddress());
-            setupLinks.emplace_back(
+            setupLinks.emplace_back(StaWifiMac::ApInfo::SetupLinksInfo{
                 linkId,
-                rnr->get().GetLinkId(apIt->m_nbrApInfoId, apIt->m_tbttInfoFieldId));
+                rnr->get().GetLinkId(apIt->m_nbrApInfoId, apIt->m_tbttInfoFieldId),
+                bssid});
 
             if (needChannelSwitch)
             {
@@ -264,12 +257,6 @@
         // we were waiting for this notification
         m_channelSwitchInfo[linkId].timer.Cancel();
 
-        // the remote station manager has been reset after switching, hence store
-        // information about AP link address and AP MLD address
-        m_mac->GetWifiRemoteStationManager(linkId)->SetMldAddress(
-            m_channelSwitchInfo[linkId].apLinkAddress,
-            m_channelSwitchInfo[linkId].apMldAddress);
-
         if (std::none_of(m_channelSwitchInfo.begin(), m_channelSwitchInfo.end(), [](auto&& info) {
                 return info.timer.IsRunning();
             }))
@@ -289,7 +276,7 @@
     auto& bestAp = *GetSortedList().begin();
     auto& setupLinks = GetSetupLinks(bestAp);
     auto it = std::find_if(setupLinks.begin(), setupLinks.end(), [&linkId](auto&& linkIds) {
-        return linkIds.first == linkId;
+        return linkIds.localLinkId == linkId;
     });
     NS_ASSERT(it != setupLinks.end());
     setupLinks.erase(it);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-default-protection-manager.cc ns-3.40/src/wifi/model/wifi-default-protection-manager.cc
--- ns-3.39/src/wifi/model/wifi-default-protection-manager.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-default-protection-manager.cc	2023-09-27 13:30:37.914839700 -0700
@@ -21,10 +21,12 @@
 
 #include "ap-wifi-mac.h"
 #include "frame-exchange-manager.h"
+#include "sta-wifi-mac.h"
 #include "wifi-mpdu.h"
 #include "wifi-tx-parameters.h"
 
 #include "ns3/boolean.h"
+#include "ns3/emlsr-manager.h"
 #include "ns3/erp-ofdm-phy.h"
 #include "ns3/log.h"
 
@@ -188,8 +190,20 @@
         return std::make_unique<WifiNoProtection>();
     }
 
+    // when an EMLSR client starts an UL TXOP on a link on which the main PHY is not operating,
+    // the aux PHY sends an RTS frame
+    bool emlsrNeedRts = false;
+
+    if (auto staMac = DynamicCast<StaWifiMac>(m_mac))
+    {
+        auto emlsrManager = staMac->GetEmlsrManager();
+
+        emlsrNeedRts = emlsrManager && staMac->IsEmlsrLink(m_linkId) &&
+                       m_mac->GetLinkForPhy(emlsrManager->GetMainPhyId()) != m_linkId;
+    }
+
     // check if RTS/CTS is needed
-    if (GetWifiRemoteStationManager()->NeedRts(hdr, size))
+    if (emlsrNeedRts || GetWifiRemoteStationManager()->NeedRts(hdr, size))
     {
         auto protection = std::make_unique<WifiRtsCtsProtection>();
         protection->rtsTxVector = GetWifiRemoteStationManager()->GetRtsTxVector(hdr.GetAddr1());
@@ -345,7 +359,6 @@
 
     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);
-    std::remove_reference_t<decltype(staList)>::const_iterator staIt;
 
     bool allProtected = true;
     bool isUnprotectedEmlsrDst = false;
@@ -355,7 +368,7 @@
         // Add a User Info field to the MU-RTS for this solicited station
         // 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)
-        staIt = staList.find(userInfo.GetAid12());
+        auto staIt = staList.find(userInfo.GetAid12());
         NS_ASSERT(staIt != staList.cend());
         AddUserInfoToMuRts(protection->muRts, txWidth, staIt->second);
         bool isProtected =
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mac.cc ns-3.40/src/wifi/model/wifi-mac.cc
--- ns-3.39/src/wifi/model/wifi-mac.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mac.cc	2023-09-27 13:30:37.918840000 -0700
@@ -38,6 +38,8 @@
 #include "ns3/pointer.h"
 #include "ns3/vht-configuration.h"
 
+#include <algorithm>
+
 namespace ns3
 {
 
@@ -363,7 +365,7 @@
         it->second->Initialize();
     }
 
-    for (auto& link : m_links)
+    for (const auto& [id, link] : m_links)
     {
         if (auto cam = link->channelAccessManager)
         {
@@ -481,7 +483,7 @@
 void
 WifiMac::SetPromisc()
 {
-    for (auto& link : m_links)
+    for (auto& [id, link] : m_links)
     {
         link->feManager->SetPromisc();
     }
@@ -646,7 +648,7 @@
 WifiMac::ConfigureContentionWindow(uint32_t cwMin, uint32_t cwMax)
 {
     std::list<bool> isDsssOnly;
-    for (const auto& link : m_links)
+    for (const auto& [id, link] : m_links)
     {
         isDsssOnly.push_back(link->dsssSupported && !link->erpSupported);
     }
@@ -751,11 +753,11 @@
     NS_ABORT_IF(standard >= WIFI_STANDARD_80211n && !m_qosSupported);
     NS_ABORT_MSG_IF(m_links.empty(), "No PHY configured yet");
 
-    for (auto& link : m_links)
+    for (auto& [id, link] : m_links)
     {
         NS_ABORT_MSG_IF(
             !link->phy || !link->phy->GetOperatingChannel().IsSet(),
-            "[LinkID " << link->id
+            "[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
@@ -772,8 +774,8 @@
         }
         link->feManager->SetWifiPhy(link->phy);
         link->feManager->SetWifiMac(this);
-        link->feManager->SetLinkId(link->id);
-        link->channelAccessManager->SetLinkId(link->id);
+        link->feManager->SetLinkId(id);
+        link->channelAccessManager->SetLinkId(id);
         link->channelAccessManager->SetupFrameExchangeManager(link->feManager);
 
         if (m_txop)
@@ -787,7 +789,7 @@
             link->channelAccessManager->Add(it->second);
         }
 
-        ConfigurePhyDependentParameters(link->id);
+        ConfigurePhyDependentParameters(id);
     }
 }
 
@@ -896,13 +898,9 @@
     for (std::size_t i = 0; i < stationManagers.size(); i++)
     {
         // the link may already exist in case PHY objects were configured first
-        if (i == m_links.size())
-        {
-            m_links.push_back(CreateLinkEntity());
-            m_links.back()->id = i;
-        }
-        NS_ABORT_IF(i != m_links[i]->id);
-        m_links[i]->stationManager = stationManagers[i];
+        auto [it, inserted] = m_links.emplace(i, CreateLinkEntity());
+        m_linkIds.insert(i);
+        it->second->stationManager = stationManagers[i];
     }
 }
 
@@ -918,12 +916,19 @@
     return std::make_unique<LinkEntity>();
 }
 
+const std::map<uint8_t, std::unique_ptr<WifiMac::LinkEntity>>&
+WifiMac::GetLinks() const
+{
+    return m_links;
+}
+
 WifiMac::LinkEntity&
 WifiMac::GetLink(uint8_t linkId) const
 {
-    NS_ASSERT(linkId < m_links.size());
-    NS_ASSERT(m_links.at(linkId)); // check that the pointer owns an object
-    return *m_links.at(linkId);
+    auto it = m_links.find(linkId);
+    NS_ASSERT(it != m_links.cend());
+    NS_ASSERT(it->second); // check that the pointer owns an object
+    return *it->second;
 }
 
 uint8_t
@@ -932,19 +937,213 @@
     return m_links.size();
 }
 
+const std::set<uint8_t>&
+WifiMac::GetLinkIds() const
+{
+    return m_linkIds;
+}
+
+void
+WifiMac::UpdateLinkId(uint8_t id)
+{
+    NS_LOG_FUNCTION(this << id);
+
+    auto& link = GetLink(id);
+    if (link.feManager)
+    {
+        link.feManager->SetLinkId(id);
+    }
+    if (link.channelAccessManager)
+    {
+        link.channelAccessManager->SetLinkId(id);
+    }
+}
+
 std::optional<uint8_t>
 WifiMac::GetLinkIdByAddress(const Mac48Address& address) const
 {
-    for (std::size_t ret = 0; ret < m_links.size(); ++ret)
+    for (const auto& [id, link] : m_links)
     {
-        if (m_links[ret]->feManager->GetAddress() == address)
+        if (link->feManager->GetAddress() == address)
         {
-            return ret;
+            return id;
         }
     }
     return std::nullopt;
 }
 
+std::optional<uint8_t>
+WifiMac::GetLinkForPhy(Ptr<const WifiPhy> phy) const
+{
+    for (const auto& [id, link] : m_links)
+    {
+        if (link->phy == phy)
+        {
+            return id;
+        }
+    }
+    return std::nullopt;
+}
+
+std::optional<uint8_t>
+WifiMac::GetLinkForPhy(std::size_t phyId) const
+{
+    NS_ABORT_UNLESS(phyId < m_device->GetNPhys());
+    auto phy = m_device->GetPhy(phyId);
+    return GetLinkForPhy(phy);
+}
+
+void
+WifiMac::SwapLinks(std::map<uint8_t, uint8_t> links)
+{
+    NS_LOG_FUNCTION(this);
+
+    std::map<uint8_t, uint8_t> actualPairs;
+
+    while (!links.empty())
+    {
+        auto from = links.cbegin()->first;
+        auto to = links.cbegin()->second;
+
+        if (from == to)
+        {
+            // nothing to do
+            links.erase(links.cbegin());
+            continue;
+        }
+
+        std::unique_ptr<LinkEntity> linkToMove;
+        NS_ASSERT(m_links.find(from) != m_links.cend());
+        linkToMove.swap(m_links.at(from)); // from is now out of m_links
+        auto empty = from;                 // track empty cell in m_links
+
+        do
+        {
+            auto [it, inserted] =
+                m_links.emplace(to, nullptr); // insert an element with key to if not present
+            m_links[to].swap(linkToMove);     // to is the link to move now
+            actualPairs.emplace(from, to);
+            UpdateLinkId(to);
+            links.erase(from);
+            if (!linkToMove)
+            {
+                if (inserted)
+                {
+                    m_links.erase(empty);
+                }
+                break;
+            }
+
+            auto nextTo = links.find(to);
+            if (nextTo == links.cend())
+            {
+                // no new position specified for 'to', use the current empty cell
+                m_links[empty].swap(linkToMove);
+                actualPairs.emplace(to, empty);
+                break;
+            }
+
+            from = to;
+            to = nextTo->second;
+        } while (true);
+    }
+
+    m_linkIds.clear();
+    for (const auto& [id, link] : m_links)
+    {
+        m_linkIds.insert(id);
+    }
+
+    if (m_txop)
+    {
+        m_txop->SwapLinks(actualPairs);
+    }
+    for (auto& [ac, edca] : m_edca)
+    {
+        edca->SwapLinks(actualPairs);
+    }
+}
+
+void
+WifiMac::UpdateTidToLinkMapping(const Mac48Address& mldAddr,
+                                WifiDirection dir,
+                                const WifiTidLinkMapping& mapping)
+{
+    NS_LOG_FUNCTION(this << mldAddr);
+
+    NS_ABORT_MSG_IF(dir == WifiDirection::BOTH_DIRECTIONS,
+                    "DL and UL directions for TID-to-Link mapping must be set separately");
+
+    auto& mappings = (dir == WifiDirection::DOWNLINK ? m_dlTidLinkMappings : m_ulTidLinkMappings);
+
+    auto [it, inserted] = mappings.emplace(mldAddr, mapping);
+
+    if (inserted)
+    {
+        // we are done
+        return;
+    }
+
+    // a previous mapping is stored for this MLD
+    if (mapping.empty())
+    {
+        // the default mapping has been now negotiated
+        it->second.clear();
+        return;
+    }
+
+    for (const auto& [tid, linkSet] : mapping)
+    {
+        it->second[tid] = linkSet;
+    }
+}
+
+std::optional<std::reference_wrapper<const WifiTidLinkMapping>>
+WifiMac::GetTidToLinkMapping(Mac48Address mldAddr, WifiDirection dir) const
+{
+    NS_ABORT_MSG_IF(dir == WifiDirection::BOTH_DIRECTIONS,
+                    "Cannot request TID-to-Link mapping for both directions");
+
+    const auto& mappings =
+        (dir == WifiDirection::DOWNLINK ? m_dlTidLinkMappings : m_ulTidLinkMappings);
+
+    if (const auto it = mappings.find(mldAddr); it != mappings.cend())
+    {
+        return it->second;
+    }
+    return std::nullopt;
+}
+
+bool
+WifiMac::TidMappedOnLink(Mac48Address mldAddr, WifiDirection dir, uint8_t tid, uint8_t linkId) const
+{
+    NS_ABORT_MSG_IF(dir == WifiDirection::BOTH_DIRECTIONS,
+                    "Cannot request TID-to-Link mapping for both directions");
+
+    const auto& mappings =
+        (dir == WifiDirection::DOWNLINK ? m_dlTidLinkMappings : m_ulTidLinkMappings);
+
+    const auto it = mappings.find(mldAddr);
+
+    if (it == mappings.cend())
+    {
+        // TID-to-link mapping was not negotiated, TIDs are mapped to all setup links
+        return GetWifiRemoteStationManager(linkId)->GetMldAddress(mldAddr).has_value();
+    }
+
+    auto linkSetIt = it->second.find(tid);
+
+    if (linkSetIt == it->second.cend())
+    {
+        // If there is no successfully negotiated TID-to-link mapping for a TID, then the TID
+        // is mapped to all setup links for DL and UL (Sec. 35.3.7.1.3 of 802.11be D3.1)
+        return GetWifiRemoteStationManager(linkId)->GetMldAddress(mldAddr).has_value();
+    }
+
+    return std::find(linkSetIt->second.cbegin(), linkSetIt->second.cend(), linkId) !=
+           linkSetIt->second.cend();
+}
+
 void
 WifiMac::SetWifiPhys(const std::vector<Ptr<WifiPhy>>& phys)
 {
@@ -964,20 +1163,15 @@
         // 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
-        if (i == m_links.size())
-        {
-            m_links.push_back(CreateLinkEntity());
-            m_links.back()->id = i;
-        }
-        NS_ABORT_IF(i != m_links[i]->id);
-        m_links[i]->phy = phys[i];
+        auto [it, inserted] = m_links.emplace(i, CreateLinkEntity());
+        m_linkIds.insert(i);
+        it->second->phy = phys[i];
     }
 }
 
 Ptr<WifiPhy>
 WifiMac::GetWifiPhy(uint8_t linkId) const
 {
-    NS_LOG_FUNCTION(this << +linkId);
     return GetLink(linkId).phy;
 }
 
@@ -985,7 +1179,7 @@
 WifiMac::ResetWifiPhys()
 {
     NS_LOG_FUNCTION(this);
-    for (auto& link : m_links)
+    for (auto& [id, link] : m_links)
     {
         if (link->feManager)
         {
@@ -1110,6 +1304,88 @@
 }
 
 void
+WifiMac::ApplyTidLinkMapping(const Mac48Address& mldAddr, WifiDirection dir)
+{
+    NS_LOG_FUNCTION(this << mldAddr);
+
+    NS_ABORT_MSG_IF(
+        dir == WifiDirection::BOTH_DIRECTIONS,
+        "This method can be used to enforce TID-to-Link mapping for one direction at a time");
+
+    const auto& mappings =
+        (dir == WifiDirection::DOWNLINK ? m_dlTidLinkMappings : m_ulTidLinkMappings);
+
+    auto it = mappings.find(mldAddr);
+
+    if (it == mappings.cend())
+    {
+        // no mapping has been ever negotiated with the given MLD, the default mapping is used
+        return;
+    }
+
+    std::set<uint8_t> setupLinks;
+
+    // find the IDs of the links setup with the given MLD
+    for (const auto& [id, link] : m_links)
+    {
+        if (link->stationManager->GetMldAddress(mldAddr))
+        {
+            setupLinks.insert(id);
+        }
+    }
+
+    auto linkMapping = it->second;
+
+    if (linkMapping.empty())
+    {
+        // default link mapping, each TID mapped on all setup links
+        for (uint8_t tid = 0; tid < 8; tid++)
+        {
+            linkMapping.emplace(tid, setupLinks);
+        }
+    }
+
+    for (const auto& [tid, linkSet] : linkMapping)
+    {
+        decltype(setupLinks) mappedLinks; // empty
+        auto notMappedLinks = setupLinks; // all setup links
+
+        for (const auto id : linkSet)
+        {
+            if (setupLinks.find(id) != setupLinks.cend())
+            {
+                // link is mapped
+                mappedLinks.insert(id);
+                notMappedLinks.erase(id);
+            }
+        }
+
+        // unblock mapped links
+        NS_ABORT_MSG_IF(mappedLinks.empty(), "Every TID must be mapped to at least a link");
+
+        m_scheduler->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
+                                   QosUtilsMapTidToAc(tid),
+                                   {WIFI_QOSDATA_QUEUE},
+                                   mldAddr,
+                                   GetAddress(),
+                                   {tid},
+                                   mappedLinks);
+
+        // block unmapped links
+        if (!notMappedLinks.empty())
+        {
+            m_scheduler->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
+                                     QosUtilsMapTidToAc(tid),
+                                     {WIFI_QOSDATA_QUEUE},
+                                     mldAddr,
+                                     GetAddress(),
+                                     {tid},
+                                     notMappedLinks);
+        }
+    }
+}
+
+void
 WifiMac::BlockUnicastTxOnLinks(WifiQueueBlockedReason reason,
                                const Mac48Address& address,
                                const std::set<uint8_t>& linkIds)
@@ -1357,9 +1633,9 @@
 std::optional<Mac48Address>
 WifiMac::GetMldAddress(const Mac48Address& remoteAddr) const
 {
-    for (std::size_t linkId = 0; linkId < m_links.size(); linkId++)
+    for (const auto& [id, link] : m_links)
     {
-        if (auto mldAddress = m_links[linkId]->stationManager->GetMldAddress(remoteAddr))
+        if (auto mldAddress = link->stationManager->GetMldAddress(remoteAddr))
         {
             return *mldAddress;
         }
@@ -1370,7 +1646,7 @@
 Mac48Address
 WifiMac::GetLocalAddress(const Mac48Address& remoteAddr) const
 {
-    for (const auto& link : m_links)
+    for (const auto& [id, link] : m_links)
     {
         if (auto mldAddress = link->stationManager->GetMldAddress(remoteAddr))
         {
@@ -1511,7 +1787,7 @@
 bool
 WifiMac::GetHtSupported(const Mac48Address& address) const
 {
-    for (const auto& link : m_links)
+    for (const auto& [id, link] : m_links)
     {
         if (link->stationManager->GetHtSupported(address))
         {
@@ -1524,7 +1800,7 @@
 bool
 WifiMac::GetVhtSupported(const Mac48Address& address) const
 {
-    for (const auto& link : m_links)
+    for (const auto& [id, link] : m_links)
     {
         if (link->stationManager->GetVhtSupported(address))
         {
@@ -1537,7 +1813,7 @@
 bool
 WifiMac::GetHeSupported(const Mac48Address& address) const
 {
-    for (const auto& link : m_links)
+    for (const auto& [id, link] : m_links)
     {
         if (link->stationManager->GetHeSupported(address))
         {
@@ -1550,7 +1826,7 @@
 bool
 WifiMac::GetEhtSupported(const Mac48Address& address) const
 {
-    for (const auto& link : m_links)
+    for (const auto& [id, link] : m_links)
     {
         if (link->stationManager->GetEhtSupported(address))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mac.h ns-3.40/src/wifi/model/wifi-mac.h
--- ns-3.39/src/wifi/model/wifi-mac.h	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mac.h	2023-09-27 13:30:37.918840000 -0700
@@ -26,7 +26,9 @@
 #include "wifi-remote-station-manager.h"
 #include "wifi-standards.h"
 
+#include <functional>
 #include <list>
+#include <map>
 #include <memory>
 #include <optional>
 #include <set>
@@ -141,6 +143,12 @@
      * \return the number of links used by this MAC
      */
     uint8_t GetNLinks() const;
+
+    /**
+     * \return the set of link IDs in use by this device
+     */
+    const std::set<uint8_t>& GetLinkIds() const;
+
     /**
      * Get the ID of the link having the given MAC address, if any.
      *
@@ -150,6 +158,22 @@
     virtual std::optional<uint8_t> GetLinkIdByAddress(const Mac48Address& address) const;
 
     /**
+     * Get the ID of the link (if any) on which the given PHY is operating.
+     *
+     * \param phy the given PHY
+     * \return the ID of the link (if any) on which the given PHY is operating
+     */
+    std::optional<uint8_t> GetLinkForPhy(Ptr<const WifiPhy> phy) const;
+
+    /**
+     * Get the ID of the link (if any) on which the given PHY is operating.
+     *
+     * \param phyId the index of the given PHY in the vector of PHYs held by WifiNetDevice
+     * \return the ID of the link (if any) on which the given PHY is operating
+     */
+    std::optional<uint8_t> GetLinkForPhy(std::size_t phyId) 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.
@@ -654,6 +678,34 @@
      */
     BlockAckReqType GetBarTypeAsRecipient(Mac48Address originator, uint8_t tid) const;
 
+    /**
+     * Get the TID-to-Link Mapping negotiated with the given MLD (if any) for the given direction.
+     * An empty mapping indicates the default mapping.
+     *
+     * \param mldAddr the MLD address of the given MLD
+     * \param dir the given direction (DL or UL)
+     * \return the negotiated TID-to-Link Mapping
+     */
+    std::optional<std::reference_wrapper<const WifiTidLinkMapping>> GetTidToLinkMapping(
+        Mac48Address mldAddr,
+        WifiDirection dir) const;
+
+    /**
+     * Check whether the given TID is mapped on the given link in the given direction for the
+     * given MLD.
+     *
+     * \param mldAddr the MLD address of the given MLD
+     * \param dir the given direction (DL or UL)
+     * \param tid the given TID
+     * \param linkId the ID of the given link
+     * \return whether the given TID is mapped on the given link in the given direction for the
+     *         given MLD
+     */
+    bool TidMappedOnLink(Mac48Address mldAddr,
+                         WifiDirection dir,
+                         uint8_t tid,
+                         uint8_t linkId) const;
+
   protected:
     void DoInitialize() override;
     void DoDispose() override;
@@ -752,6 +804,25 @@
     virtual void DeaggregateAmsduAndForward(Ptr<const WifiMpdu> mpdu);
 
     /**
+     * Apply the TID-to-Link Mapping negotiated with the given MLD for the given direction
+     * by properly configuring the queue scheduler.
+     *
+     * \param mldAddr the MLD MAC address of the given MLD
+     * \param dir the given direction (DL or UL)
+     */
+    void ApplyTidLinkMapping(const Mac48Address& mldAddr, WifiDirection dir);
+
+    /**
+     * Swap the links based on the information included in the given map. This method
+     * is normally called by a non-AP MLD upon completing ML setup to have its link IDs
+     * match AP MLD's link IDs.
+     *
+     * \param links a set of pairs (from, to) each mapping a current link ID to the
+     *              link ID it has to become (i.e., link 'from' becomes link 'to')
+     */
+    void SwapLinks(std::map<uint8_t, uint8_t> links);
+
+    /**
      * Structure holding information specific to a single link. Here, the meaning of
      * "link" is that of the 11be amendment which introduced multi-link devices. For
      * previous amendments, only one link can be created. Therefore, "link" has not
@@ -763,7 +834,6 @@
         /// Destructor (a virtual method is needed to make this struct polymorphic)
         virtual ~LinkEntity();
 
-        uint8_t id;                                     //!< Link ID (starting at 0)
         Ptr<WifiPhy> phy;                               //!< Wifi PHY object
         Ptr<ChannelAccessManager> channelAccessManager; //!< channel access manager object
         Ptr<FrameExchangeManager> feManager;            //!< Frame Exchange Manager object
@@ -774,6 +844,11 @@
     };
 
     /**
+     * \return a const reference to the map of link entities
+     */
+    const std::map<uint8_t, std::unique_ptr<LinkEntity>>& GetLinks() const;
+
+    /**
      * Get a reference to the link associated with the given ID.
      *
      * \param linkId the given link ID
@@ -781,6 +856,18 @@
      */
     LinkEntity& GetLink(uint8_t linkId) const;
 
+    /**
+     * Update the TID-to-Link Mappings for the given MLD in the given direction based on the
+     * given negotiated mappings. An empty mapping indicates the default mapping.
+     *
+     * \param mldAddr the MLD address of the given MLD
+     * \param dir the given direction (DL or UL)
+     * \param mapping the negotiated TID-to-Link Mapping
+     */
+    void UpdateTidToLinkMapping(const Mac48Address& mldAddr,
+                                WifiDirection dir,
+                                const WifiTidLinkMapping& mapping);
+
     Ptr<MacRxMiddle> m_rxMiddle; //!< RX middle (defragmentation etc.)
     Ptr<MacTxMiddle> m_txMiddle; //!< TX middle (aggregation etc.)
     Ptr<Txop> m_txop;            //!< TXOP used for transmission of frames to non-QoS peers.
@@ -837,6 +924,15 @@
     virtual std::unique_ptr<LinkEntity> CreateLinkEntity() const;
 
     /**
+     * This method is intended to be called when a link changes ID in order to update the
+     * link ID stored by the Frame Exchange Manager and the Channel Access Manager operating
+     * on that link.
+     *
+     * \param id the (new) ID of the link that has changed ID
+     */
+    void UpdateLinkId(uint8_t id);
+
+    /**
      * This method is called if this device is an MLD to determine the MAC address of
      * the affiliated STA used to communicate with the single link device having the
      * given MAC address. This method is overridden because its implementation depends
@@ -932,8 +1028,9 @@
 
     TypeOfStation m_typeOfStation; //!< the type of station
 
-    Ptr<WifiNetDevice> m_device;                      //!< Pointer to the device
-    std::vector<std::unique_ptr<LinkEntity>> m_links; //!< vector of Link objects
+    Ptr<WifiNetDevice> m_device;                            //!< Pointer to the device
+    std::map<uint8_t, std::unique_ptr<LinkEntity>> m_links; //!< ID-indexed map of Link objects
+    std::set<uint8_t> m_linkIds;                            //!< IDs of the links in use
 
     Mac48Address m_address; //!< MAC address of this station
     Ssid m_ssid;            //!< Service Set ID (SSID)
@@ -941,7 +1038,7 @@
     /** This type defines a mapping between an Access Category index,
     and a pointer to the corresponding channel access function.
     Access Categories are sorted in decreasing order of priority. */
-    typedef std::map<AcIndex, Ptr<QosTxop>, std::greater<AcIndex>> EdcaQueues;
+    typedef std::map<AcIndex, Ptr<QosTxop>, std::greater<>> EdcaQueues;
 
     /** This is a map from Access Category index to the corresponding
     channel access function */
@@ -957,6 +1054,11 @@
     uint32_t m_beMaxAmpduSize; ///< maximum A-MPDU size for AC_BE (in bytes)
     uint32_t m_bkMaxAmpduSize; ///< maximum A-MPDU size for AC_BK (in bytes)
 
+    /// @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)
+    std::unordered_map<Mac48Address, WifiTidLinkMapping, WifiAddressHash> m_ulTidLinkMappings;
+
     ForwardUpCallback m_forwardUp; //!< Callback to forward packet up the stack
 
     /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mac-header.cc ns-3.40/src/wifi/model/wifi-mac-header.cc
--- ns-3.39/src/wifi/model/wifi-mac-header.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mac-header.cc	2023-09-27 13:30:37.914839700 -0700
@@ -308,7 +308,7 @@
 void
 WifiMacHeader::SetDuration(Time duration)
 {
-    int64_t duration_us =
+    auto duration_us =
         static_cast<int64_t>(ceil(static_cast<double>(duration.GetNanoSeconds()) / 1000));
     NS_ASSERT(duration_us >= 0 && duration_us <= 0x7fff);
     m_duration = static_cast<uint16_t>(duration_us);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mac-header.h ns-3.40/src/wifi/model/wifi-mac-header.h
--- ns-3.39/src/wifi/model/wifi-mac-header.h	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mac-header.h	2023-09-27 13:30:37.914839700 -0700
@@ -188,7 +188,7 @@
      * \param resetToDsFromDs whether the ToDs and FromDs flags
      *        should be reset.
      */
-    void SetType(WifiMacType type, bool resetToDsFromDs = true);
+    virtual void SetType(WifiMacType type, bool resetToDsFromDs = true);
     /**
      * Set the Duration/ID field with the given raw uint16_t value.
      *
@@ -330,7 +330,7 @@
      *
      * \return the type (WifiMacType)
      */
-    WifiMacType GetType() const;
+    virtual WifiMacType GetType() const;
     /**
      * \return true if From DS bit is set, false otherwise
      */
@@ -621,13 +621,13 @@
      *
      * \return the size of the WifiMacHeader in octets
      */
-    uint32_t GetSize() const;
+    virtual uint32_t GetSize() const;
     /**
      * Return a string corresponds to the header type.
      *
      * \returns a string corresponds to the header type.
      */
-    const char* GetTypeString() const;
+    virtual const char* GetTypeString() const;
 
     /**
      * TracedCallback signature for WifiMacHeader
@@ -636,25 +636,25 @@
      */
     typedef void (*TracedCallback)(const WifiMacHeader& header);
 
-  private:
+  protected:
     /**
      * Return the raw Frame Control field.
      *
      * \return the raw Frame Control field
      */
-    uint16_t GetFrameControl() const;
+    virtual uint16_t GetFrameControl() const;
     /**
      * Return the raw QoS Control field.
      *
      * \return the raw QoS Control field
      */
-    uint16_t GetQosControl() const;
+    virtual uint16_t GetQosControl() const;
     /**
      * Set the Frame Control field with the given raw value.
      *
      * \param control the raw Frame Control field value
      */
-    void SetFrameControl(uint16_t control);
+    virtual void SetFrameControl(uint16_t control);
     /**
      * Set the Sequence Control field with the given raw value.
      *
@@ -666,7 +666,7 @@
      *
      * \param qos the raw QoS Control field value
      */
-    void SetQosControl(uint16_t qos);
+    virtual void SetQosControl(uint16_t qos);
     /**
      * Print the Frame Control field to the output stream.
      *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mac-queue.cc ns-3.40/src/wifi/model/wifi-mac-queue.cc
--- ns-3.39/src/wifi/model/wifi-mac-queue.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mac-queue.cc	2023-09-27 13:30:37.914839700 -0700
@@ -191,7 +191,17 @@
     {
         NS_LOG_DEBUG("Removing packet that stayed in the queue for too long (queuing time="
                      << now - it->expiryTime + m_maxDelay << ")");
-        m_traceExpired(DoRemove(it));
+        // Trace the expired MPDU first and then remove it from the queue (if still in the queue).
+        // Indeed, the Expired traced source is connected to BlockAckManager::NotifyDiscardedMpdu,
+        // which checks if the expired MPDU is in-flight or is a retransmission to determine
+        // whether a BlockAckReq frame must be sent to advance the recipient window. If the
+        // expired MPDU is removed from the queue before tracing the expiration, it is no longer
+        // in-flight and NotifyDiscardedMpdu wrongfully assumes that a BlockAckReq is not needed.
+        m_traceExpired(item);
+        if (item->IsQueued())
+        {
+            DoRemove(it);
+        }
         return true;
     }
     return false;
@@ -292,13 +302,11 @@
 Ptr<const WifiMpdu>
 WifiMacQueue::Peek() const
 {
-    // Need to specify the link ID
-    NS_ABORT_MSG("Not implemented by WifiMacQueue");
-    return nullptr;
+    return Peek(std::nullopt);
 }
 
 Ptr<WifiMpdu>
-WifiMacQueue::Peek(uint8_t linkId) const
+WifiMacQueue::Peek(std::optional<uint8_t> linkId) const
 {
     NS_LOG_FUNCTION(this);
 
@@ -334,7 +342,7 @@
         ExtractExpiredMpdus(queueId);
     }
 
-    ConstIterator it = (item ? std::next(GetIt(item)) : GetContainer().GetQueue(queueId).cbegin());
+    auto it = (item ? std::next(GetIt(item)) : GetContainer().GetQueue(queueId).cbegin());
 
     if (it == GetContainer().GetQueue(queueId).cend())
     {
@@ -385,7 +393,7 @@
 Ptr<WifiMpdu>
 WifiMacQueue::Remove()
 {
-    return Remove(Peek(0));
+    return Remove(Peek());
 }
 
 Ptr<WifiMpdu>
@@ -401,6 +409,17 @@
 }
 
 void
+WifiMacQueue::Flush()
+{
+    NS_LOG_FUNCTION(this);
+
+    // there may be some expired MPDUs in the container queue storing MPDUs with expired lifetime,
+    // which will not be flushed by the Flush() method of the base class.
+    WipeAllExpiredMpdus();
+    Queue<WifiMpdu, WifiMacQueueContainer>::Flush();
+}
+
+void
 WifiMacQueue::Replace(Ptr<const WifiMpdu> currentItem, Ptr<WifiMpdu> newItem)
 {
     NS_LOG_FUNCTION(this << *currentItem << *newItem);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mac-queue-container.cc ns-3.40/src/wifi/model/wifi-mac-queue-container.cc
--- ns-3.39/src/wifi/model/wifi-mac-queue-container.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mac-queue-container.cc	2023-09-27 13:30:37.914839700 -0700
@@ -123,8 +123,8 @@
 WifiMacQueueContainer::DoExtractExpiredMpdus(ContainerQueue& queue) const
 {
     std::optional<std::pair<WifiMacQueueContainer::iterator, WifiMacQueueContainer::iterator>> ret;
-    iterator firstExpiredIt = queue.begin();
-    iterator lastExpiredIt = firstExpiredIt;
+    auto firstExpiredIt = queue.begin();
+    auto lastExpiredIt = firstExpiredIt;
     Time now = Simulator::Now();
 
     do
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mac-queue.h ns-3.40/src/wifi/model/wifi-mac-queue.h
--- ns-3.39/src/wifi/model/wifi-mac-queue.h	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mac-queue.h	2023-09-27 13:30:37.914839700 -0700
@@ -30,6 +30,7 @@
 #include "ns3/queue.h"
 
 #include <functional>
+#include <optional>
 #include <unordered_map>
 
 namespace ns3
@@ -141,12 +142,12 @@
     Ptr<const WifiMpdu> Peek() const override;
     /**
      * Peek the packet in the front of the queue for transmission on the given
-     * link. The packet is not removed.
+     * link (if any). The packet is not removed.
      *
      * \param linkId the ID of the link onto which we can transmit a packet
      * \return the packet
      */
-    Ptr<WifiMpdu> Peek(uint8_t linkId) const;
+    Ptr<WifiMpdu> Peek(std::optional<uint8_t> linkId) const;
     /**
      * Search and return, if present in the queue, the first packet having the
      * receiver address equal to <i>dest</i>, and TID equal to <i>tid</i>.
@@ -212,6 +213,11 @@
     Ptr<WifiMpdu> Remove(Ptr<const WifiMpdu> item);
 
     /**
+     * Flush the queue.
+     */
+    void Flush();
+
+    /**
      * Replace the given current item with the given new item. Actually, the current
      * item is dequeued and the new item is enqueued in its place. In this way,
      * statistics about queue size (in terms of bytes) are correctly updated.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mac-queue-scheduler.h ns-3.40/src/wifi/model/wifi-mac-queue-scheduler.h
--- ns-3.39/src/wifi/model/wifi-mac-queue-scheduler.h	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mac-queue-scheduler.h	2023-09-27 13:30:37.914839700 -0700
@@ -45,6 +45,7 @@
     POWER_SAVE_MODE,
     USING_OTHER_EMLSR_LINK,
     WAITING_EMLSR_TRANSITION_DELAY,
+    TID_NOT_MAPPED,
     REASONS_COUNT
 };
 
@@ -68,6 +69,8 @@
         return (os << "USING_OTHER_EMLSR_LINK");
     case WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY:
         return (os << "WAITING_EMLSR_TRANSITION_DELAY");
+    case WifiQueueBlockedReason::TID_NOT_MAPPED:
+        return (os << "TID_NOT_MAPPED");
     case WifiQueueBlockedReason::REASONS_COUNT:
         return (os << "REASONS_COUNT");
     default:
@@ -101,26 +104,29 @@
     /**
      * Get the next queue to serve, which is guaranteed to contain at least an MPDU
      * whose lifetime has not expired. Queues containing MPDUs that cannot be sent
-     * over the given link are ignored.
+     * over the given link (if any) are ignored.
      *
      * \param ac the Access Category that we want to serve
-     * \param linkId the ID of the link on which we got channel access
+     * \param linkId the ID of the link on which MPDUs contained in the returned queue must be
+     *               allowed to be sent
      * \return the ID of the selected container queue (if any)
      */
-    virtual std::optional<WifiContainerQueueId> GetNext(AcIndex ac, uint8_t linkId) = 0;
+    virtual std::optional<WifiContainerQueueId> GetNext(AcIndex ac,
+                                                        std::optional<uint8_t> linkId) = 0;
     /**
      * Get the next queue to serve after the given one. The returned queue is
      * guaranteed to contain at least an MPDU whose lifetime has not expired.
-     * Queues containing MPDUs that cannot be sent over the given link are ignored.
+     * Queues containing MPDUs that cannot be sent over the given link (if any) are ignored.
      *
      * \param ac the Access Category that we want to serve
-     * \param linkId the ID of the link on which we got channel access
+     * \param linkId the ID of the link on which MPDUs contained in the returned queue must be
+     *               allowed to be sent
      * \param prevQueueId the ID of the container queue served previously
      * \return the ID of the selected container queue (if any)
      */
     virtual std::optional<WifiContainerQueueId> GetNext(
         AcIndex ac,
-        uint8_t linkId,
+        std::optional<uint8_t> linkId,
         const WifiContainerQueueId& prevQueueId) = 0;
 
     /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mac-queue-scheduler-impl.h ns-3.40/src/wifi/model/wifi-mac-queue-scheduler-impl.h
--- ns-3.39/src/wifi/model/wifi-mac-queue-scheduler-impl.h	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mac-queue-scheduler-impl.h	2023-09-27 13:30:37.914839700 -0700
@@ -24,6 +24,7 @@
 #include "wifi-mac-queue.h"
 #include "wifi-mac.h"
 
+#include <algorithm>
 #include <functional>
 #include <list>
 #include <map>
@@ -66,11 +67,14 @@
 
     /** \copydoc ns3::WifiMacQueueScheduler::SetWifiMac */
     void SetWifiMac(Ptr<WifiMac> mac) final;
-    /** \copydoc ns3::WifiMacQueueScheduler::GetNext(AcIndex,uint8_t) */
-    std::optional<WifiContainerQueueId> GetNext(AcIndex ac, uint8_t linkId) final;
-    /** \copydoc ns3::WifiMacQueueScheduler::GetNext(AcIndex,uint8_t,const WifiContainerQueueId&) */
+    /** \copydoc ns3::WifiMacQueueScheduler::GetNext(AcIndex,std::optional<uint8_t>) */
+    std::optional<WifiContainerQueueId> GetNext(AcIndex ac, std::optional<uint8_t> linkId) final;
+    /**
+     *  \copydoc ns3::WifiMacQueueScheduler::GetNext(AcIndex,std::optional<uint8_t>,
+     *           const WifiContainerQueueId&)
+     */
     std::optional<WifiContainerQueueId> GetNext(AcIndex ac,
-                                                uint8_t linkId,
+                                                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;
@@ -202,12 +206,13 @@
      * Queues containing MPDUs that cannot be sent over the given link are ignored.
      *
      * \param ac the Access Category that we want to serve
-     * \param linkId the ID of the link on which we got channel access
+     * \param linkId the ID of the link on which MPDUs contained in the returned queue must be
+     *               allowed to be sent
      * \param sortedQueuesIt iterator pointing to the queue we start the search from
      * \return the ID of the selected container queue (if any)
      */
     std::optional<WifiContainerQueueId> DoGetNext(AcIndex ac,
-                                                  uint8_t linkId,
+                                                  std::optional<uint8_t> linkId,
                                                   typename SortedQueues::iterator sortedQueuesIt);
 
     /**
@@ -352,16 +357,15 @@
 
         // this assert checks that the RA field also contain an MLD address, unless
         // it contains the broadcast address
-        NS_ASSERT_MSG(rxAddr.IsGroup() || GetMac()->GetMldAddress(rxAddr),
+        NS_ASSERT_MSG(rxAddr.IsGroup() || GetMac()->GetMldAddress(rxAddr) == rxAddr,
                       "Address 1 (" << rxAddr << ") is not an MLD address");
 
         // this assert checks that association (ML setup) has been established
         // between sender and receiver (unless the receiver is the broadcast address)
         NS_ASSERT_MSG(GetMac()->CanForwardPacketsTo(rxAddr), "Cannot forward frame to " << rxAddr);
-
         // we have to include all the links in case of broadcast frame (we are an AP)
         // and the links that have been setup with the receiver in case of unicast frame
-        for (uint8_t linkId = 0; linkId < GetMac()->GetNLinks(); linkId++)
+        for (const auto linkId : GetMac()->GetLinkIds())
         {
             if (rxAddr.IsGroup() ||
                 GetMac()->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(rxAddr))
@@ -567,19 +571,19 @@
 
 template <class Priority, class Compare>
 std::optional<WifiContainerQueueId>
-WifiMacQueueSchedulerImpl<Priority, Compare>::GetNext(AcIndex ac, uint8_t linkId)
+WifiMacQueueSchedulerImpl<Priority, Compare>::GetNext(AcIndex ac, std::optional<uint8_t> linkId)
 {
-    NS_LOG_FUNCTION(this << +ac << +linkId);
+    NS_LOG_FUNCTION(this << +ac << linkId.has_value());
     return DoGetNext(ac, linkId, m_perAcInfo[ac].sortedQueues.begin());
 }
 
 template <class Priority, class Compare>
 std::optional<WifiContainerQueueId>
 WifiMacQueueSchedulerImpl<Priority, Compare>::GetNext(AcIndex ac,
-                                                      uint8_t linkId,
+                                                      std::optional<uint8_t> linkId,
                                                       const WifiContainerQueueId& prevQueueId)
 {
-    NS_LOG_FUNCTION(this << +ac << +linkId);
+    NS_LOG_FUNCTION(this << +ac << linkId.has_value());
 
     auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(prevQueueId);
     NS_ABORT_IF(queueInfoIt == m_perAcInfo[ac].queueInfoMap.end() ||
@@ -595,19 +599,20 @@
 std::optional<WifiContainerQueueId>
 WifiMacQueueSchedulerImpl<Priority, Compare>::DoGetNext(
     AcIndex ac,
-    uint8_t linkId,
+    std::optional<uint8_t> linkId,
     typename SortedQueues::iterator sortedQueuesIt)
 {
-    NS_LOG_FUNCTION(this << +ac << +linkId);
+    NS_LOG_FUNCTION(this << +ac << linkId.has_value());
     NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
 
     while (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.end())
     {
         const auto& queueInfoPair = sortedQueuesIt->second.get();
         const auto& linkIds = queueInfoPair.second.linkIds;
+        typename std::decay_t<decltype(linkIds)>::const_iterator linkIt;
 
-        if (const auto linkIt = linkIds.find(linkId);
-            linkIt != linkIds.cend() && linkIt->second.none())
+        if (!linkId.has_value() ||
+            ((linkIt = linkIds.find(*linkId)) != linkIds.cend() && linkIt->second.none()))
         {
             // Packets in this queue can be sent over the link we got channel access on.
             // Now remove packets with expired lifetime from this queue.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mgt-header.h ns-3.40/src/wifi/model/wifi-mgt-header.h
--- ns-3.39/src/wifi/model/wifi-mgt-header.h	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mgt-header.h	2023-09-27 13:30:37.918840000 -0700
@@ -21,11 +21,11 @@
 #define WIFI_MGT_HEADER_H
 
 #include "non-inheritance.h"
+#include "supported-rates.h"
 
 #include "ns3/eht-capabilities.h"
 #include "ns3/header.h"
 #include "ns3/multi-link-element.h"
-#include "ns3/supported-rates.h"
 
 #include <algorithm>
 #include <iterator>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-mode.cc ns-3.40/src/wifi/model/wifi-mode.cc
--- ns-3.39/src/wifi/model/wifi-mode.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-mode.cc	2023-09-27 13:30:37.918840000 -0700
@@ -349,9 +349,8 @@
 WifiMode
 WifiModeFactory::Search(std::string name) const
 {
-    WifiModeItemList::const_iterator i;
     uint32_t j = 0;
-    for (i = m_itemList.begin(); i != m_itemList.end(); i++)
+    for (auto i = m_itemList.begin(); i != m_itemList.end(); i++)
     {
         if (i->uniqueUid == name)
         {
@@ -364,7 +363,7 @@
     // is a fatal problem, but we try to be helpful by displaying the
     // list of WifiModes that are supported.
     NS_LOG_UNCOND("Could not find match for WifiMode named \"" << name << "\". Valid options are:");
-    for (i = m_itemList.begin(); i != m_itemList.end(); i++)
+    for (auto i = m_itemList.begin(); i != m_itemList.end(); i++)
     {
         NS_LOG_UNCOND("  " << i->uniqueUid);
     }
@@ -384,7 +383,7 @@
 WifiModeFactory::AllocateUid(std::string uniqueUid)
 {
     uint32_t j = 0;
-    for (WifiModeItemList::const_iterator i = m_itemList.begin(); i != m_itemList.end(); i++)
+    for (auto i = m_itemList.begin(); i != m_itemList.end(); i++)
     {
         if (i->uniqueUid == uniqueUid)
         {
@@ -392,7 +391,7 @@
         }
         j++;
     }
-    uint32_t uid = static_cast<uint32_t>(m_itemList.size());
+    auto uid = static_cast<uint32_t>(m_itemList.size());
     m_itemList.emplace_back();
     return uid;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-net-device.cc ns-3.40/src/wifi/model/wifi-net-device.cc
--- ns-3.39/src/wifi/model/wifi-net-device.cc	2023-07-05 14:23:48.121428500 -0700
+++ ns-3.40/src/wifi/model/wifi-net-device.cc	2023-09-27 13:30:37.918840000 -0700
@@ -394,7 +394,7 @@
     if (m_mac->GetTypeOfStation() == STA &&
         (staMac = StaticCast<StaWifiMac>(m_mac))->IsAssociated() && m_mac->GetNLinks() > 1 &&
         (linkIds = staMac->GetSetupLinkIds()).size() == 1 &&
-        !GetRemoteStationManager(*linkIds.begin())
+        !m_mac->GetWifiRemoteStationManager(*linkIds.begin())
              ->GetMldAddress(m_mac->GetBssid(*linkIds.begin())))
     {
         return m_mac->GetFrameExchangeManager(*linkIds.begin())->GetAddress();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-phy.cc ns-3.40/src/wifi/model/wifi-phy.cc
--- ns-3.39/src/wifi/model/wifi-phy.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-phy.cc	2023-09-27 13:30:37.918840000 -0700
@@ -1249,7 +1249,7 @@
 WifiPhy::SetNumberOfAntennas(uint8_t antennas)
 {
     NS_LOG_FUNCTION(this << +antennas);
-    NS_ASSERT_MSG(antennas > 0 && antennas <= 4, "unsupported number of antennas");
+    NS_ASSERT_MSG(antennas > 0 && antennas <= 8, "unsupported number of antennas");
     m_numberOfAntennas = antennas;
     if (m_interference)
     {
@@ -1725,7 +1725,30 @@
     NS_ASSERT(!m_state->IsStateTx() && !m_state->IsStateSwitching());
     NS_ASSERT(m_endTxEvent.IsExpired());
 
-    if (txVector.GetNssMax() > GetMaxSupportedTxSpatialStreams())
+    if (!txVector.IsValid())
+    {
+        NS_FATAL_ERROR("TX-VECTOR is invalid!");
+    }
+
+    uint8_t nss = 0;
+    if (txVector.IsMu())
+    {
+        // We do not support mixed OFDMA and MU-MIMO
+        if (txVector.IsDlMuMimo())
+        {
+            nss = txVector.GetNssTotal();
+        }
+        else
+        {
+            nss = txVector.GetNssMax();
+        }
+    }
+    else
+    {
+        nss = txVector.GetNss();
+    }
+
+    if (nss > GetMaxSupportedTxSpatialStreams())
     {
         NS_FATAL_ERROR("Unsupported number of spatial streams!");
     }
@@ -1747,9 +1770,7 @@
     {
         noEndPreambleDetectionEvent &= it.second->NoEndPreambleDetectionEvents();
     }
-    if (!noEndPreambleDetectionEvent ||
-        (m_currentEvent &&
-         (m_currentEvent->GetEndTime() > (Simulator::Now() + m_state->GetDelayUntilIdle()))))
+    if (!noEndPreambleDetectionEvent || m_currentEvent)
     {
         AbortCurrentReception(RECEPTION_ABORTED_BY_TX);
     }
@@ -1817,6 +1838,13 @@
 }
 
 void
+WifiPhy::SetPreviouslyRxPpduUid(uint64_t uid)
+{
+    NS_ASSERT(m_standard >= WIFI_STANDARD_80211be);
+    m_previouslyRxPpduUid = uid;
+}
+
+void
 WifiPhy::Reset()
 {
     NS_LOG_FUNCTION(this);
@@ -1846,7 +1874,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, ppdu->GetTxVector(), rxDuration, rxPowersW);
+        m_interference->Add(ppdu, rxDuration, rxPowersW);
         SwitchMaybeToCcaBusy(nullptr);
     }
 }
@@ -2146,7 +2174,7 @@
     }
     else
     {
-        if (txVector.GetNssMax() > 1)
+        if (txVector.GetNssMax() > 1 || txVector.GetNssTotal() > 1)
         {
             txPowerDbm = std::min(m_txPowerMaxMimo, GetPowerDbm(txVector.GetTxPowerLevel()));
         }
@@ -2157,7 +2185,7 @@
     }
 
     // Apply power density constraint on EIRP
-    uint16_t channelWidth = ppdu->GetTransmissionChannelWidth();
+    uint16_t channelWidth = ppdu->GetTxChannelWidth();
     double txPowerDbmPerMhz =
         (txPowerDbm + GetTxGain()) - RatioToDb(channelWidth); // account for antenna gain since EIRP
     NS_LOG_INFO("txPowerDbm=" << txPowerDbm << " with txPowerDbmPerMhz=" << txPowerDbmPerMhz
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-phy-common.h ns-3.40/src/wifi/model/wifi-phy-common.h
--- ns-3.39/src/wifi/model/wifi-phy-common.h	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-phy-common.h	2023-09-27 13:30:37.918840000 -0700
@@ -60,6 +60,9 @@
     WifiSpectrumBandFrequencies frequencies; //!< the start and stop frequencies of the band
 };
 
+/// vector of spectrum bands
+using WifiSpectrumBands = std::vector<WifiSpectrumBandInfo>;
+
 /**
  * \ingroup wifi
  * Compare two bands.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-phy.h ns-3.40/src/wifi/model/wifi-phy.h
--- ns-3.39/src/wifi/model/wifi-phy.h	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-phy.h	2023-09-27 13:30:37.918840000 -0700
@@ -1123,6 +1123,18 @@
     uint64_t GetPreviouslyRxPpduUid() const;
 
     /**
+     * Set the UID of the previously received PPDU.
+     *
+     * \param uid the value for the UID of the previously received PPDU
+     *
+     * \note This method shall only be used in exceptional circumstances, such as when a PHY
+     * transmits a response to a Trigger Frame that was received by another PHY. This is the
+     * case, e.g., when an aux PHY of an EMLSR client receives an ICF but it is the main PHY
+     * that switches channel and transmits the response to the ICF.
+     */
+    void SetPreviouslyRxPpduUid(uint64_t uid);
+
+    /**
      * \param currentChannelWidth channel width of the current transmission (MHz)
      * \return the width of the guard band (MHz)
      *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-ppdu.cc ns-3.40/src/wifi/model/wifi-ppdu.cc
--- ns-3.39/src/wifi/model/wifi-ppdu.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-ppdu.cc	2023-09-27 13:30:37.918840000 -0700
@@ -19,10 +19,10 @@
 
 #include "wifi-ppdu.h"
 
+#include "wifi-phy-operating-channel.h"
 #include "wifi-psdu.h"
 
 #include "ns3/log.h"
-#include "ns3/wifi-phy-operating-channel.h"
 
 namespace ns3
 {
@@ -42,7 +42,9 @@
       m_txVector(txVector),
       m_operatingChannel(channel),
       m_truncatedTx(false),
-      m_txPowerLevel(txVector.GetTxPowerLevel())
+      m_txPowerLevel(txVector.GetTxPowerLevel()),
+      m_txAntennas(txVector.GetNTx()),
+      m_txChannelWidth(txVector.GetChannelWidth())
 {
     NS_LOG_FUNCTION(this << *psdu << txVector << channel << uid);
     m_psdus.insert(std::make_pair(SU_STA_ID, psdu));
@@ -63,7 +65,8 @@
       m_operatingChannel(channel),
       m_truncatedTx(false),
       m_txPowerLevel(txVector.GetTxPowerLevel()),
-      m_txAntennas(txVector.GetNTx())
+      m_txAntennas(txVector.GetNTx()),
+      m_txChannelWidth(txVector.GetChannelWidth())
 {
     NS_LOG_FUNCTION(this << psdus << txVector << channel << uid);
     m_psdus = psdus;
@@ -86,6 +89,7 @@
         m_txVector = DoGetTxVector();
         m_txVector->SetTxPowerLevel(m_txPowerLevel);
         m_txVector->SetNTx(m_txAntennas);
+        m_txVector->SetChannelWidth(m_txChannelWidth);
     }
     return m_txVector.value();
 }
@@ -139,9 +143,9 @@
 }
 
 uint16_t
-WifiPpdu::GetTransmissionChannelWidth() const
+WifiPpdu::GetTxChannelWidth() const
 {
-    return GetTxVector().GetChannelWidth();
+    return m_txChannelWidth;
 }
 
 uint16_t
@@ -154,9 +158,8 @@
 WifiPpdu::DoesOverlapChannel(uint16_t minFreq, uint16_t maxFreq) const
 {
     NS_LOG_FUNCTION(this << m_txCenterFreq << minFreq << maxFreq);
-    uint16_t txChannelWidth = GetTxVector().GetChannelWidth();
-    uint16_t minTxFreq = m_txCenterFreq - txChannelWidth / 2;
-    uint16_t maxTxFreq = m_txCenterFreq + txChannelWidth / 2;
+    uint16_t minTxFreq = m_txCenterFreq - m_txChannelWidth / 2;
+    uint16_t maxTxFreq = m_txCenterFreq + m_txChannelWidth / 2;
     /**
      * The PPDU does not overlap the channel in two cases.
      *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-ppdu.h ns-3.40/src/wifi/model/wifi-ppdu.h
--- ns-3.39/src/wifi/model/wifi-ppdu.h	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-ppdu.h	2023-09-27 13:30:37.918840000 -0700
@@ -134,7 +134,7 @@
      *
      * \return the effective channel width (in MHz) used for the tranmsission
      */
-    virtual uint16_t GetTransmissionChannelWidth() const;
+    virtual uint16_t GetTxChannelWidth() const;
 
     /**
      * \return the center frequency (MHz) used for the transmission of this PPDU
@@ -222,7 +222,13 @@
     uint8_t m_txPowerLevel; //!< the transmission power level (used only for TX and initializing the
                             //!< returned WifiTxVector)
     uint8_t m_txAntennas;   //!< the number of antennas used to transmit this PPDU
-};                          // class WifiPpdu
+
+    uint16_t m_txChannelWidth; /**< The channel width (MHz) used for the transmission of this
+                                         PPDU. This has to be stored since channel width can not
+                                         always be obtained from the PHY headers, especially for
+                                         non-HT PPDU, since we do not sense the spectrum to
+                                         determine the occupied channel width for simplicity. */
+};                             // class WifiPpdu
 
 /**
  * \brief Stream insertion operator.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-remote-station-manager.cc ns-3.40/src/wifi/model/wifi-remote-station-manager.cc
--- ns-3.39/src/wifi/model/wifi-remote-station-manager.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-remote-station-manager.cc	2023-09-27 13:30:37.918840000 -0700
@@ -390,11 +390,9 @@
     NS_LOG_FUNCTION(this << address);
     NS_ASSERT(!address.IsGroup());
     auto state = LookupState(address);
-    state->m_operationalMcsSet.clear();
-    for (const auto& mcs : m_wifiPhy->GetMcsList())
-    {
-        state->m_operationalMcsSet.push_back(mcs);
-    }
+
+    const auto& mcsList = m_wifiPhy->GetMcsList();
+    state->m_operationalMcsSet = WifiModeList(mcsList.begin(), mcsList.end());
 }
 
 void
@@ -565,21 +563,16 @@
     LookupState(address)->m_isInPsMode = isInPsMode;
 }
 
-void
-WifiRemoteStationManager::SetMldAddress(const Mac48Address& address, const Mac48Address& mldAddress)
-{
-    NS_LOG_FUNCTION(this << address << mldAddress);
-
-    auto state = LookupState(address);
-    state->m_mldAddress = mldAddress;
-    // insert another entry in m_states indexed by the MLD address and pointing to the same state
-    const_cast<WifiRemoteStationManager*>(this)->m_states.insert({mldAddress, state});
-}
-
 std::optional<Mac48Address>
 WifiRemoteStationManager::GetMldAddress(const Mac48Address& address) const
 {
-    return LookupState(address)->m_mldAddress;
+    if (auto stateIt = m_states.find(address);
+        stateIt != m_states.end() && stateIt->second->m_mleCommonInfo)
+    {
+        return stateIt->second->m_mleCommonInfo->m_mldMacAddress;
+    }
+
+    return std::nullopt;
 }
 
 std::optional<Mac48Address>
@@ -587,13 +580,13 @@
 {
     auto stateIt = m_states.find(mldAddress);
 
-    if (stateIt == m_states.end() || !stateIt->second->m_mldAddress)
+    if (stateIt == m_states.end() || !stateIt->second->m_mleCommonInfo)
     {
         // MLD address not found
         return std::nullopt;
     }
 
-    NS_ASSERT(*stateIt->second->m_mldAddress == mldAddress);
+    NS_ASSERT(stateIt->second->m_mleCommonInfo->m_mldMacAddress == mldAddress);
     return stateIt->second->m_address;
 }
 
@@ -652,7 +645,7 @@
     {
         txVector = DoGetDataTxVector(Lookup(address), allowedWidth);
         txVector.SetLdpc(txVector.GetMode().GetModulationClass() < WIFI_MOD_CLASS_HT
-                             ? 0
+                             ? false
                              : UseLdpcForDestination(address));
     }
     Ptr<HeConfiguration> heConfiguration = m_wifiPhy->GetDevice()->GetHeConfiguration();
@@ -1169,7 +1162,7 @@
     {
         // search for the BSS Basic Rate set, if the used mode is in the basic set then there is no
         // need for CTS To Self
-        for (WifiModeListIterator i = m_bssBasicRateSet.begin(); i != m_bssBasicRateSet.end(); i++)
+        for (auto i = m_bssBasicRateSet.begin(); i != m_bssBasicRateSet.end(); i++)
         {
             if (mode == *i)
             {
@@ -1181,8 +1174,7 @@
         {
             // 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
-            for (WifiModeListIterator i = m_bssBasicMcsSet.begin(); i != m_bssBasicMcsSet.end();
-                 i++)
+            for (auto i = m_bssBasicMcsSet.begin(); i != m_bssBasicMcsSet.end(); i++)
             {
                 if (mode == *i)
                 {
@@ -1422,7 +1414,7 @@
     state->m_vhtCapabilities = nullptr;
     state->m_heCapabilities = nullptr;
     state->m_ehtCapabilities = nullptr;
-    state->m_emlCapabilities = nullptr;
+    state->m_mleCommonInfo = nullptr;
     state->m_emlsrEnabled = false;
     state->m_channelWidth = m_wifiPhy->GetChannelWidth();
     state->m_guardInterval = GetGuardInterval();
@@ -1557,7 +1549,7 @@
             state->m_channelWidth = 20;
         }
     }
-    if (heCapabilities.GetHeSuPpdu1xHeLtf800nsGi() == 1)
+    if (heCapabilities.GetHeSuPpdu1xHeLtf800nsGi())
     {
         state->m_guardInterval = 800;
     }
@@ -1600,12 +1592,16 @@
 }
 
 void
-WifiRemoteStationManager::AddStationEmlCapabilities(
+WifiRemoteStationManager::AddStationMleCommonInfo(
     Mac48Address from,
-    const std::shared_ptr<CommonInfoBasicMle::EmlCapabilities>& emlCapabilities)
+    const std::shared_ptr<CommonInfoBasicMle>& mleCommonInfo)
 {
     NS_LOG_FUNCTION(this << from);
-    LookupState(from)->m_emlCapabilities = emlCapabilities;
+    auto state = LookupState(from);
+    state->m_mleCommonInfo = mleCommonInfo;
+    // insert another entry in m_states indexed by the MLD address and pointing to the same state
+    const_cast<WifiRemoteStationManager*>(this)->m_states.insert(
+        {mleCommonInfo->m_mldMacAddress, state});
 }
 
 Ptr<const HtCapabilities>
@@ -1632,10 +1628,26 @@
     return LookupState(from)->m_ehtCapabilities;
 }
 
-std::shared_ptr<CommonInfoBasicMle::EmlCapabilities>
+std::optional<std::reference_wrapper<CommonInfoBasicMle::EmlCapabilities>>
 WifiRemoteStationManager::GetStationEmlCapabilities(const Mac48Address& from)
 {
-    return LookupState(from)->m_emlCapabilities;
+    if (auto state = LookupState(from);
+        state->m_mleCommonInfo && state->m_mleCommonInfo->m_emlCapabilities)
+    {
+        return state->m_mleCommonInfo->m_emlCapabilities.value();
+    }
+    return std::nullopt;
+}
+
+std::optional<std::reference_wrapper<CommonInfoBasicMle::MldCapabilities>>
+WifiRemoteStationManager::GetStationMldCapabilities(const Mac48Address& from)
+{
+    if (auto state = LookupState(from);
+        state->m_mleCommonInfo && state->m_mleCommonInfo->m_mldCapabilities)
+    {
+        return state->m_mleCommonInfo->m_mldCapabilities.value();
+    }
+    return std::nullopt;
 }
 
 bool
@@ -1748,7 +1760,7 @@
 WifiRemoteStationManager::GetNNonErpBasicModes() const
 {
     uint32_t size = 0;
-    for (WifiModeListIterator i = m_bssBasicRateSet.begin(); i != m_bssBasicRateSet.end(); i++)
+    for (auto i = m_bssBasicRateSet.begin(); i != m_bssBasicRateSet.end(); i++)
     {
         if (i->GetModulationClass() == WIFI_MOD_CLASS_ERP_OFDM)
         {
@@ -1765,7 +1777,7 @@
     NS_ASSERT(i < GetNNonErpBasicModes());
     uint32_t index = 0;
     bool found = false;
-    for (WifiModeListIterator j = m_bssBasicRateSet.begin(); j != m_bssBasicRateSet.end();)
+    for (auto j = m_bssBasicRateSet.begin(); j != m_bssBasicRateSet.end();)
     {
         if (i == index)
         {
@@ -1889,7 +1901,7 @@
     // moved in case it breaks standard rules.
     uint32_t index = 0;
     bool found = false;
-    for (WifiModeListIterator j = station->m_state->m_operationalRateSet.begin();
+    for (auto j = station->m_state->m_operationalRateSet.begin();
          j != station->m_state->m_operationalRateSet.end();)
     {
         if (i == index)
@@ -2014,8 +2026,9 @@
 bool
 WifiRemoteStationManager::GetEmlsrSupported(const WifiRemoteStation* station) const
 {
-    auto emlCapabilities = station->m_state->m_emlCapabilities;
-    return emlCapabilities && emlCapabilities->emlsrSupport == 1;
+    auto mleCommonInfo = station->m_state->m_mleCommonInfo;
+    return mleCommonInfo && mleCommonInfo->m_emlCapabilities &&
+           mleCommonInfo->m_emlCapabilities->emlsrSupport == 1;
 }
 
 bool
@@ -2034,7 +2047,7 @@
 WifiRemoteStationManager::GetNNonErpSupported(const WifiRemoteStation* station) const
 {
     uint32_t size = 0;
-    for (WifiModeListIterator i = station->m_state->m_operationalRateSet.begin();
+    for (auto i = station->m_state->m_operationalRateSet.begin();
          i != station->m_state->m_operationalRateSet.end();
          i++)
     {
@@ -2128,8 +2141,9 @@
 bool
 WifiRemoteStationManager::GetEmlsrSupported(const Mac48Address& address) const
 {
-    auto emlCapabilities = LookupState(address)->m_emlCapabilities;
-    return emlCapabilities && emlCapabilities->emlsrSupport == 1;
+    auto mleCommonInfo = LookupState(address)->m_mleCommonInfo;
+    return mleCommonInfo && mleCommonInfo->m_emlCapabilities &&
+           mleCommonInfo->m_emlCapabilities->emlsrSupport == 1;
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-remote-station-manager.h ns-3.40/src/wifi/model/wifi-remote-station-manager.h
--- ns-3.39/src/wifi/model/wifi-remote-station-manager.h	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-remote-station-manager.h	2023-09-27 13:30:37.918840000 -0700
@@ -99,23 +99,21 @@
      * WifiRemoteStationManager::GetNSupported() and
      * WifiRemoteStationManager::GetSupported().
      */
-    WifiModeList m_operationalRateSet;        //!< operational rate set
-    WifiModeList m_operationalMcsSet;         //!< operational MCS set
-    Mac48Address m_address;                   //!< Mac48Address of the remote station
-    uint16_t m_aid;                           /**< AID of the remote station (unused if this object
-                                                   is installed on a non-AP station) */
-    std::optional<Mac48Address> m_mldAddress; /**< MLD MAC address if the remote station is
-                                                   affiliated with an MLD */
-    WifiRemoteStationInfo m_info;             //!< remote station info
-    bool m_dsssSupported;                     //!< Flag if DSSS is supported by the remote station
-    bool m_erpOfdmSupported; //!< Flag if ERP OFDM is supported by the remote station
-    bool m_ofdmSupported;    //!< Flag if OFDM is supported by the remote station
+    WifiModeList m_operationalRateSet; //!< operational rate set
+    WifiModeList m_operationalMcsSet;  //!< operational MCS set
+    Mac48Address m_address;            //!< Mac48Address of the remote station
+    uint16_t m_aid;                    /**< AID of the remote station (unused if this object
+                                            is installed on a non-AP station) */
+    WifiRemoteStationInfo m_info;      //!< remote station info
+    bool m_dsssSupported;              //!< Flag if DSSS is supported by the remote station
+    bool m_erpOfdmSupported;           //!< Flag if ERP OFDM is supported by the remote station
+    bool m_ofdmSupported;              //!< Flag if OFDM is supported by the remote station
     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 EhtCapabilities> m_ehtCapabilities; //!< remote station EHT capabilities
-    /// remote station EML capabilities
-    std::shared_ptr<CommonInfoBasicMle::EmlCapabilities> m_emlCapabilities;
+    /// remote station Multi-Link Element Common Info
+    std::shared_ptr<CommonInfoBasicMle> m_mleCommonInfo;
     bool m_emlsrEnabled; //!< whether EMLSR mode is enabled on this link
 
     uint16_t m_channelWidth;  //!< Channel width (in MHz) supported by the remote station
@@ -270,14 +268,14 @@
      */
     void AddStationEhtCapabilities(Mac48Address from, EhtCapabilities ehtCapabilities);
     /**
-     * Records EML capabilities of the remote station.
+     * Records the Common Info field advertised by the given remote station in a Multi-Link
+     * Element. It includes the MLD address of the remote station.
      *
      * \param from the address of the station being recorded
-     * \param emlCapabilities the EML capabilities of the station
+     * \param mleCommonInfo the MLE Common Info advertised by the station
      */
-    void AddStationEmlCapabilities(
-        Mac48Address from,
-        const std::shared_ptr<CommonInfoBasicMle::EmlCapabilities>& emlCapabilities);
+    void AddStationMleCommonInfo(Mac48Address from,
+                                 const std::shared_ptr<CommonInfoBasicMle>& mleCommonInfo);
     /**
      * Return the HT capabilities sent by the remote station.
      *
@@ -310,8 +308,14 @@
      * \param from the (MLD or link) address of the remote non-AP MLD
      * \return the EML Capabilities advertised by the remote non-AP MLD
      */
-    std::shared_ptr<CommonInfoBasicMle::EmlCapabilities> GetStationEmlCapabilities(
-        const Mac48Address& from);
+    std::optional<std::reference_wrapper<CommonInfoBasicMle::EmlCapabilities>>
+    GetStationEmlCapabilities(const Mac48Address& from);
+    /**
+     * \param from the (MLD or link) address of the remote non-AP MLD
+     * \return the MLD Capabilities advertised by the remote non-AP MLD
+     */
+    std::optional<std::reference_wrapper<CommonInfoBasicMle::MldCapabilities>>
+    GetStationMldCapabilities(const Mac48Address& from);
     /**
      * Return whether the device has HT capability support enabled.
      *
@@ -785,14 +789,6 @@
     void SetPsMode(const Mac48Address& address, bool isInPsMode);
 
     /**
-     * Set the address of the MLD the given station is affiliated with.
-     *
-     * \param address the MAC address of the remote station
-     * \param mldAddress the MAC address of the MLD the remote station is
-     *                   affiliated with
-     */
-    void SetMldAddress(const Mac48Address& address, const Mac48Address& mldAddress);
-    /**
      * Get the address of the MLD the given station is affiliated with, if any.
      * Note that an MLD address is only present if an ML discovery/setup was performed
      * with the given station (which requires both this station and the given
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-spectrum-phy-interface.cc ns-3.40/src/wifi/model/wifi-spectrum-phy-interface.cc
--- ns-3.39/src/wifi/model/wifi-spectrum-phy-interface.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-spectrum-phy-interface.cc	2023-09-27 13:30:37.918840000 -0700
@@ -45,7 +45,7 @@
       m_centerFrequency{0},
       m_channelWidth{0},
       m_bands{},
-      m_ruBands{}
+      m_heRuBands{}
 {
     NS_LOG_FUNCTION(this << freqRange);
 }
@@ -59,7 +59,7 @@
     m_netDevice = nullptr;
     m_channel = nullptr;
     m_bands.clear();
-    m_ruBands.clear();
+    m_heRuBands.clear();
 }
 
 void
@@ -158,27 +158,27 @@
 }
 
 void
-WifiSpectrumPhyInterface::SetBands(WifiSpectrumPhyInterface::WifiSpectrumBands&& bands)
+WifiSpectrumPhyInterface::SetBands(WifiSpectrumBands&& bands)
 {
     m_bands = std::move(bands);
 }
 
-const WifiSpectrumPhyInterface::WifiSpectrumBands&
+const WifiSpectrumBands&
 WifiSpectrumPhyInterface::GetBands() const
 {
     return m_bands;
 }
 
 void
-WifiSpectrumPhyInterface::SetRuBands(HePhy::RuBands&& ruBands)
+WifiSpectrumPhyInterface::SetHeRuBands(HeRuBands&& heRuBands)
 {
-    m_ruBands = std::move(ruBands);
+    m_heRuBands = std::move(heRuBands);
 }
 
-const HePhy::RuBands&
-WifiSpectrumPhyInterface::GetRuBands() const
+const HeRuBands&
+WifiSpectrumPhyInterface::GetHeRuBands() const
 {
-    return m_ruBands;
+    return m_heRuBands;
 }
 
 void
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-spectrum-phy-interface.h ns-3.40/src/wifi/model/wifi-spectrum-phy-interface.h
--- ns-3.39/src/wifi/model/wifi-spectrum-phy-interface.h	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-spectrum-phy-interface.h	2023-09-27 13:30:37.918840000 -0700
@@ -126,9 +126,6 @@
                             uint32_t bandBandwidth,
                             uint16_t guardBandwidth);
 
-    /// vector of spectrum bands handled by this interface
-    using WifiSpectrumBands = std::vector<WifiSpectrumBandInfo>;
-
     /**
      * Set the vector of spectrum bands handled by this interface
      *
@@ -145,15 +142,15 @@
     /**
      * Set the HE RU spectrum bands handled by this interface (if any)
      *
-     * \param ruBands the HE RU spectrum bands
+     * \param heRuBands the HE RU spectrum bands
      */
-    void SetRuBands(HePhy::RuBands&& ruBands);
+    void SetHeRuBands(HeRuBands&& heRuBands);
     /**
      * Get the HE RU spectrum bands handled by this interface
      *
      * \return the HE RU spectrum bands
      */
-    const HePhy::RuBands& GetRuBands() const;
+    const HeRuBands& GetHeRuBands() const;
 
   private:
     void DoDispose() override;
@@ -168,7 +165,7 @@
 
     WifiSpectrumBands
         m_bands; /**< Store all the distinct spectrum bands associated with every channels widths */
-    HePhy::RuBands m_ruBands; /**< Store all the distinct spectrum bands associated with every RU */
+    HeRuBands m_heRuBands; /**< Store all the distinct spectrum bands associated with every RU */
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-spectrum-signal-parameters.cc ns-3.40/src/wifi/model/wifi-spectrum-signal-parameters.cc
--- ns-3.39/src/wifi/model/wifi-spectrum-signal-parameters.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-spectrum-signal-parameters.cc	2023-09-27 13:30:37.918840000 -0700
@@ -31,16 +31,14 @@
 
 WifiSpectrumSignalParameters::WifiSpectrumSignalParameters()
     : SpectrumSignalParameters(),
-      ppdu(nullptr),
-      txWidth(0)
+      ppdu(nullptr)
 {
     NS_LOG_FUNCTION(this);
 }
 
 WifiSpectrumSignalParameters::WifiSpectrumSignalParameters(const WifiSpectrumSignalParameters& p)
     : SpectrumSignalParameters(p),
-      ppdu(p.ppdu),
-      txWidth(p.txWidth)
+      ppdu(p.ppdu)
 {
     NS_LOG_FUNCTION(this << &p);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-spectrum-signal-parameters.h ns-3.40/src/wifi/model/wifi-spectrum-signal-parameters.h
--- ns-3.39/src/wifi/model/wifi-spectrum-signal-parameters.h	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-spectrum-signal-parameters.h	2023-09-27 13:30:37.918840000 -0700
@@ -50,7 +50,6 @@
     WifiSpectrumSignalParameters(const WifiSpectrumSignalParameters& p);
 
     Ptr<const WifiPpdu> ppdu; ///< The PPDU being transmitted
-    uint16_t txWidth;         ///< The TX width in MHz
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-tx-timer.cc ns-3.40/src/wifi/model/wifi-tx-timer.cc
--- ns-3.39/src/wifi/model/wifi-tx-timer.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-tx-timer.cc	2023-09-27 13:30:37.918840000 -0700
@@ -129,6 +129,19 @@
     NS_LOG_FUNCTION(this << GetReasonString(m_reason));
     m_timeoutEvent.Cancel();
     m_impl = nullptr;
+    m_staExpectResponseFrom.clear();
+}
+
+void
+WifiTxTimer::GotResponseFrom(const Mac48Address& from)
+{
+    m_staExpectResponseFrom.erase(from);
+}
+
+const std::set<Mac48Address>&
+WifiTxTimer::GetStasExpectedToRespond() const
+{
+    return m_staExpectResponseFrom;
 }
 
 Time
@@ -174,13 +187,14 @@
 }
 
 void
-WifiTxTimer::FeedTraceSource(WifiPsduMap* psduMap,
-                             std::set<Mac48Address>* missingStations,
-                             std::size_t nTotalStations)
+WifiTxTimer::FeedTraceSource(WifiPsduMap* psduMap, std::size_t nTotalStations)
 {
     if (!m_psduMapResponseTimeoutCallback.IsNull())
     {
-        m_psduMapResponseTimeoutCallback(m_reason, psduMap, missingStations, nTotalStations);
+        m_psduMapResponseTimeoutCallback(m_reason,
+                                         psduMap,
+                                         &m_staExpectResponseFrom,
+                                         nTotalStations);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-tx-timer.h ns-3.40/src/wifi/model/wifi-tx-timer.h
--- ns-3.39/src/wifi/model/wifi-tx-timer.h	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-tx-timer.h	2023-09-27 13:30:37.918840000 -0700
@@ -81,12 +81,18 @@
      * \tparam Args \deduced Type template parameter pack
      * \param reason the reason why the timer was started
      * \param delay the time to the expiration of the timer
+     * \param from the set of stations we expect to receive a response from
      * \param mem_ptr Member method pointer to invoke
      * \param obj The object on which to invoke the member method
      * \param args The arguments to pass to the invoked method
      */
     template <typename MEM, typename OBJ, typename... Args>
-    void Set(Reason reason, const Time& delay, MEM mem_ptr, OBJ obj, Args... args);
+    void Set(Reason reason,
+             const Time& delay,
+             const std::set<Mac48Address>& from,
+             MEM mem_ptr,
+             OBJ obj,
+             Args... args);
 
     /**
      * Reschedule the timer to time out the given amount of time from the moment
@@ -125,6 +131,18 @@
     void Cancel();
 
     /**
+     * Notify that a response was got from the given station.
+     *
+     * \param from the MAC address of the given station
+     */
+    void GotResponseFrom(const Mac48Address& from);
+
+    /**
+     * \return the set of stations that are still expected to respond
+     */
+    const std::set<Mac48Address>& GetStasExpectedToRespond() const;
+
+    /**
      * Get the remaining time until the timer will expire.
      *
      * \return the remaining time until the timer will expire.
@@ -216,18 +234,17 @@
      * timeout callback.
      *
      * \param psduMap the PSDU map for which not all responses were received
-     * \param missingStations the set of stations that did not respond
      * \param nTotalStations the total number of expected responses
      */
-    void FeedTraceSource(WifiPsduMap* psduMap,
-                         std::set<Mac48Address>* missingStations,
-                         std::size_t nTotalStations);
+    void FeedTraceSource(WifiPsduMap* psduMap, std::size_t nTotalStations);
 
     EventId m_timeoutEvent; //!< the timeout event after a missing response
     Reason m_reason;        //!< the reason why the timer was started
     Ptr<EventImpl> m_impl;  /**< the timer implementation, which contains the bound
                                  callback function and arguments */
     Time m_end;             //!< the absolute time when the timer will expire
+    std::set<Mac48Address>
+        m_staExpectResponseFrom; //!< the set of stations we expect to receive a response from
 
     /// the MPDU response timeout callback
     mutable MpduResponseTimeout m_mpduResponseTimeoutCallback;
@@ -248,13 +265,19 @@
 
 template <typename MEM, typename OBJ, typename... Args>
 void
-WifiTxTimer::Set(Reason reason, const Time& delay, MEM mem_ptr, OBJ obj, Args... args)
+WifiTxTimer::Set(Reason reason,
+                 const Time& delay,
+                 const std::set<Mac48Address>& from,
+                 MEM mem_ptr,
+                 OBJ obj,
+                 Args... args)
 {
     typedef void (WifiTxTimer::*TimeoutType)(MEM, OBJ, Args...);
 
     m_timeoutEvent = Simulator::Schedule(delay, &WifiTxTimer::Expire, this);
     m_reason = reason;
     m_end = Simulator::Now() + delay;
+    m_staExpectResponseFrom = from;
 
     // create an event to invoke when the timer expires
     m_impl = Ptr<EventImpl>(MakeEvent<TimeoutType>(&WifiTxTimer::Timeout,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-tx-vector.cc ns-3.40/src/wifi/model/wifi-tx-vector.cc
--- ns-3.39/src/wifi/model/wifi-tx-vector.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-tx-vector.cc	2023-09-27 13:30:37.918840000 -0700
@@ -27,6 +27,8 @@
 
 #include <algorithm>
 #include <iterator>
+#include <numeric>
+#include <set>
 
 namespace ns3
 {
@@ -217,6 +219,7 @@
 uint8_t
 WifiTxVector::GetNssMax() const
 {
+    // We do not support mixed OFDMA and MU-MIMO
     uint8_t nss = 0;
     if (IsMu())
     {
@@ -233,6 +236,26 @@
 }
 
 uint8_t
+WifiTxVector::GetNssTotal() const
+{
+    // We do not support mixed OFDMA and MU-MIMO
+    uint8_t nss = 0;
+    if (IsMu())
+    {
+        nss = std::accumulate(
+            m_muUserInfos.cbegin(),
+            m_muUserInfos.cend(),
+            0,
+            [](uint8_t prevNss, const auto& info) { return prevNss + info.second.nss; });
+    }
+    else
+    {
+        nss = m_nss;
+    }
+    return nss;
+}
+
+uint8_t
 WifiTxVector::GetNess() const
 {
     return m_ness;
@@ -259,8 +282,7 @@
 bool
 WifiTxVector::IsNonHtDuplicate() const
 {
-    return ((m_channelWidth >= 40) && !IsMu() &&
-            (GetMode().GetModulationClass() < WIFI_MOD_CLASS_HT));
+    return ((m_channelWidth >= 40) && !IsMu() && (GetModulationClass() < WIFI_MOD_CLASS_HT));
 }
 
 void
@@ -440,25 +462,64 @@
     {
         if (m_nss != 3 && m_nss != 6)
         {
-            return (modeName != "VhtMcs9");
+            if (modeName == "VhtMcs9")
+            {
+                return false;
+            }
         }
     }
     else if (m_channelWidth == 80)
     {
         if (m_nss == 3 || m_nss == 7)
         {
-            return (modeName != "VhtMcs6");
+            if (modeName == "VhtMcs6")
+            {
+                return false;
+            }
         }
         else if (m_nss == 6)
         {
-            return (modeName != "VhtMcs9");
+            if (modeName == "VhtMcs9")
+            {
+                return false;
+            }
         }
     }
     else if (m_channelWidth == 160)
     {
         if (m_nss == 3)
         {
-            return (modeName != "VhtMcs9");
+            if (modeName == "VhtMcs9")
+            {
+                return false;
+            }
+        }
+    }
+    for (const auto& userInfo : m_muUserInfos)
+    {
+        if (GetNumStasInRu(userInfo.second.ru) > 8)
+        {
+            return false;
+        }
+    }
+    std::map<HeRu::RuSpec, uint8_t> streamsPerRu{};
+    for (const auto& info : m_muUserInfos)
+    {
+        auto it = streamsPerRu.find(info.second.ru);
+        if (it == streamsPerRu.end())
+        {
+            streamsPerRu[info.second.ru] = info.second.nss;
+        }
+        else
+        {
+            it->second += info.second.nss;
+        }
+    }
+    for (auto& streams : streamsPerRu)
+    {
+        if (streams.second > 8)
+        {
+            return false;
         }
     }
     return true;
@@ -483,6 +544,60 @@
 }
 
 bool
+WifiTxVector::IsDlOfdma() const
+{
+    if (!IsDlMu())
+    {
+        return false;
+    }
+    if (IsEht(m_preamble))
+    {
+        return m_ehtPpduType == 0;
+    }
+    if (m_muUserInfos.size() == 1)
+    {
+        return true;
+    }
+    std::set<HeRu::RuSpec> rus{};
+    for (const auto& userInfo : m_muUserInfos)
+    {
+        rus.insert(userInfo.second.ru);
+        if (rus.size() > 1)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool
+WifiTxVector::IsDlMuMimo() const
+{
+    if (!IsDlMu())
+    {
+        return false;
+    }
+    if (IsEht(m_preamble))
+    {
+        return m_ehtPpduType == 2;
+    }
+    if (m_muUserInfos.size() < 2)
+    {
+        return false;
+    }
+    // TODO: mixed OFDMA and MU-MIMO is not supported
+    return !IsDlOfdma();
+}
+
+uint8_t
+WifiTxVector::GetNumStasInRu(const HeRu::RuSpec& ru) const
+{
+    return std::count_if(m_muUserInfos.cbegin(),
+                         m_muUserInfos.cend(),
+                         [&ru](const auto& info) -> bool { return (ru == info.second.ru); });
+}
+
+bool
 WifiTxVector::IsAllocated(uint16_t staId) const
 {
     return m_muUserInfos.count(staId) > 0;
@@ -536,6 +651,12 @@
     return m_muUserInfos;
 }
 
+bool
+WifiTxVector::IsSigBCompression() const
+{
+    return IsDlMuMimo() && !IsDlOfdma();
+}
+
 void
 WifiTxVector::SetInactiveSubchannels(const std::vector<bool>& inactiveSubchannels)
 {
@@ -652,11 +773,18 @@
 {
     auto heRuComparator = HeRu::RuSpecCompare(m_channelWidth, p20Index);
     UserInfoMapOrderedByRus orderedMap{heRuComparator};
-    std::transform(
-        m_muUserInfos.cbegin(),
-        m_muUserInfos.cend(),
-        std::inserter(orderedMap, orderedMap.end()),
-        [](auto&& userInfo) { return std::make_pair(userInfo.second.ru, userInfo.first); });
+    for (const auto& userInfo : m_muUserInfos)
+    {
+        const auto ru = userInfo.second.ru;
+        if (auto it = orderedMap.find(ru); it != orderedMap.end())
+        {
+            it->second.emplace(userInfo.first);
+        }
+        else
+        {
+            orderedMap.emplace(userInfo.second.ru, std::set<uint16_t>{userInfo.first});
+        }
+    }
     return orderedMap;
 }
 
@@ -667,7 +795,7 @@
     std::vector<HeRu::RuType> ruTypes{};
     ruTypes.resize(ruAllocations.size());
     const auto& orderedMap = GetUserInfoMapOrderedByRus(p20Index);
-    for (const auto& [ru, staId] : orderedMap)
+    for (const auto& [ru, staIds] : orderedMap)
     {
         const auto ruType = ru.GetRuType();
         const auto ruBw = HeRu::GetBandwidth(ruType);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-tx-vector.h ns-3.40/src/wifi/model/wifi-tx-vector.h
--- ns-3.39/src/wifi/model/wifi-tx-vector.h	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-tx-vector.h	2023-09-27 13:30:37.918840000 -0700
@@ -28,6 +28,7 @@
 
 #include <list>
 #include <optional>
+#include <set>
 #include <vector>
 
 namespace ns3
@@ -248,10 +249,14 @@
      */
     uint8_t GetNss(uint16_t staId = SU_STA_ID) const;
     /**
-     * \returns the maximum number of Nss (namely if MU)
+     * \returns the maximum number of Nss over all RUs of an HE MU (used for OFDMA)
      */
     uint8_t GetNssMax() const;
     /**
+     * \returns the total number of Nss for a given RU of an HE MU (used for full bandwidth MU-MIMO)
+     */
+    uint8_t GetNssTotal() const;
+    /**
      * Sets the number of Nss
      *
      * \param nss the number of spatial streams
@@ -371,6 +376,18 @@
      */
     bool IsUlMu() const;
     /**
+     * Return true if this TX vector is used for a downlink multi-user transmission using OFDMA.
+     *
+     * \return true if this TX vector is used for a downlink multi-user transmission using OFDMA
+     */
+    bool IsDlOfdma() const;
+    /**
+     * Return true if this TX vector is used for a downlink multi-user transmission using MU-MIMO.
+     *
+     * \return true if this TX vector is used for a downlink multi-user transmission using MU-MIMO
+     */
+    bool IsDlMuMimo() const;
+    /**
      * Check if STA ID is allocated
      * \param staId STA ID
      * \return true if allocated, false otherwise
@@ -424,7 +441,7 @@
     HeMuUserInfoMap& GetHeMuUserInfoMap();
 
     /// map of specific user info parameters ordered per increasing frequency RUs
-    using UserInfoMapOrderedByRus = std::map<HeRu::RuSpec, uint16_t, HeRu::RuSpecCompare>;
+    using UserInfoMapOrderedByRus = std::map<HeRu::RuSpec, std::set<uint16_t>, HeRu::RuSpecCompare>;
 
     /**
      * Get the map of specific user info parameters ordered per increasing frequency RUs.
@@ -435,6 +452,13 @@
     UserInfoMapOrderedByRus GetUserInfoMapOrderedByRus(uint8_t p20Index) const;
 
     /**
+     * Indicate whether the Common field is present in the HE-SIG-B field.
+     *
+     * \return true if the Common field is present in the HE-SIG-B, false otherwise
+     */
+    bool IsSigBCompression() const;
+
+    /**
      * Set the 20 MHz subchannels that are punctured.
      *
      * \param inactiveSubchannels the bitmap indexed by the 20 MHz subchannels in ascending order,
@@ -523,6 +547,14 @@
      */
     Center26ToneRuIndication DeriveCenter26ToneRuIndication() const;
 
+    /**
+     * Get the number of STAs in a given RU.
+     *
+     * \param ru the RU specification
+     * \return the number of STAs in the RU
+     */
+    uint8_t GetNumStasInRu(const HeRu::RuSpec& ru) const;
+
     WifiMode m_mode;          /**< The DATARATE parameter in Table 15-4.
                               It is the value that will be passed
                               to PMD_RATE.request */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-utils.cc ns-3.40/src/wifi/model/wifi-utils.cc
--- ns-3.39/src/wifi/model/wifi-utils.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-utils.cc	2023-09-27 13:30:37.918840000 -0700
@@ -144,4 +144,37 @@
     return size;
 }
 
+bool
+TidToLinkMappingValidForNegType1(const WifiTidLinkMapping& dlLinkMapping,
+                                 const WifiTidLinkMapping& ulLinkMapping)
+{
+    if (dlLinkMapping.empty() && ulLinkMapping.empty())
+    {
+        // default mapping is valid
+        return true;
+    }
+
+    if (dlLinkMapping.size() != 8 || ulLinkMapping.size() != 8)
+    {
+        // not all TIDs have been mapped
+        return false;
+    }
+
+    const auto& linkSet = dlLinkMapping.cbegin()->second;
+
+    for (const auto& linkMapping : {std::cref(dlLinkMapping), std::cref(ulLinkMapping)})
+    {
+        for (const auto& [tid, links] : linkMapping.get())
+        {
+            if (links != linkSet)
+            {
+                // distinct link sets
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/wifi-utils.h ns-3.40/src/wifi/model/wifi-utils.h
--- ns-3.39/src/wifi/model/wifi-utils.h	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/wifi-utils.h	2023-09-27 13:30:37.918840000 -0700
@@ -22,9 +22,12 @@
 
 #include "block-ack-type.h"
 
+#include "ns3/fatal-error.h"
 #include "ns3/ptr.h"
 
 #include <list>
+#include <map>
+#include <set>
 
 namespace ns3
 {
@@ -33,6 +36,44 @@
 class Packet;
 
 /**
+ * Wifi direction. Values are those defined for the TID-to-Link Mapping Control Direction
+ * field in IEEE 802.11be D3.1 Figure 9-1002ap
+ */
+enum class WifiDirection : uint8_t
+{
+    DOWNLINK = 0,
+    UPLINK = 1,
+    BOTH_DIRECTIONS = 2,
+};
+
+/**
+ * \brief Stream insertion operator.
+ *
+ * \param os the stream
+ * \param direction the direction
+ * \returns a reference to the stream
+ */
+inline std::ostream&
+operator<<(std::ostream& os, const WifiDirection& direction)
+{
+    switch (direction)
+    {
+    case WifiDirection::DOWNLINK:
+        return (os << "DOWNLINK");
+    case WifiDirection::UPLINK:
+        return (os << "UPLINK");
+    case WifiDirection::BOTH_DIRECTIONS:
+        return (os << "BOTH_DIRECTIONS");
+    default:
+        NS_FATAL_ERROR("Invalid direction");
+        return (os << "INVALID");
+    }
+}
+
+/// @brief TID-indexed map of the link set to which the TID is mapped
+using WifiTidLinkMapping = std::map<uint8_t, std::set<uint8_t>>;
+
+/**
  * Convert from dBm to Watts.
  *
  * \param dbm the power in dBm
@@ -129,6 +170,17 @@
  */
 uint32_t GetSize(Ptr<const Packet> packet, const WifiMacHeader* hdr, bool isAmpdu);
 
+/**
+ * Check if the given TID-to-Link Mappings are valid for a negotiation type of 1. Specifically,
+ * it is checked whether all TIDs are mapped to the same set of links.
+ *
+ * \param dlLinkMapping the given TID-to-Link Mapping for Downlink
+ * \param ulLinkMapping the given TID-to-Link Mapping for Uplink
+ * \return whether the given TID-to-Link Mappings are valid for a negotiation type of 1
+ */
+bool TidToLinkMappingValidForNegType1(const WifiTidLinkMapping& dlLinkMapping,
+                                      const WifiTidLinkMapping& ulLinkMapping);
+
 /// Size of the space of sequence numbers
 static constexpr uint16_t SEQNO_SPACE_SIZE = 4096;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/model/yans-wifi-channel.cc ns-3.40/src/wifi/model/yans-wifi-channel.cc
--- ns-3.39/src/wifi/model/yans-wifi-channel.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/model/yans-wifi-channel.cc	2023-09-27 13:30:37.918840000 -0700
@@ -19,6 +19,7 @@
 
 #include "yans-wifi-channel.h"
 
+#include "wifi-net-device.h"
 #include "wifi-ppdu.h"
 #include "wifi-psdu.h"
 #include "wifi-utils.h"
@@ -31,7 +32,6 @@
 #include "ns3/propagation-delay-model.h"
 #include "ns3/propagation-loss-model.h"
 #include "ns3/simulator.h"
-#include "ns3/wifi-net-device.h"
 
 namespace ns3
 {
@@ -92,7 +92,7 @@
     NS_LOG_FUNCTION(this << sender << ppdu << txPowerDbm);
     Ptr<MobilityModel> senderMobility = sender->GetMobility();
     NS_ASSERT(senderMobility);
-    for (PhyList::const_iterator i = m_phyList.begin(); i != m_phyList.end(); i++)
+    for (auto i = m_phyList.begin(); i != m_phyList.end(); i++)
     {
         if (sender != (*i))
         {
@@ -137,7 +137,7 @@
     // 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->GetTransmissionChannelWidth();
+    uint16_t txWidth = ppdu->GetTxChannelWidth();
     if ((rxPowerDbm + phy->GetRxGain()) < phy->GetRxSensitivity() + RatioToDb(txWidth / 20.0))
     {
         NS_LOG_INFO("Received signal too weak to process: " << rxPowerDbm << " dBm");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/block-ack-test-suite.cc ns-3.40/src/wifi/test/block-ack-test-suite.cc
--- ns-3.39/src/wifi/test/block-ack-test-suite.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/test/block-ack-test-suite.cc	2023-09-27 13:30:37.922839900 -0700
@@ -1284,7 +1284,7 @@
     uint16_t aid6 = 2045;
     bool ackType6 = true;
     uint8_t tid6 = 6;
-    Mac48Address address6 = Mac48Address("00:00:00:00:00:01");
+    Mac48Address address6("00:00:00:00:00:01");
 
     blockAck.SetAid11(aid6, 5);
     blockAck.SetAckType(ackType6, 5);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/channel-access-manager-test.cc ns-3.40/src/wifi/test/channel-access-manager-test.cc
--- ns-3.39/src/wifi/test/channel-access-manager-test.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/test/channel-access-manager-test.cc	2023-09-27 13:30:37.922839900 -0700
@@ -650,7 +650,7 @@
 {
     Simulator::Run();
 
-    for (typename TxopTests::const_iterator i = m_txop.begin(); i != m_txop.end(); i++)
+    for (auto i = m_txop.begin(); i != m_txop.end(); i++)
     {
         Ptr<TxopTest<TxopType>> state = *i;
         NS_TEST_EXPECT_MSG_EQ(state->m_expectedGrants.empty(), true, "Have no expected grants");
@@ -836,6 +836,7 @@
     Simulator::Schedule(MicroSeconds(at) - Now(),
                         &ChannelAccessManager::NotifySwitchingStartNow,
                         m_ChannelAccessManager,
+                        nullptr,
                         MicroSeconds(duration));
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/spectrum-wifi-phy-test.cc ns-3.40/src/wifi/test/spectrum-wifi-phy-test.cc
--- ns-3.39/src/wifi/test/spectrum-wifi-phy-test.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/test/spectrum-wifi-phy-test.cc	2023-09-27 13:30:37.922839900 -0700
@@ -26,6 +26,7 @@
 #include "ns3/pointer.h"
 #include "ns3/spectrum-wifi-helper.h"
 #include "ns3/spectrum-wifi-phy.h"
+#include "ns3/string.h"
 #include "ns3/test.h"
 #include "ns3/wifi-mac-header.h"
 #include "ns3/wifi-net-device.h"
@@ -57,54 +58,6 @@
   public:
     using SpectrumWifiPhy::SpectrumWifiPhy;
     using WifiPhy::GetBand;
-
-    /**
-     * Get the spectrum PHY interfaces
-     *
-     * \return the spectrum PHY interfaces
-     */
-    const std::map<FrequencyRange, Ptr<WifiSpectrumPhyInterface>>& GetSpectrumPhyInterfaces() const
-    {
-        return m_spectrumPhyInterfaces;
-    }
-
-    /**
-     * \return the current spectrum PHY interface
-     */
-    Ptr<WifiSpectrumPhyInterface> GetCurrentSpectrumPhyInterface() const
-    {
-        return m_currentSpectrumPhyInterface;
-    }
-
-    /**
-     * Get the info of a given band for a given spectrum PHY interface
-     *
-     * \param bandWidth the width of the band to be returned (MHz)
-     * \param bandIndex the index of the band to be returned
-     * \param freqRange the frequency range identifying the spectrum PHY interface
-     * \param channelWidth the channel width currently used by the spectrum PHY interface
-     *
-     * \return the info that defines the band
-     */
-    WifiSpectrumBandInfo GetBandForInterface(uint16_t bandWidth,
-                                             uint8_t bandIndex,
-                                             const FrequencyRange& freqRange,
-                                             uint16_t channelWidth)
-    {
-        auto subcarrierSpacing = GetSubcarrierSpacing();
-        auto numBandsInChannel = static_cast<size_t>(channelWidth * 1e6 / subcarrierSpacing);
-        auto numBandsInBand = static_cast<size_t>(bandWidth * 1e6 / subcarrierSpacing);
-        auto rxSpectrumModel = m_spectrumPhyInterfaces.at(freqRange)->GetRxSpectrumModel();
-        size_t totalNumBands = rxSpectrumModel->GetNumBands();
-        auto startIndex = ((totalNumBands - numBandsInChannel) / 2) + (bandIndex * numBandsInBand);
-        auto stopIndex = startIndex + numBandsInBand - 1;
-        auto startGuardBand = rxSpectrumModel->Begin();
-        auto startChannel = startGuardBand + startIndex;
-        auto endChannel = startGuardBand + stopIndex + 1;
-        auto lowFreq = static_cast<uint64_t>(startChannel->fc);
-        auto highFreq = static_cast<uint64_t>(endChannel->fc);
-        return {{startIndex, stopIndex}, {lowFreq, highFreq}};
-    }
 };
 
 /**
@@ -213,7 +166,6 @@
     txParams->txPhy = nullptr;
     txParams->duration = txDuration;
     txParams->ppdu = ppdu;
-    txParams->txWidth = CHANNEL_WIDTH;
 
     return txParams;
 }
@@ -717,7 +669,7 @@
         {
             for (unsigned int type = 0; type < 7; type++)
             {
-                HeRu::RuType ruType = static_cast<HeRu::RuType>(type);
+                auto ruType = static_cast<HeRu::RuType>(type);
                 for (std::size_t index = 1; index <= HeRu::GetNRus(bw, ruType); index++)
                 {
                     HeRu::SubcarrierGroup subcarrierGroup =
@@ -886,24 +838,22 @@
      * 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
-     * \param channelWidth the channel width for which the check has to be executed
+     * \param band the band for which the check has to be executed
      * \param interferencesExpected flag whether interferences are expected to have been tracked
      */
-    void CheckInterferences(Ptr<ExtSpectrumWifiPhy> phy,
+    void CheckInterferences(Ptr<SpectrumWifiPhy> phy,
                             const FrequencyRange& freqRange,
-                            uint16_t channelWidth,
+                            const WifiSpectrumBandInfo& band,
                             bool interferencesExpected);
 
     /**
      * 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
-     * \param channelWidth the channel width for which the check has to be executed
+     * \param band the band for which the check has to be executed
      * \param interferencesExpected flag whether interferences are expected to have been tracked
      */
-    void DoCheckInterferences(Ptr<ExtSpectrumWifiPhy> phy,
-                              const FrequencyRange& freqRange,
-                              uint16_t channelWidth,
+    void DoCheckInterferences(Ptr<SpectrumWifiPhy> phy,
+                              const WifiSpectrumBandInfo& band,
                               bool interferencesExpected);
 
     /**
@@ -936,17 +886,14 @@
      */
     void Reset();
 
-    /// typedef for spectrum channel infos
-    using SpectrumChannelInfos = std::tuple<Ptr<MultiModelSpectrumChannel>, uint16_t, uint16_t>;
-
     bool
         m_trackSignalsInactiveInterfaces; //!< flag to indicate whether signals coming from inactive
                                           //!< spectrum PHY interfaces are tracked during the test
 
-    std::vector<SpectrumChannelInfos> m_spectrumChannelInfos;    //!< Spectrum channels infos
-    std::vector<Ptr<ExtSpectrumWifiPhy>> m_txPhys{};             //!< TX PHYs
-    std::vector<Ptr<ExtSpectrumWifiPhy>> m_rxPhys{};             //!< RX PHYs
-    std::vector<std::unique_ptr<TestPhyListener>> m_listeners{}; //!< listeners
+    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::unique_ptr<TestPhyListener>> m_listeners{};    //!< listeners
 
     std::vector<uint32_t> m_counts{0}; //!< count number of packets received by PHYs
 
@@ -1013,9 +960,9 @@
 }
 
 void
-SpectrumWifiPhyMultipleInterfacesTest::CheckInterferences(Ptr<ExtSpectrumWifiPhy> phy,
+SpectrumWifiPhyMultipleInterfacesTest::CheckInterferences(Ptr<SpectrumWifiPhy> phy,
                                                           const FrequencyRange& freqRange,
-                                                          uint16_t channelWidth,
+                                                          const WifiSpectrumBandInfo& band,
                                                           bool interferencesExpected)
 {
     if ((!m_trackSignalsInactiveInterfaces) && (phy->GetCurrentFrequencyRange() != freqRange))
@@ -1028,23 +975,20 @@
     Simulator::ScheduleNow(&SpectrumWifiPhyMultipleInterfacesTest::DoCheckInterferences,
                            this,
                            phy,
-                           freqRange,
-                           channelWidth,
+                           band,
                            interferencesExpected);
 }
 
 void
-SpectrumWifiPhyMultipleInterfacesTest::DoCheckInterferences(Ptr<ExtSpectrumWifiPhy> phy,
-                                                            const FrequencyRange& freqRange,
-                                                            uint16_t channelWidth,
+SpectrumWifiPhyMultipleInterfacesTest::DoCheckInterferences(Ptr<SpectrumWifiPhy> phy,
+                                                            const WifiSpectrumBandInfo& band,
                                                             bool interferencesExpected)
 {
-    NS_LOG_FUNCTION(this << phy << freqRange << interferencesExpected);
+    NS_LOG_FUNCTION(this << phy << band << interferencesExpected);
     PointerValue ptr;
     phy->GetAttribute("InterferenceHelper", ptr);
     auto interferenceHelper = DynamicCast<InterferenceHelper>(ptr.Get<InterferenceHelper>());
     NS_ASSERT(interferenceHelper);
-    const auto band = phy->GetBandForInterface(channelWidth, 0, freqRange, channelWidth);
     const auto energyDuration = interferenceHelper->GetEnergyDuration(0, band);
     NS_TEST_ASSERT_MSG_EQ(energyDuration.IsStrictlyPositive(),
                           interferencesExpected,
@@ -1064,7 +1008,7 @@
     for (const auto& [freqRange, interface] : phy->GetSpectrumPhyInterfaces())
     {
         const auto expectedActive = (freqRange == expectedFrequencyRangeActiveRfInterface);
-        const auto isActive = (interface == phy->GetCurrentSpectrumPhyInterface());
+        const auto isActive = (interface == phy->GetCurrentInterface());
         NS_TEST_ASSERT_MSG_EQ(isActive, expectedActive, "Incorrect active interface");
         if (isActive)
         {
@@ -1072,11 +1016,10 @@
         }
     }
     NS_TEST_ASSERT_MSG_EQ(numActiveInterfaces, 1, "There should always be one active interface");
-    NS_ASSERT(expectedConnectedPhysPerChannel.size() == m_spectrumChannelInfos.size());
-    for (std::size_t i = 0; i < m_spectrumChannelInfos.size(); ++i)
+    NS_ASSERT(expectedConnectedPhysPerChannel.size() == m_spectrumChannels.size());
+    for (std::size_t i = 0; i < m_spectrumChannels.size(); ++i)
     {
-        const auto spectrumChannel = std::get<0>(m_spectrumChannelInfos.at(i));
-        NS_TEST_ASSERT_MSG_EQ(spectrumChannel->GetNDevices(),
+        NS_TEST_ASSERT_MSG_EQ(m_spectrumChannels.at(i)->GetNDevices(),
                               expectedConnectedPhysPerChannel.at(i),
                               "Incorrect number of PHYs attached to the spectrum channel");
     }
@@ -1140,77 +1083,75 @@
     // WifiHelper::EnableLogComponents();
     // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
 
-    const std::vector<std::pair<WifiPhyBand, uint8_t>> channels{{WIFI_PHY_BAND_2_4GHZ, 2},
-                                                                {WIFI_PHY_BAND_5GHZ, 42},
-                                                                {WIFI_PHY_BAND_5GHZ, 114},
-                                                                {WIFI_PHY_BAND_6GHZ, 215}};
+    NodeContainer wifiApNode(1);
+    NodeContainer wifiStaNode(1);
 
-    // create spectrum channels
-    for (std::size_t i = 0; i < channels.size(); ++i)
+    WifiHelper wifi;
+    wifi.SetStandard(WIFI_STANDARD_80211be);
+
+    SpectrumWifiPhyHelper phyHelper(4);
+    phyHelper.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
+
+    struct SpectrumPhyInterfaceInfo
+    {
+        FrequencyRange range; ///< frequency range covered by the interface
+        uint8_t number;       ///< channel number the interface operates on
+        WifiPhyBand band;     ///< PHY band the interface operates on
+        std::string bandName; ///< name of the PHY band the interface operates on
+    };
+
+    const FrequencyRange WIFI_SPECTRUM_5_GHZ_LOW{
+        WIFI_SPECTRUM_5_GHZ.minFrequency,
+        WIFI_SPECTRUM_5_GHZ.minFrequency +
+            ((WIFI_SPECTRUM_5_GHZ.maxFrequency - WIFI_SPECTRUM_5_GHZ.minFrequency) / 2)};
+    const FrequencyRange WIFI_SPECTRUM_5_GHZ_HIGH{
+        WIFI_SPECTRUM_5_GHZ.minFrequency +
+            ((WIFI_SPECTRUM_5_GHZ.maxFrequency - WIFI_SPECTRUM_5_GHZ.minFrequency) / 2),
+        WIFI_SPECTRUM_5_GHZ.maxFrequency};
+
+    const std::vector<SpectrumPhyInterfaceInfo> interfaces{
+        {WIFI_SPECTRUM_2_4_GHZ, 2, WIFI_PHY_BAND_2_4GHZ, "BAND_2_4GHZ"},
+        {WIFI_SPECTRUM_5_GHZ_LOW, 42, WIFI_PHY_BAND_5GHZ, "BAND_5GHZ"},
+        {WIFI_SPECTRUM_5_GHZ_HIGH, 163, WIFI_PHY_BAND_5GHZ, "BAND_5GHZ"},
+        {WIFI_SPECTRUM_6_GHZ, 215, WIFI_PHY_BAND_6GHZ, "BAND_6GHZ"}};
+
+    for (std::size_t i = 0; i < interfaces.size(); ++i)
     {
         auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
         [[maybe_unused]] const auto [channel, frequency, channelWidth, type, band] =
-            (*WifiPhyOperatingChannel::FindFirst(channels.at(i).second,
+            (*WifiPhyOperatingChannel::FindFirst(interfaces.at(i).number,
                                                  0,
                                                  0,
-                                                 WIFI_STANDARD_80211ax,
-                                                 channels.at(i).first));
+                                                 WIFI_STANDARD_80211be,
+                                                 interfaces.at(i).band));
 
-        m_spectrumChannelInfos.emplace_back(spectrumChannel, frequency, channelWidth);
+        std::ostringstream oss;
+        oss << "{" << +interfaces.at(i).number << ", 0, " << interfaces.at(i).bandName << ", 0}";
+        phyHelper.Set(i, "ChannelSettings", StringValue(oss.str()));
+        phyHelper.AddChannel(spectrumChannel, interfaces.at(i).range);
+
+        m_spectrumChannels.emplace_back(spectrumChannel);
     }
 
-    // create PHYs and add all channels to each of them
-    for (std::size_t i = 0; i < channels.size(); ++i)
-    {
-        auto txNode = CreateObject<Node>();
-        auto txDev = CreateObject<WifiNetDevice>();
-        auto txPhy = CreateObject<ExtSpectrumWifiPhy>();
-        txPhy->SetAttribute("ChannelSwitchDelay", TimeValue(Seconds(0)));
-        txPhy->SetAttribute("TrackSignalsFromInactiveInterfaces",
-                            BooleanValue(m_trackSignalsInactiveInterfaces));
-        auto txInterferenceHelper = CreateObject<InterferenceHelper>();
-        txPhy->SetInterferenceHelper(txInterferenceHelper);
-        auto txError = CreateObject<NistErrorRateModel>();
-        txPhy->SetErrorRateModel(txError);
-        txPhy->SetDevice(txDev);
-        for (const auto& [spectrumChannel, freq, width] : m_spectrumChannelInfos)
-        {
-            const uint16_t minFreq = freq - width / 2;
-            const uint16_t maxFreq = freq + width / 2;
-            txPhy->AddChannel(spectrumChannel, {minFreq, maxFreq});
-        }
-        txPhy->SetOperatingChannel(
-            WifiPhy::ChannelTuple{channels.at(i).second, 0, channels.at(i).first, 0});
-        txPhy->ConfigureStandard(WIFI_STANDARD_80211ax);
-        txDev->SetPhy(txPhy);
-        txNode->AddDevice(txDev);
+    WifiMacHelper mac;
+    mac.SetType("ns3::ApWifiMac", "BeaconGeneration", BooleanValue(false));
+    phyHelper.Set("TrackSignalsFromInactiveInterfaces", BooleanValue(false));
+    auto apDevice = wifi.Install(phyHelper, mac, wifiApNode.Get(0));
 
-        m_txPhys.push_back(txPhy);
+    mac.SetType("ns3::StaWifiMac", "ActiveProbing", BooleanValue(false));
+    phyHelper.Set("TrackSignalsFromInactiveInterfaces",
+                  BooleanValue(m_trackSignalsInactiveInterfaces));
+    auto staDevice = wifi.Install(phyHelper, mac, wifiStaNode.Get(0));
 
-        auto rxNode = CreateObject<Node>();
-        auto rxDev = CreateObject<WifiNetDevice>();
-        auto rxPhy = CreateObject<ExtSpectrumWifiPhy>();
-        rxPhy->SetAttribute("ChannelSwitchDelay", TimeValue(Seconds(0)));
-        rxPhy->SetAttribute("TrackSignalsFromInactiveInterfaces",
-                            BooleanValue(m_trackSignalsInactiveInterfaces));
-        auto rxInterferenceHelper = CreateObject<InterferenceHelper>();
-        rxPhy->SetInterferenceHelper(rxInterferenceHelper);
-        auto rxError = CreateObject<NistErrorRateModel>();
-        rxPhy->SetErrorRateModel(rxError);
-        rxPhy->SetDevice(rxDev);
-        for (const auto& [spectrumChannel, freq, width] : m_spectrumChannelInfos)
-        {
-            const uint16_t minFreq = freq - width / 2;
-            const uint16_t maxFreq = freq + width / 2;
-            rxPhy->AddChannel(spectrumChannel, {minFreq, maxFreq});
-        }
-        rxPhy->SetOperatingChannel(
-            WifiPhy::ChannelTuple{channels.at(i).second, 0, channels.at(i).first, 0});
-        rxPhy->ConfigureStandard(WIFI_STANDARD_80211ax);
-        rxDev->SetPhy(rxPhy);
-        rxNode->AddDevice(rxDev);
+    for (std::size_t i = 0; i < interfaces.size(); ++i)
+    {
+        auto txPhy =
+            DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(apDevice.Get(0))->GetPhy(i));
+        m_txPhys.push_back(txPhy);
 
         const auto index = m_rxPhys.size();
+        auto rxPhy =
+            DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(staDevice.Get(0))->GetPhy(i));
         rxPhy->TraceConnectWithoutContext(
             "PhyRxBegin",
             MakeCallback(&SpectrumWifiPhyMultipleInterfacesTest::RxCallback, this).Bind(index));
@@ -1259,29 +1200,6 @@
                           ///< in time the transmission is ongoing
 
     Time delay{0};
-    // make sure all interfaces got active once for all RX PHYs to have them monitored
-    for (std::size_t rxPhyIndex = 0; rxPhyIndex < m_rxPhys.size(); ++rxPhyIndex)
-    {
-        for (std::size_t txPhyIndex = 0; txPhyIndex < m_txPhys.size(); ++txPhyIndex)
-        {
-            if (txPhyIndex == rxPhyIndex)
-            {
-                // handled at end
-                continue;
-            }
-            auto txPhy = m_txPhys.at(txPhyIndex);
-            Simulator::Schedule(delay + Seconds((rxPhyIndex + rxPhyIndex) * 0.1),
-                                &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
-                                this,
-                                rxPhyIndex,
-                                txPhy->GetPhyBand(),
-                                txPhy->GetChannelNumber(),
-                                txPhy->GetChannelWidth());
-        }
-        Simulator::Schedule(delay + flushResultsDelay,
-                            &SpectrumWifiPhyMultipleInterfacesTest::Reset,
-                            this);
-    }
 
     // default channels active for all PHYs: each PHY only receives from its associated TX
     std::vector<std::size_t> expectedConnectedPhysPerChannel =
@@ -1303,15 +1221,13 @@
         {
             auto txPhy = m_txPhys.at(j);
             auto rxPhy = m_rxPhys.at(j);
-            const uint16_t minExpectedFreq = txPhy->GetFrequency() - (txPhy->GetChannelWidth() / 2);
-            const uint16_t maxExpectedFreq = txPhy->GetFrequency() + (txPhy->GetChannelWidth() / 2);
-            const FrequencyRange expectedFreqRange = {minExpectedFreq, maxExpectedFreq};
+            const auto& expectedFreqRange = txPhy->GetCurrentFrequencyRange();
             Simulator::Schedule(delay + txOngoingAfterTxStartedDelay,
                                 &SpectrumWifiPhyMultipleInterfacesTest::CheckInterferences,
                                 this,
                                 rxPhy,
                                 txPpduPhy->GetCurrentFrequencyRange(),
-                                txPpduPhy->GetChannelWidth(),
+                                txPpduPhy->GetBand(txPpduPhy->GetChannelWidth(), 0),
                                 true);
             Simulator::Schedule(delay + checkResultsDelay,
                                 &SpectrumWifiPhyMultipleInterfacesTest::CheckResults,
@@ -1320,10 +1236,10 @@
                                 (i == j) ? 1 : 0,
                                 expectedFreqRange,
                                 expectedConnectedPhysPerChannel);
-            Simulator::Schedule(delay + flushResultsDelay,
-                                &SpectrumWifiPhyMultipleInterfacesTest::Reset,
-                                this);
         }
+        Simulator::Schedule(delay + flushResultsDelay,
+                            &SpectrumWifiPhyMultipleInterfacesTest::Reset,
+                            this);
     }
 
     // same channel active for all PHYs: all PHYs receive from TX
@@ -1336,11 +1252,7 @@
                             this,
                             txPpduPhy,
                             0);
-        const uint16_t minExpectedFreq =
-            txPpduPhy->GetFrequency() - (txPpduPhy->GetChannelWidth() / 2);
-        const uint16_t maxExpectedFreq =
-            txPpduPhy->GetFrequency() + (txPpduPhy->GetChannelWidth() / 2);
-        const FrequencyRange expectedFreqRange = {minExpectedFreq, maxExpectedFreq};
+        const auto& expectedFreqRange = txPpduPhy->GetCurrentFrequencyRange();
         for (std::size_t j = 0; j < 4; ++j)
         {
             if (!m_trackSignalsInactiveInterfaces)
@@ -1363,7 +1275,7 @@
                                 this,
                                 rxPhy,
                                 txPpduPhy->GetCurrentFrequencyRange(),
-                                txPpduPhy->GetChannelWidth(),
+                                txPpduPhy->GetBand(txPpduPhy->GetChannelWidth(), 0),
                                 true);
             Simulator::Schedule(delay + checkResultsDelay,
                                 &SpectrumWifiPhyMultipleInterfacesTest::CheckResults,
@@ -1372,21 +1284,17 @@
                                 1,
                                 expectedFreqRange,
                                 expectedConnectedPhysPerChannel);
-            Simulator::Schedule(delay + flushResultsDelay,
-                                &SpectrumWifiPhyMultipleInterfacesTest::Reset,
-                                this);
         }
+        Simulator::Schedule(delay + flushResultsDelay,
+                            &SpectrumWifiPhyMultipleInterfacesTest::Reset,
+                            this);
     }
 
     // Switch all PHYs to channel 36: all PHYs switch to the second spectrum channel
     // since second spectrum channel is 42 (80 MHz) and hence covers channel 36 (20 MHz)
     const auto secondSpectrumChannelIndex = 1;
     auto channel36TxPhy = m_txPhys.at(secondSpectrumChannelIndex);
-    const uint16_t minExpectedFreq =
-        channel36TxPhy->GetFrequency() - (channel36TxPhy->GetChannelWidth() / 2);
-    const uint16_t maxExpectedFreq =
-        channel36TxPhy->GetFrequency() + (channel36TxPhy->GetChannelWidth() / 2);
-    FrequencyRange expectedFreqRange = {minExpectedFreq, maxExpectedFreq};
+    const auto& expectedFreqRange = channel36TxPhy->GetCurrentFrequencyRange();
     for (std::size_t i = 0; i < 4; ++i)
     {
         delay += Seconds(1);
@@ -1420,10 +1328,10 @@
                                 (i == secondSpectrumChannelIndex) ? 1 : 0,
                                 expectedFreqRange,
                                 expectedConnectedPhysPerChannel);
-            Simulator::Schedule(delay + flushResultsDelay,
-                                &SpectrumWifiPhyMultipleInterfacesTest::Reset,
-                                this);
         }
+        Simulator::Schedule(delay + flushResultsDelay,
+                            &SpectrumWifiPhyMultipleInterfacesTest::Reset,
+                            this);
     }
 
     // verify CCA indication when switching to a channel with an ongoing transmission
@@ -1464,9 +1372,6 @@
                                         channelWidth);
                     for (std::size_t k = 0; k < 4; ++k)
                     {
-                        Simulator::Schedule(delay + flushResultsDelay,
-                                            &SpectrumWifiPhyMultipleInterfacesTest::Reset,
-                                            this);
                         if ((i != j) && (k == i))
                         {
                             continue;
@@ -1484,11 +1389,15 @@
                             expectCcaBusyIndication,
                             txOngoingAfterTxStartedDelay);
                     }
+                    Simulator::Schedule(delay + flushResultsDelay,
+                                        &SpectrumWifiPhyMultipleInterfacesTest::Reset,
+                                        this);
                 }
             }
         }
     }
 
+    Simulator::Stop(Seconds(30));
     Simulator::Run();
 }
 
@@ -1496,6 +1405,195 @@
  * \ingroup wifi-test
  * \ingroup tests
  *
+ * \brief Spectrum Wifi Phy Interfaces Helper Test
+ *
+ * This test checks the expected interfaces are added to the spectrum PHY instances
+ * created by the helper.
+ */
+class SpectrumWifiPhyInterfacesHelperTest : public TestCase
+{
+  public:
+    SpectrumWifiPhyInterfacesHelperTest();
+    ~SpectrumWifiPhyInterfacesHelperTest() override = default;
+
+  private:
+    void DoRun() override;
+};
+
+SpectrumWifiPhyInterfacesHelperTest::SpectrumWifiPhyInterfacesHelperTest()
+    : TestCase("Check PHY interfaces added to PHY instances using helper")
+{
+}
+
+void
+SpectrumWifiPhyInterfacesHelperTest::DoRun()
+{
+    WifiHelper wifiHelper;
+    wifiHelper.SetStandard(WIFI_STANDARD_80211be);
+
+    SpectrumWifiPhyHelper phyHelper(3);
+    phyHelper.Set(0, "ChannelSettings", StringValue("{2, 0, BAND_2_4GHZ, 0}"));
+    phyHelper.Set(1, "ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
+    phyHelper.Set(2, "ChannelSettings", StringValue("{1, 0, BAND_6GHZ, 0}"));
+
+    phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_2_4_GHZ);
+    phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_5_GHZ);
+    phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_6_GHZ);
+
+    WifiMacHelper macHelper;
+    NodeContainer nodes(4);
+
+    /* Default case: all interfaces are added to each link */
+    auto device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(0));
+
+    // Verify each PHY has 3 interfaces
+    auto phyLink0 =
+        DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
+    NS_ASSERT(phyLink0);
+    NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
+                          3,
+                          "Incorrect number of PHY interfaces added to PHY link ID 0");
+
+    auto phyLink1 =
+        DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
+    NS_ASSERT(phyLink1);
+    NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
+                          3,
+                          "Incorrect number of PHY interfaces added to PHY link ID 1");
+
+    auto phyLink2 =
+        DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
+    NS_ASSERT(phyLink2);
+    NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
+                          3,
+                          "Incorrect number of PHY interfaces added to PHY link ID 2");
+
+    /* each PHY has a single interface */
+    phyHelper.AddPhyToFreqRangeMapping(0, WIFI_SPECTRUM_2_4_GHZ);
+    phyHelper.AddPhyToFreqRangeMapping(1, WIFI_SPECTRUM_5_GHZ);
+    phyHelper.AddPhyToFreqRangeMapping(2, WIFI_SPECTRUM_6_GHZ);
+    device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(1));
+
+    // Verify each PHY has a single interface
+    phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
+    NS_ASSERT(phyLink0);
+    NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
+                          1,
+                          "Incorrect number of PHY interfaces added to PHY link ID 0");
+    NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+
+    phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
+    NS_ASSERT(phyLink1);
+    NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
+                          1,
+                          "Incorrect number of PHY interfaces added to PHY link ID 1");
+    NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 1");
+
+    phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
+    NS_ASSERT(phyLink2);
+    NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
+                          1,
+                          "Incorrect number of PHY interfaces added to PHY link ID 2");
+    NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 2");
+
+    /* add yet another interface to PHY 0 */
+    phyHelper.AddPhyToFreqRangeMapping(0, WIFI_SPECTRUM_5_GHZ);
+    device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(2));
+
+    // Verify each PHY has a single interface except PHY 0 that should have 2 interfaces
+    phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
+    NS_ASSERT(phyLink0);
+    NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
+                          2,
+                          "Incorrect number of PHY interfaces added to PHY link ID 0");
+    NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+    NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+
+    phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
+    NS_ASSERT(phyLink1);
+    NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
+                          1,
+                          "Incorrect number of PHY interfaces added to PHY link ID 1");
+    NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 1");
+
+    phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
+    NS_ASSERT(phyLink2);
+    NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
+                          1,
+                          "Incorrect number of PHY interfaces added to PHY link ID 2");
+    NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 2");
+
+    /* reset mapping previously configured to helper: back to default */
+    phyHelper.ResetPhyToFreqRangeMapping();
+    device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(3));
+
+    // Verify each PHY has 3 interfaces
+    phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
+    NS_ASSERT(phyLink0);
+    NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
+                          3,
+                          "Incorrect number of PHY interfaces added to PHY link ID 0");
+    NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+    NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+    NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+
+    phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
+    NS_ASSERT(phyLink1);
+    NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
+                          3,
+                          "Incorrect number of PHY interfaces added to PHY link ID 1");
+    NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+    NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+    NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+
+    phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
+    NS_ASSERT(phyLink2);
+    NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
+                          3,
+                          "Incorrect number of PHY interfaces added to PHY link ID 2");
+    NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+    NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+    NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
+                          1,
+                          "Incorrect PHY interfaces added to PHY link ID 0");
+
+    Simulator::Destroy();
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
  * \brief Spectrum Wifi Phy Test Suite
  */
 class SpectrumWifiPhyTestSuite : public TestSuite
@@ -1512,6 +1610,7 @@
     AddTestCase(new SpectrumWifiPhyFilterTest, TestCase::QUICK);
     AddTestCase(new SpectrumWifiPhyMultipleInterfacesTest(false), TestCase::QUICK);
     AddTestCase(new SpectrumWifiPhyMultipleInterfacesTest(true), TestCase::QUICK);
+    AddTestCase(new SpectrumWifiPhyInterfacesHelperTest, TestCase::QUICK);
 }
 
 static SpectrumWifiPhyTestSuite spectrumWifiPhyTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/tx-duration-test.cc ns-3.40/src/wifi/test/tx-duration-test.cc
--- ns-3.39/src/wifi/test/tx-duration-test.cc	2023-07-05 14:23:48.125428400 -0700
+++ ns-3.40/src/wifi/test/tx-duration-test.cc	2023-09-27 13:30:37.922839900 -0700
@@ -30,11 +30,12 @@
 #include "ns3/wifi-psdu.h"
 #include "ns3/yans-wifi-phy.h"
 
+#include <list>
 #include <numeric>
 
 using namespace ns3;
 
-NS_LOG_COMPONENT_DEFINE("InterferenceHelperTxDurationTest");
+NS_LOG_COMPONENT_DEFINE("TxDurationTest");
 
 /**
  * \ingroup wifi-test
@@ -153,7 +154,7 @@
     txVector.SetChannelWidth(channelWidth);
     txVector.SetGuardInterval(guardInterval);
     txVector.SetNss(1);
-    txVector.SetStbc(0);
+    txVector.SetStbc(false);
     txVector.SetNess(0);
     std::list<WifiPhyBand> testedBands;
     Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy>();
@@ -205,7 +206,7 @@
     txVector.SetChannelWidth(channelWidth);
     txVector.SetGuardInterval(guardInterval);
     txVector.SetNss(1);
-    txVector.SetStbc(0);
+    txVector.SetStbc(false);
     txVector.SetNess(0);
     std::list<WifiPhyBand> testedBands;
     Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy>();
@@ -273,7 +274,7 @@
     txVector.SetPreambleType(preamble);
     txVector.SetChannelWidth(channelWidth);
     txVector.SetGuardInterval(guardInterval);
-    txVector.SetStbc(0);
+    txVector.SetStbc(false);
     txVector.SetNess(0);
     if (IsEht(preamble))
     {
@@ -1304,11 +1305,21 @@
 {
   public:
     /**
+     * OFDMA or MU-MIMO
+     */
+    enum MuType
+    {
+        OFDMA = 0,
+        MU_MIMO
+    };
+
+    /**
      * Constructor
      *
      * \param userInfos the HE MU specific per-user information to use for the test
      * \param sigBMode the mode to transmit HE-SIG-B for the test
      * \param channelWidth the channel width in MHz to select for the test
+     * \param expectedMuType the expected MU type (OFDMA or MU-MIMO)
      * \param expectedRuAllocation the expected RU_ALLOCATION
      * \param expectedNumUsersPerCc the expected number of users per content channel
      * \param expectedSigBDuration the expected duration of the HE-SIG-B header
@@ -1316,6 +1327,7 @@
     HeSigBDurationTest(const std::list<HeMuUserInfo>& userInfos,
                        const WifiMode& sigBMode,
                        uint16_t channelWidth,
+                       MuType expectedMuType,
                        const RuAllocation& expectedRuAllocation,
                        const std::pair<std::size_t, std::size_t>& expectedNumUsersPerCc,
                        Time expectedSigBDuration);
@@ -1333,6 +1345,7 @@
     std::list<HeMuUserInfo> m_userInfos; ///< HE MU specific per-user information
     WifiMode m_sigBMode;                 ///< Mode used to transmit HE-SIG-B
     uint16_t m_channelWidth;             ///< Channel width in MHz
+    MuType m_expectedMuType;             ///< Expected MU type (OFDMA or MU-MIMO)
     RuAllocation m_expectedRuAllocation; ///< Expected RU_ALLOCATION
     std::pair<std::size_t, std::size_t>
         m_expectedNumUsersPerCc; ///< Expected number of users per content channel
@@ -1343,6 +1356,7 @@
     const std::list<HeMuUserInfo>& userInfos,
     const WifiMode& sigBMode,
     uint16_t channelWidth,
+    MuType expectedMuType,
     const RuAllocation& expectedRuAllocation,
     const std::pair<std::size_t, std::size_t>& expectedNumUsersPerCc,
     Time expectedSigBDuration)
@@ -1350,6 +1364,7 @@
       m_userInfos{userInfos},
       m_sigBMode{sigBMode},
       m_channelWidth{channelWidth},
+      m_expectedMuType{expectedMuType},
       m_expectedRuAllocation{expectedRuAllocation},
       m_expectedNumUsersPerCc{expectedNumUsersPerCc},
       m_expectedSigBDuration{expectedSigBDuration}
@@ -1363,7 +1378,7 @@
     txVector.SetPreambleType(WIFI_PREAMBLE_HE_MU);
     txVector.SetChannelWidth(m_channelWidth);
     txVector.SetGuardInterval(3200);
-    txVector.SetStbc(0);
+    txVector.SetStbc(false);
     txVector.SetNess(0);
     std::list<uint16_t> staIds;
     uint16_t staId = 1;
@@ -1373,6 +1388,7 @@
         staIds.push_back(staId++);
     }
     txVector.SetSigBMode(m_sigBMode);
+    NS_ASSERT(m_expectedMuType == OFDMA ? txVector.IsDlOfdma() : txVector.IsDlMuMimo());
     return txVector;
 }
 
@@ -1393,9 +1409,11 @@
                           "Incorrect RU_ALLOCATION");
 
     // Verify number of users for content channels 1 and 2
-    const auto& numUsersPerCc =
-        HePpdu::GetNumRusPerHeSigBContentChannel(txVector.GetChannelWidth(),
-                                                 txVector.GetRuAllocation(0));
+    const auto& numUsersPerCc = HePpdu::GetNumRusPerHeSigBContentChannel(
+        txVector.GetChannelWidth(),
+        txVector.GetRuAllocation(0),
+        txVector.IsSigBCompression(),
+        txVector.IsSigBCompression() ? txVector.GetHeMuUserInfoMap().size() : 0);
     const auto contentChannels = HePpdu::GetHeSigBContentChannels(txVector, 0);
     NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
                           m_expectedNumUsersPerCc.first,
@@ -1788,17 +1806,18 @@
 
     AddTestCase(new PhyHeaderSectionsTest, TestCase::QUICK);
 
-    // 20 MHz band, even number of users per HE-SIG-B content channel
+    // 20 MHz band, HeSigBDurationTest::OFDMA, even number of users per HE-SIG-B content channel
     AddTestCase(new HeSigBDurationTest(
                     {{{HeRu::RU_106_TONE, 1, true}, 11, 1}, {{HeRu::RU_106_TONE, 2, true}, 10, 4}},
                     VhtPhy::GetVhtMcs5(),
                     20,
+                    HeSigBDurationTest::OFDMA,
                     {96},
                     std::make_pair(2, 0), // both users in HE-SIG-B content channel 1
                     MicroSeconds(4)),     // one OFDM symbol;
                 TestCase::QUICK);
 
-    // 40 MHz band, even number of users per HE-SIG-B content channel
+    // 40 MHz band, HeSigBDurationTest::OFDMA, even number of users per HE-SIG-B content channel
     AddTestCase(
         new HeSigBDurationTest({{{HeRu::RU_106_TONE, 1, true}, 11, 1},
                                 {{HeRu::RU_106_TONE, 2, true}, 10, 4},
@@ -1808,13 +1827,14 @@
                                 {{HeRu::RU_52_TONE, 8, true}, 6, 2}},
                                VhtPhy::GetVhtMcs4(),
                                40,
+                               HeSigBDurationTest::OFDMA,
                                {96, 112},
                                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);
 
-    // 40 MHz band, odd number of users per HE-SIG-B content channel
+    // 40 MHz band, HeSigBDurationTest::OFDMA, odd number of users per HE-SIG-B content channel
     AddTestCase(
         new HeSigBDurationTest({{{HeRu::RU_106_TONE, 1, true}, 11, 1},
                                 {{HeRu::RU_106_TONE, 2, true}, 10, 4},
@@ -1825,13 +1845,14 @@
                                 {{HeRu::RU_26_TONE, 14, true}, 3, 1}},
                                VhtPhy::GetVhtMcs3(),
                                40,
+                               HeSigBDurationTest::OFDMA,
                                {96, 15},
                                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);
 
-    // 80 MHz band
+    // 80 MHz band, OFDMA
     AddTestCase(
         new HeSigBDurationTest({{{HeRu::RU_106_TONE, 1, true}, 11, 1},
                                 {{HeRu::RU_106_TONE, 2, true}, 10, 4},
@@ -1844,13 +1865,14 @@
                                 {{HeRu::RU_242_TONE, 4, true}, 4, 1}},
                                VhtPhy::GetVhtMcs1(),
                                80,
+                               HeSigBDurationTest::OFDMA,
                                {96, 15, 192, 192},
                                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);
 
-    // 160 MHz band
+    // 160 MHz band, OFDMA
     AddTestCase(
         new HeSigBDurationTest({{{HeRu::RU_106_TONE, 1, true}, 11, 1},
                                 {{HeRu::RU_106_TONE, 2, true}, 10, 4},
@@ -1864,13 +1886,14 @@
                                 {{HeRu::RU_996_TONE, 1, false}, 1, 1}},
                                VhtPhy::GetVhtMcs1(),
                                160,
+                               HeSigBDurationTest::OFDMA,
                                {96, 15, 192, 192, 208, 208, 208, 208},
                                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);
 
-    // 20 MHz band, one unallocated RU at the middle
+    // 20 MHz band, HeSigBDurationTest::OFDMA, one unallocated RU at the middle
     AddTestCase(
         new HeSigBDurationTest({{{HeRu::RU_26_TONE, 1, true}, 11, 1},
                                 {{HeRu::RU_26_TONE, 2, true}, 11, 1},
@@ -1882,13 +1905,14 @@
                                 {{HeRu::RU_26_TONE, 9, true}, 11, 1}},
                                VhtPhy::GetVhtMcs5(),
                                20,
+                               HeSigBDurationTest::OFDMA,
                                {0},
                                std::make_pair(9, 0), // 9 users in HE-SIG-B content channel 1
-                               MicroSeconds(8)),     // two OFDM symbols;
+                               MicroSeconds(8)),     // two OFDM symbols
         TestCase::QUICK);
 
-    // 40 MHz band, 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
+    // 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
     AddTestCase(
         new HeSigBDurationTest({{{HeRu::RU_52_TONE, 2, true}, 10, 1},
                                 {{HeRu::RU_52_TONE, 3, true}, 10, 2},
@@ -1896,13 +1920,14 @@
                                 {{HeRu::RU_52_TONE, 8, true}, 11, 2}},
                                VhtPhy::GetVhtMcs5(),
                                40,
+                               HeSigBDurationTest::OFDMA,
                                {112, 112},
                                std::make_pair(4, 4), // 4 users in both HE-SIG-B content channels
-                               MicroSeconds(4)),     // two OFDM symbols;
+                               MicroSeconds(4)),     // two OFDM symbols
         TestCase::QUICK);
 
-    // 40 MHz band, one unallocated RUs in the first 20 MHz subband and two unallocated RUs in
-    // second 20 MHz subband
+    // 40 MHz band, HeSigBDurationTest::OFDMA, one unallocated RUs in the first 20 MHz subband and
+    // two unallocated RUs in second 20 MHz subband
     AddTestCase(
         new HeSigBDurationTest({{{HeRu::RU_52_TONE, 1, true}, 10, 1},
                                 {{HeRu::RU_52_TONE, 2, true}, 10, 2},
@@ -1911,10 +1936,303 @@
                                 {{HeRu::RU_52_TONE, 6, true}, 11, 3}},
                                VhtPhy::GetVhtMcs5(),
                                40,
+                               HeSigBDurationTest::OFDMA,
                                {112, 112},
                                std::make_pair(4, 4), // 4 users in both HE-SIG-B content channels
-                               MicroSeconds(4)),     // two OFDM symbols;
+                               MicroSeconds(4)),     // two OFDM symbols
+        TestCase::QUICK);
+
+    // 20 MHz band, MU-MIMO, 2 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_242_TONE, 1, true}, 11, 1}, {{HeRu::RU_242_TONE, 1, true}, 10, 4}},
+                    VhtPhy::GetVhtMcs5(),
+                    20,
+                    HeSigBDurationTest::MU_MIMO,
+                    {192},
+                    std::make_pair(2, 0), // both users in HE-SIG-B content channel 1
+                    MicroSeconds(4)),     // one OFDM symbol
+                TestCase::QUICK);
+
+    // 20 MHz band, MU-MIMO, 3 users
+    AddTestCase(
+        new HeSigBDurationTest({{{HeRu::RU_242_TONE, 1, true}, 4, 3},
+                                {{HeRu::RU_242_TONE, 1, true}, 5, 2},
+                                {{HeRu::RU_242_TONE, 1, true}, 6, 1}},
+                               VhtPhy::GetVhtMcs4(),
+                               20,
+                               HeSigBDurationTest::MU_MIMO,
+                               {192},
+                               std::make_pair(3, 0), // all users in HE-SIG-B content channel 1
+                               MicroSeconds(4)),     // one OFDM symbol
+        TestCase::QUICK);
+
+    // 20 MHz band, MU-MIMO, 4 users
+    AddTestCase(
+        new HeSigBDurationTest({{{HeRu::RU_242_TONE, 1, true}, 4, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 5, 2},
+                                {{HeRu::RU_242_TONE, 1, true}, 6, 3},
+                                {{HeRu::RU_242_TONE, 1, true}, 7, 2}},
+                               VhtPhy::GetVhtMcs4(),
+                               20,
+                               HeSigBDurationTest::MU_MIMO,
+                               {192},
+                               std::make_pair(4, 0), // all users in HE-SIG-B content channel 1
+                               MicroSeconds(4)),     // one OFDM symbol
+        TestCase::QUICK);
+
+    // 20 MHz band, MU-MIMO, 6 users
+    AddTestCase(
+        new HeSigBDurationTest({{{HeRu::RU_242_TONE, 1, true}, 4, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 5, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 6, 2},
+                                {{HeRu::RU_242_TONE, 1, true}, 7, 2},
+                                {{HeRu::RU_242_TONE, 1, true}, 8, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 9, 1}},
+                               VhtPhy::GetVhtMcs4(),
+                               20,
+                               HeSigBDurationTest::MU_MIMO,
+                               {192},
+                               std::make_pair(6, 0), // all users in HE-SIG-B content channel 1
+                               MicroSeconds(4)),     // one OFDM symbol
+        TestCase::QUICK);
+
+    // 20 MHz band, MU-MIMO, 8 users
+    AddTestCase(
+        new HeSigBDurationTest({{{HeRu::RU_242_TONE, 1, true}, 4, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 5, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 6, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 7, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 8, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 9, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 10, 1},
+                                {{HeRu::RU_242_TONE, 1, true}, 11, 1}},
+                               VhtPhy::GetVhtMcs4(),
+                               20,
+                               HeSigBDurationTest::MU_MIMO,
+                               {192},
+                               std::make_pair(8, 0), // all users in HE-SIG-B content channel 1
+                               MicroSeconds(8)),     // two OFDM symbols
+        TestCase::QUICK);
+
+    // 40 MHz band, MU-MIMO, 2 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_484_TONE, 1, true}, 11, 1}, {{HeRu::RU_484_TONE, 1, true}, 10, 4}},
+                    VhtPhy::GetVhtMcs5(),
+                    40,
+                    HeSigBDurationTest::MU_MIMO,
+                    {200, 200},
+                    std::make_pair(1, 1), // users equally split between the two content channels
+                    MicroSeconds(4)),     // one OFDM symbol
+                TestCase::QUICK);
+
+    // 40 MHz band, MU-MIMO, 3 users
+    AddTestCase(
+        new HeSigBDurationTest(
+            {{{HeRu::RU_484_TONE, 1, true}, 4, 3},
+             {{HeRu::RU_484_TONE, 1, true}, 5, 2},
+             {{HeRu::RU_484_TONE, 1, true}, 6, 1}},
+            VhtPhy::GetVhtMcs4(),
+            40,
+            HeSigBDurationTest::MU_MIMO,
+            {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);
+
+    // 40 MHz band, MU-MIMO, 4 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_484_TONE, 1, true}, 4, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 5, 2},
+                     {{HeRu::RU_484_TONE, 1, true}, 6, 3},
+                     {{HeRu::RU_484_TONE, 1, true}, 7, 2}},
+                    VhtPhy::GetVhtMcs4(),
+                    40,
+                    HeSigBDurationTest::MU_MIMO,
+                    {200, 200},
+                    std::make_pair(2, 2), // users equally split between the two content channels
+                    MicroSeconds(4)),     // one OFDM symbol
+                TestCase::QUICK);
+
+    // 40 MHz band, MU-MIMO, 6 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_484_TONE, 1, true}, 4, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 5, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 6, 2},
+                     {{HeRu::RU_484_TONE, 1, true}, 7, 2},
+                     {{HeRu::RU_484_TONE, 1, true}, 8, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 9, 1}},
+                    VhtPhy::GetVhtMcs4(),
+                    40,
+                    HeSigBDurationTest::MU_MIMO,
+                    {200, 200},
+                    std::make_pair(3, 3), // users equally split between the two content channels
+                    MicroSeconds(4)),     // one OFDM symbol
+                TestCase::QUICK);
+
+    // 40 MHz band, MU-MIMO, 8 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_484_TONE, 1, true}, 4, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 5, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 6, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 7, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 8, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 9, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 10, 1},
+                     {{HeRu::RU_484_TONE, 1, true}, 11, 1}},
+                    VhtPhy::GetVhtMcs4(),
+                    40,
+                    HeSigBDurationTest::MU_MIMO,
+                    {200, 200},
+                    std::make_pair(4, 4), // users equally split between the two content channels
+                    MicroSeconds(4)),     // one OFDM symbol
+                TestCase::QUICK);
+
+    // 80 MHz band, MU-MIMO, 2 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_996_TONE, 1, true}, 11, 1}, {{HeRu::RU_996_TONE, 1, true}, 10, 4}},
+                    VhtPhy::GetVhtMcs5(),
+                    80,
+                    HeSigBDurationTest::MU_MIMO,
+                    {208, 208, 208, 208},
+                    std::make_pair(1, 1), // users equally split between the two content channels
+                    MicroSeconds(4)),     // one OFDM symbol
+                TestCase::QUICK);
+
+    // 80 MHz band, MU-MIMO, 3 users
+    AddTestCase(
+        new HeSigBDurationTest(
+            {{{HeRu::RU_996_TONE, 1, true}, 4, 3},
+             {{HeRu::RU_996_TONE, 1, true}, 5, 2},
+             {{HeRu::RU_996_TONE, 1, true}, 6, 1}},
+            VhtPhy::GetVhtMcs4(),
+            80,
+            HeSigBDurationTest::MU_MIMO,
+            {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);
+
+    // 80 MHz band, MU-MIMO, 4 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_996_TONE, 1, true}, 4, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 5, 2},
+                     {{HeRu::RU_996_TONE, 1, true}, 6, 3},
+                     {{HeRu::RU_996_TONE, 1, true}, 7, 2}},
+                    VhtPhy::GetVhtMcs4(),
+                    80,
+                    HeSigBDurationTest::MU_MIMO,
+                    {208, 208, 208, 208},
+                    std::make_pair(2, 2), // users equally split between the two content channels
+                    MicroSeconds(4)),     // one OFDM symbol
+                TestCase::QUICK);
+
+    // 80 MHz band, MU-MIMO, 6 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_996_TONE, 1, true}, 4, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 5, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 6, 2},
+                     {{HeRu::RU_996_TONE, 1, true}, 7, 2},
+                     {{HeRu::RU_996_TONE, 1, true}, 8, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 9, 1}},
+                    VhtPhy::GetVhtMcs4(),
+                    80,
+                    HeSigBDurationTest::MU_MIMO,
+                    {208, 208, 208, 208},
+                    std::make_pair(3, 3), // users equally split between the two content channels
+                    MicroSeconds(4)),     // one OFDM symbol
+                TestCase::QUICK);
+
+    // 80 MHz band, MU-MIMO, 8 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_996_TONE, 1, true}, 4, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 5, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 6, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 7, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 8, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 9, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 10, 1},
+                     {{HeRu::RU_996_TONE, 1, true}, 11, 1}},
+                    VhtPhy::GetVhtMcs4(),
+                    80,
+                    HeSigBDurationTest::MU_MIMO,
+                    {208, 208, 208, 208},
+                    std::make_pair(4, 4), // users equally split between the two content channels
+                    MicroSeconds(4)),     // one OFDM symbol
+                TestCase::QUICK);
+
+    // 160 MHz band, MU-MIMO, 2 users
+    AddTestCase(
+        new HeSigBDurationTest(
+            {{{HeRu::RU_2x996_TONE, 1, true}, 11, 1}, {{HeRu::RU_2x996_TONE, 1, true}, 10, 4}},
+            VhtPhy::GetVhtMcs5(),
+            160,
+            HeSigBDurationTest::MU_MIMO,
+            {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);
+
+    // 160 MHz band, MU-MIMO, 3 users
+    AddTestCase(
+        new HeSigBDurationTest(
+            {{{HeRu::RU_2x996_TONE, 1, true}, 4, 3},
+             {{HeRu::RU_2x996_TONE, 1, true}, 5, 2},
+             {{HeRu::RU_2x996_TONE, 1, true}, 6, 1}},
+            VhtPhy::GetVhtMcs4(),
+            160,
+            HeSigBDurationTest::MU_MIMO,
+            {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);
+
+    // 160 MHz band, MU-MIMO, 4 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_2x996_TONE, 1, true}, 4, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 5, 2},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 6, 3},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 7, 2}},
+                    VhtPhy::GetVhtMcs4(),
+                    160,
+                    HeSigBDurationTest::MU_MIMO,
+                    {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);
+
+    // 160 MHz band, MU-MIMO, 6 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_2x996_TONE, 1, true}, 4, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 5, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 6, 2},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 7, 2},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 8, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 9, 1}},
+                    VhtPhy::GetVhtMcs4(),
+                    160,
+                    HeSigBDurationTest::MU_MIMO,
+                    {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);
+
+    // 160 MHz band, MU-MIMO, 8 users
+    AddTestCase(new HeSigBDurationTest(
+                    {{{HeRu::RU_2x996_TONE, 1, true}, 4, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 5, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 6, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 7, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 8, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 9, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 10, 1},
+                     {{HeRu::RU_2x996_TONE, 1, true}, 11, 1}},
+                    VhtPhy::GetVhtMcs4(),
+                    160,
+                    HeSigBDurationTest::MU_MIMO,
+                    {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);
 }
 
 static TxDurationTestSuite g_txDurationTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-eht-info-elems-test.cc ns-3.40/src/wifi/test/wifi-eht-info-elems-test.cc
--- ns-3.39/src/wifi/test/wifi-eht-info-elems-test.cc	2023-07-05 14:23:48.129428400 -0700
+++ ns-3.40/src/wifi/test/wifi-eht-info-elems-test.cc	2023-09-27 13:30:37.922839900 -0700
@@ -23,10 +23,13 @@
 #include "ns3/mgt-headers.h"
 #include "ns3/multi-link-element.h"
 #include "ns3/reduced-neighbor-report.h"
+#include "ns3/simulator.h"
 #include "ns3/tid-to-link-mapping-element.h"
 #include "ns3/wifi-phy-operating-channel.h"
+#include "ns3/wifi-utils.h"
 
 #include <optional>
+#include <set>
 #include <sstream>
 #include <vector>
 
@@ -216,7 +219,7 @@
     assoc.Get<Ssid>() = Ssid("OtherSsid");
     // another "mistake" of the same type, except that a TID-To-Link Mapping element
     // is not included in the containing frame
-    assoc.Get<TidToLinkMapping>().emplace();
+    assoc.Get<TidToLinkMapping>().emplace_back();
     // the SupportedRates IE is the same (hence not serialized) as in the containing frame,
     // while the ExtendedSupportedRatesIE is different (hence serialized)
     rates.AddSupportedRate(5.5e6);
@@ -404,8 +407,8 @@
     NS_TEST_EXPECT_MSG_EQ(frame.Get<EhtCapabilities>().has_value(),
                           true,
                           "Containing frame should have EHT Capabilities IE");
-    NS_TEST_EXPECT_MSG_EQ(frame.Get<TidToLinkMapping>().has_value(),
-                          false,
+    NS_TEST_EXPECT_MSG_EQ(frame.Get<TidToLinkMapping>().empty(),
+                          true,
                           "Containing frame should not have TID-to-Link Mapping IE");
 
     auto& mle = frame.Get<MultiLinkElement>().value();
@@ -467,8 +470,8 @@
         (perSta1Frame.Get<EhtCapabilities>() == frame.Get<EhtCapabilities>()),
         true,
         "EHT Capabilities IE not correctly inherited by frame in first Per-STA Profile");
-    NS_TEST_EXPECT_MSG_EQ(perSta1Frame.Get<TidToLinkMapping>().has_value(),
-                          false,
+    NS_TEST_EXPECT_MSG_EQ(perSta1Frame.Get<TidToLinkMapping>().empty(),
+                          true,
                           "Frame in first Per-STA Profile should not have TID-to-Link Mapping IE");
 
     // frame in second Per-STA Profile subelement includes VHT Capabilities IE and has inherited
@@ -524,8 +527,8 @@
         perSta2Frame.Get<EhtCapabilities>().has_value(),
         false,
         "Frame in second Per-STA Profile should have not inherited EHT Capabilities IE");
-    NS_TEST_EXPECT_MSG_EQ(perSta2Frame.Get<TidToLinkMapping>().has_value(),
-                          false,
+    NS_TEST_EXPECT_MSG_EQ(perSta2Frame.Get<TidToLinkMapping>().empty(),
+                          true,
                           "Frame in second Per-STA Profile should not have TID-to-Link Mapping IE");
 
     // frame in third Per-STA Profile subelement includes VHT Capabilities IE and has inherited
@@ -584,8 +587,8 @@
         (perSta3Frame.Get<EhtCapabilities>() == frame.Get<EhtCapabilities>()),
         true,
         "EHT Capabilities IE not correctly inherited by frame in third Per-STA Profile");
-    NS_TEST_EXPECT_MSG_EQ(perSta3Frame.Get<TidToLinkMapping>().has_value(),
-                          false,
+    NS_TEST_EXPECT_MSG_EQ(perSta3Frame.Get<TidToLinkMapping>().empty(),
+                          true,
                           "Frame in third Per-STA Profile should not have TID-to-Link Mapping IE");
 }
 
@@ -1205,64 +1208,81 @@
     /**
      * Constructor
      *
-     * \tparam Args \deduced Template type parameter pack for the sequence of TID-Link mapping pairs
      * \param direction The direction for the TID-to-link mapping
-     * \param args A sequence of TID-Link mapping pairs
+     * \param mappingSwitchTime the Mapping Switching Time
+     * \param expectedDuration the Expected Duration
+     * \param mappings A TID-indexed map of the link sets the TIDs are mapped to
      */
-    template <typename... Args>
-    TidToLinkMappingElementTest(TidLinkMapDir direction, Args&&... args);
+    TidToLinkMappingElementTest(WifiDirection direction,
+                                std::optional<Time> mappingSwitchTime,
+                                std::optional<Time> expectedDuration,
+                                const WifiTidLinkMapping& mappings);
 
     ~TidToLinkMappingElementTest() override = default;
 
   private:
-    /**
-     * Set the given TID-Link mapping and recursively call itself to set the remaining pairs.
-     *
-     * \tparam Args \deduced Template type parameter pack for the sequence of TID-Link mapping pairs
-     * \param tid the TID
-     * \param linkIds the IDs of the links on which the given TID is mapped
-     * \param args A sequence of TID-Link mapping pairs
-     */
-    template <typename... Args>
-    void SetLinkMapping(uint8_t tid, const std::list<uint8_t>& linkIds, Args&&... args);
-
-    /**
-     * Base case to stop the recursion performed by the templated version of this method.
-     */
-    void SetLinkMapping()
-    {
-    }
-
+    void DoSetup() override;
     void DoRun() override;
 
-    TidToLinkMapping m_tidToLinkMapping; ///< TID-To-Link Mapping element
+    WifiDirection m_direction;               ///< the direction for the TID-to-link mapping
+    std::optional<Time> m_mappingSwitchTime; ///< the Mapping Switching Time
+    std::optional<Time> m_expectedDuration;  ///< the Expected Duration
+    WifiTidLinkMapping m_mappings;           ///< maps TIDs to link sets
+    TidToLinkMapping m_tidToLinkMapping;     ///< TID-To-Link Mapping element
 };
 
-template <typename... Args>
-TidToLinkMappingElementTest::TidToLinkMappingElementTest(TidLinkMapDir direction, Args&&... args)
+TidToLinkMappingElementTest::TidToLinkMappingElementTest(WifiDirection direction,
+                                                         std::optional<Time> mappingSwitchTime,
+                                                         std::optional<Time> expectedDuration,
+                                                         const WifiTidLinkMapping& mappings)
     : HeaderSerializationTestCase(
-          "Check serialization and deserialization of TID-To-Link Mapping elements")
+          "Check serialization and deserialization of TID-To-Link Mapping elements"),
+      m_direction(direction),
+      m_mappingSwitchTime(mappingSwitchTime),
+      m_expectedDuration(expectedDuration),
+      m_mappings(mappings)
 {
-    m_tidToLinkMapping.m_control.direction = direction;
-    m_tidToLinkMapping.m_control.defaultMapping = true;
-    SetLinkMapping(args...);
 }
 
-template <typename... Args>
 void
-TidToLinkMappingElementTest::SetLinkMapping(uint8_t tid,
-                                            const std::list<uint8_t>& linkIds,
-                                            Args&&... args)
-{
-    m_tidToLinkMapping.m_control.defaultMapping = false;
-    m_tidToLinkMapping.SetLinkMappingOfTid(tid, linkIds);
-    SetLinkMapping(args...);
+TidToLinkMappingElementTest::DoSetup()
+{
+    m_tidToLinkMapping.m_control.direction = m_direction;
+    m_tidToLinkMapping.m_control.defaultMapping = true;
+
+    if (m_mappingSwitchTime)
+    {
+        m_tidToLinkMapping.SetMappingSwitchTime(*m_mappingSwitchTime);
+        std::optional<Time> encoded = m_tidToLinkMapping.GetMappingSwitchTime();
+        NS_TEST_ASSERT_MSG_EQ(encoded.has_value(), true, "Mapping Switch Time should be present");
+        NS_TEST_EXPECT_MSG_EQ(*m_mappingSwitchTime,
+                              *encoded,
+                              "Incorrect Mapping Switch Time value");
+    }
+    if (m_expectedDuration)
+    {
+        m_tidToLinkMapping.SetExpectedDuration(*m_expectedDuration);
+        std::optional<Time> encoded = m_tidToLinkMapping.GetExpectedDuration();
+        NS_TEST_ASSERT_MSG_EQ(encoded.has_value(), true, "Expected Duration should be present");
+        NS_TEST_EXPECT_MSG_EQ(*m_expectedDuration, *encoded, "Incorrect Expected Duration value");
+    }
+
+    for (const auto& [tid, linkSet] : m_mappings)
+    {
+        m_tidToLinkMapping.m_control.defaultMapping = false;
+        m_tidToLinkMapping.SetLinkMappingOfTid(tid, linkSet);
+        NS_TEST_EXPECT_MSG_EQ((m_tidToLinkMapping.GetLinkMappingOfTid(tid) == linkSet),
+                              true,
+                              "Incorrect link set for TID " << +tid);
+    }
 }
 
 void
 TidToLinkMappingElementTest::DoRun()
 {
     TestHeaderSerialization(m_tidToLinkMapping);
+
+    Simulator::Destroy();
 }
 
 /**
@@ -1362,33 +1382,31 @@
     AddTestCase(new WifiEhtCapabilitiesIeTest(true, 80), TestCase::QUICK);
     AddTestCase(new WifiEhtCapabilitiesIeTest(false, 160), TestCase::QUICK);
     AddTestCase(new WifiEhtCapabilitiesIeTest(false, 320), TestCase::QUICK);
-    AddTestCase(new TidToLinkMappingElementTest(TidLinkMapDir::DOWNLINK), TestCase::QUICK);
     AddTestCase(
-        new TidToLinkMappingElementTest(TidLinkMapDir::UPLINK, 3, std::list<uint8_t>{0, 4, 6}),
+        new TidToLinkMappingElementTest(WifiDirection::DOWNLINK, std::nullopt, std::nullopt, {}),
         TestCase::QUICK);
-    AddTestCase(new TidToLinkMappingElementTest(TidLinkMapDir::BOTH_DIRECTIONS,
-                                                3,
-                                                std::list<uint8_t>{0, 4, 6},
-                                                6,
-                                                std::list<uint8_t>{3, 7, 11, 14}),
+    AddTestCase(new TidToLinkMappingElementTest(WifiDirection::UPLINK,
+                                                MicroSeconds(500 * 1024),
+                                                MicroSeconds(300 * 1024),
+                                                {{3, std::set<uint8_t>{0, 4, 6}}}),
+                TestCase::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);
-    AddTestCase(new TidToLinkMappingElementTest(TidLinkMapDir::DOWNLINK,
-                                                0,
-                                                std::list<uint8_t>{0, 1, 2},
-                                                1,
-                                                std::list<uint8_t>{3, 4, 5},
-                                                2,
-                                                std::list<uint8_t>{6, 7},
-                                                3,
-                                                std::list<uint8_t>{8, 9, 10},
-                                                4,
-                                                std::list<uint8_t>{11, 12, 13},
-                                                5,
-                                                std::list<uint8_t>{14},
-                                                6,
-                                                std::list<uint8_t>{1, 3, 6},
-                                                7,
-                                                std::list<uint8_t>{11, 14}),
+    AddTestCase(new TidToLinkMappingElementTest(WifiDirection::DOWNLINK,
+                                                MicroSeconds(100 * 1024),
+                                                std::nullopt,
+                                                {{0, std::set<uint8_t>{0, 1, 2}},
+                                                 {1, std::set<uint8_t>{3, 4, 5}},
+                                                 {2, std::set<uint8_t>{6, 7}},
+                                                 {3, std::set<uint8_t>{8, 9, 10}},
+                                                 {4, std::set<uint8_t>{11, 12, 13}},
+                                                 {5, std::set<uint8_t>{14}},
+                                                 {6, std::set<uint8_t>{1, 3, 6}},
+                                                 {7, std::set<uint8_t>{11, 14}}}),
                 TestCase::QUICK);
     AddTestCase(new EhtOperationElementTest({0, 0, 0, 0, 0}, 1, 2, 3, 4, 5, 6, 7, 8, std::nullopt),
                 TestCase::QUICK);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-emlsr-test.cc ns-3.40/src/wifi/test/wifi-emlsr-test.cc
--- ns-3.39/src/wifi/test/wifi-emlsr-test.cc	2023-07-05 14:23:48.129428400 -0700
+++ ns-3.40/src/wifi/test/wifi-emlsr-test.cc	2023-09-27 13:30:37.922839900 -0700
@@ -55,15 +55,6 @@
 
 NS_LOG_COMPONENT_DEFINE("WifiEmlsrTest");
 
-static uint32_t
-ContextToNodeId(std::string context)
-{
-    std::string sub = context.substr(10);
-    uint32_t pos = sub.find("/Device");
-    uint32_t nodeId = std::stoi(sub.substr(0, pos));
-    return nodeId;
-}
-
 /**
  * \ingroup wifi-test
  * \ingroup tests
@@ -92,7 +83,7 @@
 void
 EmlOperatingModeNotificationTest::DoRun()
 {
-    MgtEmlOperatingModeNotification frame;
+    MgtEmlOmn frame;
 
     // Both EMLSR Mode and EMLMR Mode subfields set to 0 (no link bitmap);
     TestHeaderSerialization(frame);
@@ -113,7 +104,7 @@
     auto transition = MicroSeconds(128);
 
     frame.m_emlControl.emlsrParamUpdateCtrl = 1;
-    frame.m_emlsrParamUpdate = MgtEmlOperatingModeNotification::EmlsrParamUpdate{};
+    frame.m_emlsrParamUpdate = MgtEmlOmn::EmlsrParamUpdate{};
     frame.m_emlsrParamUpdate->paddingDelay = CommonInfoBasicMle::EncodeEmlsrPaddingDelay(padding);
     frame.m_emlsrParamUpdate->transitionDelay =
         CommonInfoBasicMle::EncodeEmlsrTransitionDelay(transition);
@@ -168,14 +159,14 @@
     /**
      * Callback invoked when a FEM passes PSDUs to the PHY.
      *
-     * \param linkId the ID of the link transmitting the PSDUs
-     * \param context the context
+     * \param mac the MAC transmitting the PSDUs
+     * \param phyId the ID of the PHY transmitting the PSDUs
      * \param psduMap the PSDU map
      * \param txVector the TX vector
      * \param txPowerW the tx power in Watts
      */
-    virtual void Transmit(uint8_t linkId,
-                          std::string context,
+    virtual void Transmit(Ptr<WifiMac> mac,
+                          uint8_t phyId,
                           WifiConstPsduMap psduMap,
                           WifiTxVector txVector,
                           double txPowerW);
@@ -193,6 +184,27 @@
                                            std::size_t count,
                                            std::size_t pktSize) const;
 
+    /**
+     * Check whether QoS data unicast transmissions addressed to the given destination on the
+     * given link are blocked or unblocked for the given reason on the given device.
+     *
+     * \param mac the MAC of the given device
+     * \param dest the MAC address of the given destination
+     * \param linkId the ID of the given link
+     * \param reason the reason for blocking transmissions to test
+     * \param blocked whether transmissions are blocked for the given reason
+     * \param description text indicating when this check is performed
+     * \param testUnblockedForOtherReasons whether to test if transmissions are unblocked for
+     *                                     all the reasons other than the one provided
+     */
+    void CheckBlockedLink(Ptr<WifiMac> mac,
+                          Mac48Address dest,
+                          uint8_t linkId,
+                          WifiQueueBlockedReason reason,
+                          bool blocked,
+                          std::string description,
+                          bool testUnblockedForOtherReasons = true);
+
     void DoSetup() override;
 
     /// Information about transmitted frames
@@ -202,8 +214,10 @@
         WifiConstPsduMap psduMap; ///< transmitted PSDU map
         WifiTxVector txVector;    ///< TXVECTOR
         uint8_t linkId;           ///< link ID
+        uint8_t phyId;            ///< ID of the transmitting PHY
     };
 
+    uint8_t m_mainPhyId{0};                   //!< ID of the main PHY
     std::set<uint8_t> m_linksToEnableEmlsrOn; /**< IDs of the links on which EMLSR mode has to
                                                    be enabled */
     std::size_t m_nEmlsrStations{1};          ///< number of stations to create that activate EMLSR
@@ -250,21 +264,24 @@
 }
 
 void
-EmlsrOperationsTestBase::Transmit(uint8_t linkId,
-                                  std::string context,
+EmlsrOperationsTestBase::Transmit(Ptr<WifiMac> mac,
+                                  uint8_t phyId,
                                   WifiConstPsduMap psduMap,
                                   WifiTxVector txVector,
                                   double txPowerW)
 {
-    m_txPsdus.push_back({Simulator::Now(), psduMap, txVector, linkId});
+    auto linkId = mac->GetLinkForPhy(phyId);
+    NS_TEST_ASSERT_MSG_EQ(linkId.has_value(), true, "No link found for PHY ID " << +phyId);
+    m_txPsdus.push_back({Simulator::Now(), psduMap, txVector, *linkId, phyId});
+
     auto txDuration =
-        WifiPhy::CalculateTxDuration(psduMap, txVector, m_apMac->GetWifiPhy(linkId)->GetPhyBand());
+        WifiPhy::CalculateTxDuration(psduMap, txVector, mac->GetWifiPhy(*linkId)->GetPhyBand());
 
     for (const auto& [aid, psdu] : psduMap)
     {
         std::stringstream ss;
-        ss << std::setprecision(10) << "PSDU #" << m_txPsdus.size() << " Link ID " << +linkId << " "
-           << psdu->GetHeader(0).GetTypeString();
+        ss << std::setprecision(10) << "PSDU #" << m_txPsdus.size() << " Link ID "
+           << +linkId.value() << " Phy ID " << +phyId << " " << psdu->GetHeader(0).GetTypeString();
         if (psdu->GetHeader(0).IsAction())
         {
             ss << " ";
@@ -341,7 +358,9 @@
                 BooleanValue(false));
     mac.SetEmlsrManager("ns3::DefaultEmlsrManager",
                         "EmlsrLinkSet",
-                        AttributeContainerValue<UintegerValue>(m_linksToEnableEmlsrOn));
+                        AttributeContainerValue<UintegerValue>(m_linksToEnableEmlsrOn),
+                        "MainPhyId",
+                        UintegerValue(m_mainPhyId));
 
     NetDeviceContainer staDevices = wifi.Install(phyHelper, mac, wifiStaNodes);
 
@@ -375,11 +394,22 @@
     }
 
     // Trace PSDUs passed to the PHY on AP MLD and non-AP MLDs
-    for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
+    for (uint8_t phyId = 0; phyId < m_apMac->GetDevice()->GetNPhys(); phyId++)
+    {
+        Config::ConnectWithoutContext(
+            "/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phys/" + std::to_string(phyId) +
+                "/PhyTxPsduBegin",
+            MakeCallback(&EmlsrOperationsTestBase::Transmit, this).Bind(m_apMac, phyId));
+    }
+    for (std::size_t i = 0; i < m_nEmlsrStations + m_nNonEmlsrStations; i++)
     {
-        Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
-                            std::to_string(linkId) + "/PhyTxPsduBegin",
-                        MakeCallback(&EmlsrOperationsTestBase::Transmit, this).Bind(linkId));
+        for (uint8_t phyId = 0; phyId < m_staMacs[i]->GetDevice()->GetNPhys(); phyId++)
+        {
+            Config::ConnectWithoutContext(
+                "/NodeList/" + std::to_string(i + 1) + "/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
+                    std::to_string(phyId) + "/PhyTxPsduBegin",
+                MakeCallback(&EmlsrOperationsTestBase::Transmit, this).Bind(m_staMacs[i], phyId));
+        }
     }
 
     // Uncomment the lines below to write PCAP files
@@ -509,6 +539,50 @@
     });
 }
 
+void
+EmlsrOperationsTestBase::CheckBlockedLink(Ptr<WifiMac> mac,
+                                          Mac48Address dest,
+                                          uint8_t linkId,
+                                          WifiQueueBlockedReason reason,
+                                          bool blocked,
+                                          std::string description,
+                                          bool testUnblockedForOtherReasons)
+{
+    WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, dest, 0);
+    auto mask = mac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, linkId);
+    NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
+                          true,
+                          description << ": Expected to find a mask for EMLSR link " << +linkId);
+    if (blocked)
+    {
+        NS_TEST_EXPECT_MSG_EQ(mask->test(static_cast<std::size_t>(reason)),
+                              true,
+                              description << ": Expected EMLSR link " << +linkId
+                                          << " to be blocked for reason " << reason);
+        if (testUnblockedForOtherReasons)
+        {
+            NS_TEST_EXPECT_MSG_EQ(mask->count(),
+                                  1,
+                                  description << ": Expected EMLSR link " << +linkId
+                                              << " to be blocked for one reason only");
+        }
+    }
+    else if (testUnblockedForOtherReasons)
+    {
+        NS_TEST_EXPECT_MSG_EQ(mask->none(),
+                              true,
+                              description << ": Expected EMLSR link " << +linkId
+                                          << " to be unblocked");
+    }
+    else
+    {
+        NS_TEST_EXPECT_MSG_EQ(mask->test(static_cast<std::size_t>(reason)),
+                              false,
+                              description << ": Expected EMLSR link " << +linkId
+                                          << " to be unblocked for reason " << reason);
+    }
+}
+
 /**
  * \ingroup wifi-test
  * \ingroup tests
@@ -531,7 +605,7 @@
  *   timeout expires and when an EML Notification response is received from the AP MLD (thus,
  *   the correct EMLSR link set is stored after whichever of the two events occur first)
  */
-class EmlNotificationExchangeTest : public EmlsrOperationsTestBase
+class EmlOmnExchangeTest : public EmlsrOperationsTestBase
 {
   public:
     /**
@@ -540,15 +614,14 @@
      * \param linksToEnableEmlsrOn IDs of links on which EMLSR mode should be enabled
      * \param transitionTimeout the Transition Timeout advertised by the AP MLD
      */
-    EmlNotificationExchangeTest(const std::set<uint8_t>& linksToEnableEmlsrOn,
-                                Time transitionTimeout);
-    ~EmlNotificationExchangeTest() override = default;
+    EmlOmnExchangeTest(const std::set<uint8_t>& linksToEnableEmlsrOn, Time transitionTimeout);
+    ~EmlOmnExchangeTest() override = default;
 
   protected:
     void DoSetup() override;
     void DoRun() override;
-    void Transmit(uint8_t linkId,
-                  std::string context,
+    void Transmit(Ptr<WifiMac> mac,
+                  uint8_t phyId,
                   WifiConstPsduMap psduMap,
                   WifiTxVector txVector,
                   double txPowerW) override;
@@ -605,7 +678,6 @@
     void CheckEmlsrLinks();
 
   private:
-    std::optional<uint8_t> m_assocLinkId;      //!< ID of the link used to establish association
     std::size_t m_checkEmlsrLinksCount;        /**< counter for the number of times CheckEmlsrLinks
                                                     is called (should be two: when the transition
                                                     timeout expires and when the EML Notification
@@ -617,9 +689,8 @@
     std::list<uint64_t> m_uidList;             ///< list of UIDs of packets to corrupt
 };
 
-EmlNotificationExchangeTest::EmlNotificationExchangeTest(
-    const std::set<uint8_t>& linksToEnableEmlsrOn,
-    Time transitionTimeout)
+EmlOmnExchangeTest::EmlOmnExchangeTest(const std::set<uint8_t>& linksToEnableEmlsrOn,
+                                       Time transitionTimeout)
     : EmlsrOperationsTestBase("Check EML Notification exchange"),
       m_checkEmlsrLinksCount(0),
       m_emlNotificationDroppedCount(0)
@@ -632,7 +703,7 @@
 }
 
 void
-EmlNotificationExchangeTest::DoSetup()
+EmlOmnExchangeTest::DoSetup()
 {
     EmlsrOperationsTestBase::DoSetup();
 
@@ -642,27 +713,28 @@
         m_apMac->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_errorModel);
     }
 
-    m_staMacs[0]->TraceConnectWithoutContext(
-        "AckedMpdu",
-        MakeCallback(&EmlNotificationExchangeTest::TxOk, this));
-    m_staMacs[0]->TraceConnectWithoutContext(
-        "DroppedMpdu",
-        MakeCallback(&EmlNotificationExchangeTest::TxDropped, this));
+    m_staMacs[0]->TraceConnectWithoutContext("AckedMpdu",
+                                             MakeCallback(&EmlOmnExchangeTest::TxOk, this));
+    m_staMacs[0]->TraceConnectWithoutContext("DroppedMpdu",
+                                             MakeCallback(&EmlOmnExchangeTest::TxDropped, this));
 }
 
 void
-EmlNotificationExchangeTest::Transmit(uint8_t linkId,
-                                      std::string context,
-                                      WifiConstPsduMap psduMap,
-                                      WifiTxVector txVector,
-                                      double txPowerW)
+EmlOmnExchangeTest::Transmit(Ptr<WifiMac> mac,
+                             uint8_t phyId,
+                             WifiConstPsduMap psduMap,
+                             WifiTxVector txVector,
+                             double txPowerW)
 {
+    EmlsrOperationsTestBase::Transmit(mac, phyId, psduMap, txVector, txPowerW);
+    auto linkId = m_txPsdus.back().linkId;
+
     auto psdu = psduMap.begin()->second;
 
     switch (psdu->GetHeader(0).GetType())
     {
     case WIFI_MAC_MGT_ASSOCIATION_REQUEST:
-        m_assocLinkId = linkId;
+        NS_TEST_EXPECT_MSG_EQ(+linkId, +m_mainPhyId, "AssocReq not sent by the main PHY");
         CheckEmlCapabilitiesInAssocReq(*psdu->begin(), txVector, linkId);
         break;
 
@@ -690,14 +762,12 @@
 
     default:;
     }
-
-    EmlsrOperationsTestBase::Transmit(linkId, context, psduMap, txVector, txPowerW);
 }
 
 void
-EmlNotificationExchangeTest::CheckEmlCapabilitiesInAssocReq(Ptr<const WifiMpdu> mpdu,
-                                                            const WifiTxVector& txVector,
-                                                            uint8_t linkId)
+EmlOmnExchangeTest::CheckEmlCapabilitiesInAssocReq(Ptr<const WifiMpdu> mpdu,
+                                                   const WifiTxVector& txVector,
+                                                   uint8_t linkId)
 {
     MgtAssocRequestHeader frame;
     mpdu->GetPacket()->PeekHeader(frame);
@@ -720,9 +790,9 @@
 }
 
 void
-EmlNotificationExchangeTest::CheckEmlCapabilitiesInAssocResp(Ptr<const WifiMpdu> mpdu,
-                                                             const WifiTxVector& txVector,
-                                                             uint8_t linkId)
+EmlOmnExchangeTest::CheckEmlCapabilitiesInAssocResp(Ptr<const WifiMpdu> mpdu,
+                                                    const WifiTxVector& txVector,
+                                                    uint8_t linkId)
 {
     bool sentToEmlsrClient =
         (m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr1()) == linkId);
@@ -752,11 +822,11 @@
 }
 
 void
-EmlNotificationExchangeTest::CheckEmlNotification(Ptr<const WifiPsdu> psdu,
-                                                  const WifiTxVector& txVector,
-                                                  uint8_t linkId)
+EmlOmnExchangeTest::CheckEmlNotification(Ptr<const WifiPsdu> psdu,
+                                         const WifiTxVector& txVector,
+                                         uint8_t linkId)
 {
-    MgtEmlOperatingModeNotification frame;
+    MgtEmlOmn frame;
     auto mpdu = *psdu->begin();
     auto pkt = mpdu->GetPacket()->Copy();
     WifiActionHeader::Remove(pkt);
@@ -806,20 +876,17 @@
                                                   txVector,
                                                   m_staMacs[0]->GetWifiPhy(linkId)->GetPhyBand()) +
                      MicroSeconds(1); // to account for propagation delay
-        Simulator::Schedule(delay, &EmlNotificationExchangeTest::CheckEmlsrLinks, this);
+        Simulator::Schedule(delay, &EmlOmnExchangeTest::CheckEmlsrLinks, this);
     }
 
-    NS_TEST_ASSERT_MSG_EQ(m_assocLinkId.has_value(),
-                          true,
-                          "No link ID indicating the link on which association was performed");
-    NS_TEST_EXPECT_MSG_EQ(+m_assocLinkId.value(),
+    NS_TEST_EXPECT_MSG_EQ(+m_mainPhyId,
                           +linkId,
                           "EML Notification received on unexpected link (frame sent by non-AP MLD: "
                               << std::boolalpha << sentbyNonApMld << ")");
 }
 
 void
-EmlNotificationExchangeTest::TxOk(Ptr<const WifiMpdu> mpdu)
+EmlOmnExchangeTest::TxOk(Ptr<const WifiMpdu> mpdu)
 {
     const auto& hdr = mpdu->GetHeader();
 
@@ -833,14 +900,14 @@
             // the EML Operating Mode Notification frame that the non-AP MLD sent has been
             // acknowledged; after the transition timeout, the EMLSR links have been set
             Simulator::Schedule(m_transitionTimeout + NanoSeconds(1),
-                                &EmlNotificationExchangeTest::CheckEmlsrLinks,
+                                &EmlOmnExchangeTest::CheckEmlsrLinks,
                                 this);
         }
     }
 }
 
 void
-EmlNotificationExchangeTest::TxDropped(WifiMacDropReason reason, Ptr<const WifiMpdu> mpdu)
+EmlOmnExchangeTest::TxDropped(WifiMacDropReason reason, Ptr<const WifiMpdu> mpdu)
 {
     const auto& hdr = mpdu->GetHeader();
 
@@ -859,7 +926,7 @@
 }
 
 void
-EmlNotificationExchangeTest::CheckEmlsrLinks()
+EmlOmnExchangeTest::CheckEmlsrLinks()
 {
     m_checkEmlsrLinksCount++;
 
@@ -877,7 +944,7 @@
 }
 
 void
-EmlNotificationExchangeTest::DoRun()
+EmlOmnExchangeTest::DoRun()
 {
     Simulator::Stop(m_duration);
     Simulator::Run();
@@ -970,8 +1037,8 @@
   protected:
     void DoSetup() override;
     void DoRun() override;
-    void Transmit(uint8_t linkId,
-                  std::string context,
+    void Transmit(Ptr<WifiMac> mac,
+                  uint8_t phyId,
                   WifiConstPsduMap psduMap,
                   WifiTxVector txVector,
                   double txPowerW) override;
@@ -1031,11 +1098,11 @@
      *
      * \param psduMap the PSDU carrying BlockAck frames
      * \param txVector the TXVECTOR used to send the PPDU
-     * \param linkId the ID of the given link
+     * \param phyId the ID of the PHY transmitting the PSDU(s)
      */
     void CheckBlockAck(const WifiConstPsduMap& psduMap,
                        const WifiTxVector& txVector,
-                       uint8_t linkId);
+                       uint8_t phyId);
 
   private:
     void StartTraffic() override;
@@ -1046,14 +1113,11 @@
     void EnableEmlsrMode();
 
     std::set<uint8_t> m_emlsrLinks; /**< IDs of the links on which EMLSR mode has to be enabled */
-    std::vector<std::optional<uint8_t>>
-        m_assocLinkId; /**< ID of the link used to establish association (vector index is the node
-                          ID) */
-    Time m_emlsrEnabledTime;      //!< when EMLSR mode has been enabled on all EMLSR clients
-    const Time m_fe2to3delay;     /**< time interval between 2nd and 3rd frame exchange sequences
-                                       after the enablement of EMLSR mode */
-    std::size_t m_countQoSframes; //!< counter for QoS frames (transition delay test)
-    std::size_t m_countBlockAck;  //!< counter for BlockAck frames (transition delay test)
+    Time m_emlsrEnabledTime;        //!< when EMLSR mode has been enabled on all EMLSR clients
+    const Time m_fe2to3delay;       /**< time interval between 2nd and 3rd frame exchange sequences
+                                         after the enablement of EMLSR mode */
+    std::size_t m_countQoSframes;   //!< counter for QoS frames (transition delay test)
+    std::size_t m_countBlockAck;    //!< counter for BlockAck frames (transition delay test)
     Ptr<ListErrorModel> m_errorModel; ///< error rate model to corrupt BlockAck at AP MLD
 };
 
@@ -1066,7 +1130,6 @@
     : EmlsrOperationsTestBase("Check EML DL TXOP transmissions (" + std::to_string(nEmlsrStations) +
                               "," + std::to_string(nNonEmlsrStations) + ")"),
       m_emlsrLinks(linksToEnableEmlsrOn),
-      m_assocLinkId(1 + nEmlsrStations + nNonEmlsrStations, std::nullopt),
       m_emlsrEnabledTime(0),
       m_fe2to3delay(MilliSeconds(20)),
       m_countQoSframes(0),
@@ -1075,6 +1138,7 @@
     m_nEmlsrStations = nEmlsrStations;
     m_nNonEmlsrStations = nNonEmlsrStations;
     m_linksToEnableEmlsrOn = {}; // do not enable EMLSR right after association
+    m_mainPhyId = 1;
     m_paddingDelay = paddingDelay;
     m_transitionDelay = transitionDelay;
     m_transitionTimeout = transitionTimeout;
@@ -1086,26 +1150,29 @@
 }
 
 void
-EmlsrDlTxopTest::Transmit(uint8_t linkId,
-                          std::string context,
+EmlsrDlTxopTest::Transmit(Ptr<WifiMac> mac,
+                          uint8_t phyId,
                           WifiConstPsduMap psduMap,
                           WifiTxVector txVector,
                           double txPowerW)
 {
+    EmlsrOperationsTestBase::Transmit(mac, phyId, psduMap, txVector, txPowerW);
+    auto linkId = m_txPsdus.back().linkId;
+
     auto psdu = psduMap.begin()->second;
-    auto nodeId = ContextToNodeId(context);
+    auto nodeId = mac->GetDevice()->GetNode()->GetId();
 
     switch (psdu->GetHeader(0).GetType())
     {
     case WIFI_MAC_MGT_ASSOCIATION_REQUEST:
         NS_ASSERT_MSG(nodeId > 0, "APs do not send AssocReq frames");
-        m_assocLinkId.at(nodeId) = linkId;
         if (nodeId <= m_nEmlsrStations)
         {
+            NS_TEST_EXPECT_MSG_EQ(+linkId, +m_mainPhyId, "AssocReq not sent by the main PHY");
             // this AssocReq is being sent by an EMLSR client. The other EMLSR links should be
             // in powersave mode after association; we let the non-EMLSR links transition to
             // active mode (by sending data null frames) after association
-            for (uint8_t id = 0; id < m_staMacs.at(nodeId - 1)->GetNLinks(); id++)
+            for (const auto id : m_staMacs.at(nodeId - 1)->GetLinkIds())
             {
                 if (id != linkId && m_emlsrLinks.count(id) == 1)
                 {
@@ -1141,13 +1208,11 @@
         break;
 
     case WIFI_MAC_CTL_BACKRESP:
-        CheckBlockAck(psduMap, txVector, linkId);
+        CheckBlockAck(psduMap, txVector, phyId);
         break;
 
     default:;
     }
-
-    EmlsrOperationsTestBase::Transmit(linkId, context, psduMap, txVector, txPowerW);
 }
 
 void
@@ -1222,7 +1287,7 @@
 
         Simulator::Schedule(m_fe2to3delay + MilliSeconds(5 * (m_nEmlsrStations + 1)), [=]() {
             m_apMac->GetDevice()->GetNode()->AddApplication(
-                GetApplication(DOWNLINK, id, 8 / m_nEmlsrStations, 450));
+                GetApplication(DOWNLINK, id, 8 / m_nEmlsrStations, 650));
         });
     }
 }
@@ -1358,15 +1423,13 @@
         auto setupLinks = m_staMacs[i]->GetSetupLinkIds();
         if (i < m_nEmlsrStations &&
             std::none_of(setupLinks.begin(), setupLinks.end(), [&](auto&& linkId) {
-                return linkId != *m_assocLinkId[i + 1] && m_emlsrLinks.count(linkId) == 0;
+                return linkId != m_mainPhyId && m_emlsrLinks.count(linkId) == 0;
             }))
         {
             NS_TEST_EXPECT_MSG_EQ(linkIds.size(),
                                   1,
                                   "Expected both A-MPDUs to be sent on the same link");
-            NS_TEST_EXPECT_MSG_EQ(*linkIds.begin(),
-                                  *m_assocLinkId[i + 1],
-                                  "A-MPDUs sent on incorrect link");
+            NS_TEST_EXPECT_MSG_EQ(*linkIds.begin(), +m_mainPhyId, "A-MPDUs sent on incorrect link");
             NS_TEST_EXPECT_MSG_LT(firstAmpduTxEnd,
                                   secondAmpduTxStart,
                                   "A-MPDUs are not sent one after another");
@@ -1638,15 +1701,15 @@
      *                   │CTS│       │BA│       │BA│
      *                   ├───┤       ├──┤       └──┘
      *                   │CTS│       │BA│
-     *                   └───┘       └──┘                      A switches to listening
-     *                                                         after timeout + transition delay
-     *                                                         │
-     *                                     ┌───┐     ┌─────┐   │       ┌───┐
-     *                                     │MU │     │QoS x│   │       │MU │     ┌───┐
-     *  [link 1]                           │RTS│     │ to A│   │       │RTS│     │BAR│
-     *  ───────────────────────────────────┴───┴┬───┬┴─────┴┬──┬───────┴───┴┬───┬┴───┴┬──┬─
-     *                                          │CTS│       │BA│            │CTS│     │BA│
-     *                                          └───┘       └──x            └───┘     └──┘
+     *                   └───┘       └──┘  AP continues the TXOP despite   A switches to listening
+     *                                     the failure, but sends an ICF    after transition delay
+     *                                                                │                       │
+     *                                            ┌───┐     ┌─────┐   │┌───┐              ┌───┐
+     *                                            │MU │     │QoS x│   ││MU │     ┌───┐    │CF-│
+     *  [link 1]                                  │RTS│     │ to A│   ││RTS│     │BAR│    │End│
+     *  ──────────────────────────────────────────┴───┴┬───┬┴─────┴┬──┬┴───┴┬───┬┴───┴┬──┬┴───┴─
+     *                                                 │CTS│       │BA│     │CTS│     │BA│
+     *                                                 └───┘       └──x     └───┘     └──┘
      */
     if (m_nEmlsrStations == 2 && m_apMac->GetNLinks() == m_emlsrLinks.size())
     {
@@ -1766,11 +1829,16 @@
                                                                            phy->GetPhyBand());
         auto timeout = phy->GetSifs() + phy->GetSlot() + MicroSeconds(20);
 
-        // the fourth frame exchange starts a SIFS after the previous one
+        // the fourth frame exchange starts a SIFS after the previous one because the AP can
+        // continue the TXOP despite it does not receive the BlockAck (the AP received the
+        // PHY-RXSTART.indication and the frame exchange involves an EMLSR client)
         NS_TEST_EXPECT_MSG_GT_OR_EQ(fourthExchangeIt->front()->startTx,
-                                    bAckRespTxEnd + timeout +
-                                        m_transitionDelay.at(thirdExchangeStaId),
-                                    "Transmission started before transition delay");
+                                    bAckRespTxEnd + phy->GetSifs(),
+                                    "Transmission started less than a SIFS after BlockAck");
+        NS_TEST_EXPECT_MSG_LT(fourthExchangeIt->front()->startTx,
+                              bAckRespTxEnd + phy->GetSifs() +
+                                  MicroSeconds(1) /* propagation delay upper bound */,
+                              "Transmission started too much time after BlockAck");
 
         auto bAckReqIt = std::next(fourthExchangeIt->front(), 2);
         NS_TEST_EXPECT_MSG_EQ(bAckReqIt->psduMap.cbegin()->second->GetHeader(0).IsBlockAckReq(),
@@ -1846,31 +1914,34 @@
     // (ICF protects the EML Notification response) and two frame exchanges with data frames
     for (std::size_t i = 0; i < m_nEmlsrStations; i++)
     {
-        // if the EML Notification frame disabling EMLSR mode is sent on an EMLSR link, it
-        // is protected by an ICF; otherwise, it is not protected. Given that the default
-        // EMLSR Manager sends EML Notification frames on the link used to establish association,
-        // ICF is sent to protect the EML Notification frame if the link used to establish
-        // association is an EMLSR link
-        if (m_emlsrLinks.count(*m_assocLinkId.at(i + 1)) == 1)
-        {
-            auto firstExchangeIt = frameExchanges.at(i).begin();
+        // 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
+        auto exchangeIt = frameExchanges.at(i).cbegin();
 
-            NS_TEST_EXPECT_MSG_EQ(IsTrigger(firstExchangeIt->front()->psduMap),
-                                  true,
-                                  "Expected an MU-RTS TF as ICF of first frame exchange sequence");
-            NS_TEST_EXPECT_MSG_EQ(firstExchangeIt->size(),
-                                  1,
-                                  "Expected no data frame in the first frame exchange sequence");
+        auto linkIdOpt = m_staMacs[i]->GetLinkForPhy(m_mainPhyId);
+        NS_TEST_ASSERT_MSG_EQ(linkIdOpt.has_value(),
+                              true,
+                              "Didn't find a link on which the main PHY is operating");
 
-            frameExchanges.at(i).pop_front();
-        }
+        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();
 
         NS_TEST_EXPECT_MSG_GT_OR_EQ(frameExchanges.at(i).size(),
                                     2,
                                     "Expected at least 2 frame exchange sequences "
                                         << "involving EMLSR client " << i);
 
-        auto firstExchangeIt = frameExchanges.at(i).begin();
+        auto firstExchangeIt = frameExchanges.at(i).cbegin();
         auto secondExchangeIt = std::next(firstExchangeIt);
 
         const auto firstAmpduTxEnd =
@@ -1897,20 +1968,19 @@
                               1,
                               "Expected one frame only in the second frame exchange sequence");
 
-        if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size() ||
-            m_emlsrLinks.count(*m_assocLinkId.at(i + 1)) == 0)
+        if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
         {
-            // all links are EMLSR links or the non-EMLSR link is the link used for association:
-            // the two QoS data frames are sent one after another on the link used for association
+            // all links are EMLSR links: the two QoS data frames are sent one after another on
+            // the link used for sending EML OMN
             NS_TEST_EXPECT_MSG_EQ(
                 +firstExchangeIt->front()->linkId,
-                +(*m_assocLinkId.at(i + 1)),
-                "First frame exchange expected to occur on link used for association");
+                +linkIdOpt.value(),
+                "First frame exchange expected to occur on link used to send EML OMN");
 
             NS_TEST_EXPECT_MSG_EQ(
                 +secondExchangeIt->front()->linkId,
-                +(*m_assocLinkId.at(i + 1)),
-                "Second frame exchange expected to occur on link used for association");
+                +linkIdOpt.value(),
+                "Second frame exchange expected to occur on link used to send EML OMN");
 
             NS_TEST_EXPECT_MSG_LT(firstAmpduTxEnd,
                                   secondAmpduTxStart,
@@ -1949,8 +2019,8 @@
     // transitioned to active mode instead
     for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
     {
-        bool psModeExpected = *staId < m_nEmlsrStations && linkId != m_assocLinkId.at(*staId + 1) &&
-                              m_emlsrLinks.count(linkId) == 1;
+        bool psModeExpected =
+            *staId < m_nEmlsrStations && linkId != m_mainPhyId && m_emlsrLinks.count(linkId) == 1;
         auto addr = m_staMacs.at(*staId)->GetAddress();
         auto psMode = m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
         NS_TEST_EXPECT_MSG_EQ(psMode,
@@ -1959,18 +2029,14 @@
                                             << " not in " << (psModeExpected ? "PS" : "active")
                                             << " mode");
         // check that AP is blocking transmission of QoS data frames on this link
-        WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, addr, 0);
-        auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, linkId);
-        NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                              true,
-                              "Expected to find a mask for EMLSR link "
-                                  << +linkId << " of EMLSR client " << *staId);
-        auto reason = static_cast<std::size_t>(WifiQueueBlockedReason::POWER_SAVE_MODE);
-        NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
-                              psModeExpected,
-                              "Expected EMLSR link " << +linkId << " of EMLSR client " << *staId
-                                                     << " to be "
-                                                     << (psModeExpected ? "blocked" : "unblocked"));
+        CheckBlockedLink(m_apMac,
+                         addr,
+                         linkId,
+                         WifiQueueBlockedReason::POWER_SAVE_MODE,
+                         psModeExpected,
+                         "Checking PM mode after association on AP MLD for EMLSR client " +
+                             std::to_string(*staId),
+                         false);
     }
 }
 
@@ -1983,7 +2049,7 @@
     auto pkt = mpdu->GetPacket()->Copy();
     const auto& hdr = mpdu->GetHeader();
     WifiActionHeader::Remove(pkt);
-    MgtEmlOperatingModeNotification frame;
+    MgtEmlOmn frame;
     pkt->RemoveHeader(frame);
 
     std::optional<std::size_t> staId;
@@ -2026,18 +2092,15 @@
                                       "EMLSR link " << +linkId << " of EMLSR client " << *staId
                                                     << " not in active mode");
                 // check that AP is not blocking transmission of QoS data frames on this link
-                WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, addr, 0);
-                auto mask =
-                    m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, linkId);
-                NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                      true,
-                                      "Expected to find a mask for EMLSR link "
-                                          << +linkId << " of EMLSR client " << *staId);
-                auto reason = static_cast<std::size_t>(WifiQueueBlockedReason::POWER_SAVE_MODE);
-                NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
-                                      false,
-                                      "Expected EMLSR link " << +linkId << " of EMLSR client "
-                                                             << *staId << " to be unblocked");
+                CheckBlockedLink(
+                    m_apMac,
+                    addr,
+                    linkId,
+                    WifiQueueBlockedReason::POWER_SAVE_MODE,
+                    false,
+                    "Checking EMLSR links on AP MLD after EMLSR mode is enabled on EMLSR client " +
+                        std::to_string(*staId),
+                    false);
             }
         }
         else
@@ -2056,18 +2119,15 @@
                                           << +id << " of EMLSR client " << *staId << " not in "
                                           << (psModeExpected ? "PS" : "active") << " mode");
                 // check that AP is blocking transmission of QoS data frames on this link
-                WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, addr, 0);
-                auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
-                NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                      true,
-                                      "Expected to find a mask for EMLSR link "
-                                          << +id << " of EMLSR client " << *staId);
-                auto reason = static_cast<std::size_t>(WifiQueueBlockedReason::POWER_SAVE_MODE);
-                NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
-                                      psModeExpected,
-                                      "Expected EMLSR link "
-                                          << +id << " of EMLSR client " << *staId << " to be "
-                                          << (psModeExpected ? "blocked" : "unblocked"));
+                CheckBlockedLink(
+                    m_apMac,
+                    addr,
+                    id,
+                    WifiQueueBlockedReason::POWER_SAVE_MODE,
+                    psModeExpected,
+                    "Checking links on AP MLD after EMLSR mode is disabled on EMLSR client " +
+                        std::to_string(*staId),
+                    false);
             }
         }
     });
@@ -2128,53 +2188,28 @@
                     continue;
                 }
 
-                if (id == linkId)
-                {
-                    WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
-                    auto mask =
-                        m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
-                    NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                          true,
-                                          "Expected to find a mask for EMLSR link "
-                                              << +id << " of EMLSR client " << *addr);
-                    NS_TEST_EXPECT_MSG_EQ(mask->none(),
-                                          true,
-                                          "Expected EMLSR link " << +id << " of EMLSR client "
-                                                                 << *addr << " to be unblocked");
-                    continue;
-                }
-
-                WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
-                auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
-                NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                      true,
-                                      "Expected to find a mask for EMLSR link "
-                                          << +id << " of EMLSR client " << *addr);
-                auto reason =
-                    static_cast<std::size_t>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
-                NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
-                                      true,
-                                      "Expected EMLSR link " << +id << " of EMLSR client " << *addr
-                                                             << " to be blocked");
-                NS_TEST_EXPECT_MSG_EQ(mask->count(),
-                                      1,
-                                      "Expected EMLSR link "
-                                          << +id << " of EMLSR client " << *addr
-                                          << " to be blocked for one reason only");
+                CheckBlockedLink(m_apMac,
+                                 *addr,
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 id != linkId,
+                                 "Checking that AP blocked transmissions on all other EMLSR "
+                                 "links after sending ICF to client with AID=" +
+                                     std::to_string(userInfo.GetAid12()));
             }
         }
     }
 
     NS_TEST_EXPECT_MSG_EQ(found, true, "Expected ICF to be addressed to at least an EMLSR client");
 
+    auto txDuration = WifiPhy::CalculateTxDuration(mpdu->GetSize(),
+                                                   txVector,
+                                                   m_apMac->GetWifiPhy(linkId)->GetPhyBand());
+
     if (maxPaddingDelay.IsStrictlyPositive())
     {
         // compare the TX duration of this Trigger Frame to that of the Trigger Frame with no
         // padding added
-        auto txDurationWith =
-            WifiPhy::CalculateTxDuration(mpdu->GetSize(),
-                                         txVector,
-                                         m_apMac->GetWifiPhy(linkId)->GetPhyBand());
         trigger.SetPaddingSize(0);
         auto pkt = Create<Packet>();
         pkt->AddHeader(trigger);
@@ -2183,11 +2218,40 @@
                                          txVector,
                                          m_apMac->GetWifiPhy(linkId)->GetPhyBand());
 
-        NS_TEST_EXPECT_MSG_EQ(txDurationWith,
+        NS_TEST_EXPECT_MSG_EQ(txDuration,
                               txDurationWithout + maxPaddingDelay,
                               "Unexpected TX duration of the MU-RTS TF with padding "
                                   << maxPaddingDelay.As(Time::US));
     }
+
+    // check that the EMLSR clients have blocked transmissions on other links after
+    // receiving this ICF
+    for (const auto& userInfo : trigger)
+    {
+        for (std::size_t i = 0; i < m_nEmlsrStations; i++)
+        {
+            if (m_staMacs[i]->GetAssociationId() != userInfo.GetAid12())
+            {
+                continue;
+            }
+
+            Simulator::Schedule(txDuration + NanoSeconds(5), [=]() {
+                for (uint8_t id = 0; id < m_staMacs[i]->GetNLinks(); id++)
+                {
+                    // non-EMLSR links or links on which ICF is received are not blocked
+                    CheckBlockedLink(m_staMacs[i],
+                                     m_apMac->GetAddress(),
+                                     id,
+                                     WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                     id != linkId && m_staMacs[i]->IsEmlsrLink(id),
+                                     "Checking EMLSR links on EMLSR client " + std::to_string(i) +
+                                         " after receiving ICF");
+                }
+            });
+
+            break;
+        }
+    }
 }
 
 void
@@ -2217,80 +2281,95 @@
         // generate another small packet addressed to the first EMLSR client only
         m_apMac->GetDevice()->GetNode()->AddApplication(
             GetApplication(DOWNLINK, firstClientId, 1, 40));
+        // both EMLSR clients are about to receive a QoS data frame
+        for (std::size_t clientId : {firstClientId, secondClientId})
+        {
+            Simulator::Schedule(txDuration, [=]() {
+                for (uint8_t id = 0; id < m_staMacs[clientId]->GetNLinks(); id++)
+                {
+                    // link on which QoS data is received is not blocked
+                    CheckBlockedLink(m_staMacs[clientId],
+                                     m_apMac->GetAddress(),
+                                     id,
+                                     WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                     id != linkId,
+                                     "Checking EMLSR links on EMLSR client " +
+                                         std::to_string(clientId) +
+                                         " after receiving the first QoS data frame");
+                }
+            });
+        }
         break;
     case 2:
         // generate another small packet addressed to the second EMLSR client
         m_apMac->GetDevice()->GetNode()->AddApplication(
             GetApplication(DOWNLINK, secondClientId, 1, 40));
 
+        // when the transmission of the second QoS data frame starts, both EMLSR clients are
+        // still blocking all the links but the one used to receive the QoS data frame
+        for (std::size_t clientId : {firstClientId, secondClientId})
+        {
+            for (uint8_t id = 0; id < m_staMacs[clientId]->GetNLinks(); id++)
+            {
+                // link on which QoS data is received is not blocked
+                CheckBlockedLink(m_staMacs[clientId],
+                                 m_apMac->GetAddress(),
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 id != linkId,
+                                 "Checking EMLSR links on EMLSR client " +
+                                     std::to_string(clientId) +
+                                     " when starting the reception of the second QoS frame");
+            }
+        }
+
         // the EMLSR client that is not the recipient of the QoS frame being transmitted will
         // switch back to listening mode after a transition delay starting from the end of
         // the PPDU carrying this QoS data frame
 
-        // immediately before the end of the PPDU, this link is not blocked for the EMLSR client
+        // immediately before the end of the PPDU, this link only is not blocked for the EMLSR
+        // client on the AP MLD
         Simulator::Schedule(txDuration - NanoSeconds(1), [=]() {
-            WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, addr, 0);
-            auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, linkId);
-            NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                  true,
-                                  "Expected to find a mask for EMLSR link "
-                                      << +linkId << " of EMLSR client " << secondClientId);
-            NS_TEST_EXPECT_MSG_EQ(mask->none(),
-                                  true,
-                                  "Expected EMLSR link " << +linkId << " of EMLSR client "
-                                                         << secondClientId << " to be unblocked");
+            for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+            {
+                CheckBlockedLink(m_apMac,
+                                 addr,
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 id != linkId,
+                                 "Checking that links of EMLSR client " +
+                                     std::to_string(secondClientId) +
+                                     " are blocked on the AP MLD before the end of the PPDU");
+            }
         });
-        // immediately before the end of the PPDU, the other links are blocked for the EMLSR client
+        // immediately before the end of the PPDU, all the links on the EMLSR client that is not
+        // the recipient of the second QoS frame are unblocked (they are unblocked when the
+        // PHY-RXSTART.indication is not received)
         Simulator::Schedule(txDuration - NanoSeconds(1), [=]() {
-            for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+            for (uint8_t id = 0; id < m_staMacs[secondClientId]->GetNLinks(); id++)
             {
-                if (id == linkId)
-                {
-                    continue;
-                }
-
-                WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, addr, 0);
-                auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
-                NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                      true,
-                                      "Expected to find a mask for EMLSR link "
-                                          << +id << " of EMLSR client " << secondClientId);
-                auto reason =
-                    static_cast<std::size_t>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
-                NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
-                                      true,
-                                      "Expected EMLSR link " << +id << " of EMLSR client "
-                                                             << secondClientId << " to be blocked");
-                NS_TEST_EXPECT_MSG_EQ(mask->count(),
-                                      1,
-                                      "Expected EMLSR link " << +id << " of EMLSR client "
-                                                             << secondClientId
-                                                             << " to be blocked "
-                                                                " for one reason only");
+                CheckBlockedLink(m_staMacs[secondClientId],
+                                 m_apMac->GetAddress(),
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 false,
+                                 "Checking that links of EMLSR client " +
+                                     std::to_string(secondClientId) +
+                                     " are unblocked before the end of the second QoS frame");
             }
         });
         // immediately after the end of the PPDU, all links are blocked for the EMLSR client
         Simulator::Schedule(txDuration + NanoSeconds(1), [=]() {
             for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
             {
-                WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, addr, 0);
-                auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
-                NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                      true,
-                                      "Expected to find a mask for EMLSR link "
-                                          << +id << " of EMLSR client " << secondClientId);
-                auto reason = static_cast<std::size_t>(
-                    WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY);
-                NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
-                                      true,
-                                      "Expected EMLSR link " << +id << " of EMLSR client "
-                                                             << secondClientId << " to be blocked");
-                NS_TEST_EXPECT_MSG_EQ(mask->count(),
-                                      1,
-                                      "Expected EMLSR link " << +id << " of EMLSR client "
-                                                             << secondClientId
-                                                             << " to be blocked "
-                                                                " for one reason only");
+                CheckBlockedLink(m_apMac,
+                                 addr,
+                                 id,
+                                 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
+                                 true,
+                                 "Checking links of EMLSR client " +
+                                     std::to_string(secondClientId) +
+                                     " are all blocked on the AP MLD after the end of the PPDU");
             }
         });
         // immediately before the transition delay, all links are still blocked for the EMLSR client
@@ -2299,37 +2378,42 @@
             [=]() {
                 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
                 {
-                    WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, addr, 0);
-                    auto mask =
-                        m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
-                    NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                          true,
-                                          "Expected to find a mask for EMLSR link "
-                                              << +id << " of EMLSR client " << secondClientId);
-                    auto reason = static_cast<std::size_t>(
-                        WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY);
-                    NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
-                                          true,
-                                          "Expected EMLSR link " << +id << " of EMLSR client "
-                                                                 << secondClientId
-                                                                 << " to be blocked");
-                    NS_TEST_EXPECT_MSG_EQ(mask->count(),
-                                          1,
-                                          "Expected EMLSR link " << +id << " of EMLSR client "
-                                                                 << secondClientId
-                                                                 << " to be blocked "
-                                                                    " for one reason only");
+                    CheckBlockedLink(
+                        m_apMac,
+                        addr,
+                        id,
+                        WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
+                        true,
+                        "Checking links of EMLSR client " + std::to_string(secondClientId) +
+                            " are all blocked on the AP MLD before the transition delay");
                 }
             });
 
         break;
+    case 3:
+        // at the end of the third QoS frame, this link only is not blocked on the EMLSR
+        // client receiving the frame
+        Simulator::Schedule(txDuration, [=]() {
+            for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+            {
+                CheckBlockedLink(m_staMacs[secondClientId],
+                                 m_apMac->GetAddress(),
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 id != linkId,
+                                 "Checking EMLSR links on EMLSR client " +
+                                     std::to_string(secondClientId) +
+                                     " after receiving the third QoS data frame");
+            }
+        });
+        break;
     }
 }
 
 void
 EmlsrDlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
                                const WifiTxVector& txVector,
-                               uint8_t linkId)
+                               uint8_t phyId)
 {
     if (m_nEmlsrStations != 2 || m_apMac->GetNLinks() != m_emlsrLinks.size() ||
         m_emlsrEnabledTime.IsZero() || Simulator::Now() < m_emlsrEnabledTime + m_fe2to3delay)
@@ -2351,142 +2435,181 @@
                               "Unexpected TA for BlockAck: " << taddr);
         clientId = 1;
     }
+
+    // find the link on which the main PHY is operating
+    auto currMainPhyLinkId = m_staMacs[clientId]->GetLinkForPhy(phyId);
+    NS_TEST_ASSERT_MSG_EQ(
+        currMainPhyLinkId.has_value(),
+        true,
+        "Didn't find the link on which the PHY sending the BlockAck is operating");
+    auto linkId = *currMainPhyLinkId;
+
     // we need the MLD address to check the status of the container queues
     auto addr = m_apMac->GetWifiRemoteStationManager(linkId)->GetMldAddress(taddr);
     NS_TEST_ASSERT_MSG_EQ(addr.has_value(), true, "MLD address not found for " << taddr);
 
     auto apPhy = m_apMac->GetWifiPhy(linkId);
     auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, apPhy->GetPhyBand());
-    auto timeout = apPhy->GetSifs() + apPhy->GetSlot() + MicroSeconds(20);
+    auto cfEndTxDuration = WifiPhy::CalculateTxDuration(
+        Create<WifiPsdu>(Create<Packet>(), WifiMacHeader(WIFI_MAC_CTL_END)),
+        m_apMac->GetWifiRemoteStationManager(linkId)->GetRtsTxVector(Mac48Address::GetBroadcast()),
+        apPhy->GetPhyBand());
 
     m_countBlockAck++;
 
     switch (m_countBlockAck)
     {
     case 4:
-        // at the end of the PPDU carrying this BlockAck, the EMLSR client sending this
-        // frame will start a timeout interval, after which it will start the transition to
-        // the listening mode (such transition lasting the transition delay)
-
-        // immediately before the end of the PPDU plus timeout, this link is not blocked
-        // for the EMLSR client
-        Simulator::Schedule(txDuration + timeout - NanoSeconds(1), [=]() {
-            WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
-            auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, linkId);
-            NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                  true,
-                                  "Expected to find a mask for EMLSR link "
-                                      << +linkId << " of EMLSR client " << clientId);
-            NS_TEST_EXPECT_MSG_EQ(mask->none(),
-                                  true,
-                                  "Expected EMLSR link " << +linkId << " of EMLSR client "
-                                                         << clientId << " to be unblocked");
+        // the PPDU carrying this BlockAck is corrupted, hence the AP MLD MAC receives the
+        // PHY-RXSTART indication but it does not receive any frame from the PHY. Therefore,
+        // at the end of the PPDU transmission, the AP MLD realizes that the EMLSR client has
+        // not responded and makes an attempt at continuing the TXOP
+
+        // at the end of the PPDU, this link only is not blocked on both the EMLSR client and
+        // the AP MLD
+        Simulator::Schedule(txDuration, [=]() {
+            for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+            {
+                CheckBlockedLink(m_staMacs[clientId],
+                                 m_apMac->GetAddress(),
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 id != linkId,
+                                 "Checking links on EMLSR client " + std::to_string(clientId) +
+                                     " at the end of fourth BlockAck");
+                CheckBlockedLink(m_apMac,
+                                 *addr,
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 id != linkId,
+                                 "Checking links of EMLSR client " + std::to_string(clientId) +
+                                     " on the AP MLD at the end of fourth BlockAck");
+            }
         });
-        // immediately before the end of the PPDU plus timeout, the other links are blocked
-        // for the EMLSR client
-        Simulator::Schedule(txDuration + timeout - NanoSeconds(1), [=]() {
+        // a SIFS after the end of the PPDU, still this link only is not blocked on both the
+        // EMLSR client and the AP MLD
+        Simulator::Schedule(txDuration + apPhy->GetSifs(), [=]() {
             for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
             {
-                if (id == linkId)
-                {
-                    continue;
-                }
-
-                WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
-                auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
-                NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                      true,
-                                      "Expected to find a mask for EMLSR link "
-                                          << +id << " of EMLSR client " << clientId);
-                auto reason =
-                    static_cast<std::size_t>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
-                NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
-                                      true,
-                                      "Expected EMLSR link " << +id << " of EMLSR client "
-                                                             << clientId << " to be blocked");
-                NS_TEST_EXPECT_MSG_EQ(mask->count(),
-                                      1,
-                                      "Expected EMLSR link " << +id << " of EMLSR client "
-                                                             << clientId
-                                                             << " to be blocked "
-                                                                " for one reason only");
+                CheckBlockedLink(m_staMacs[clientId],
+                                 m_apMac->GetAddress(),
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 id != linkId,
+                                 "Checking links on EMLSR client " + std::to_string(clientId) +
+                                     " a SIFS after the end of fourth BlockAck");
+                CheckBlockedLink(m_apMac,
+                                 *addr,
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 id != linkId,
+                                 "Checking links of EMLSR client " + std::to_string(clientId) +
+                                     " a SIFS after the end of fourth BlockAck");
             }
         });
-        // immediately after the end of the PPDU plus timeout, all links are blocked for the EMLSR
-        // client
-        Simulator::Schedule(txDuration + timeout + MicroSeconds(1), [=]() {
+        // corrupt this BlockAck so that the AP MLD sends a BlockAckReq later on
+        {
+            auto uid = psduMap.cbegin()->second->GetPacket()->GetUid();
+            m_errorModel->SetList({uid});
+        }
+        break;
+    case 5:
+        // at the end of the PPDU, this link only is not blocked on both the EMLSR client and
+        // the AP MLD
+        Simulator::Schedule(txDuration, [=]() {
             for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
             {
-                WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
-                auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
-                NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                      true,
-                                      "Expected to find a mask for EMLSR link "
-                                          << +id << " of EMLSR client " << clientId);
-                auto reason = static_cast<std::size_t>(
-                    WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY);
-                NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
-                                      true,
-                                      "Expected EMLSR link " << +id << " of EMLSR client "
-                                                             << clientId << " to be blocked");
-                NS_TEST_EXPECT_MSG_EQ(mask->count(),
-                                      1,
-                                      "Expected EMLSR link " << +id << " of EMLSR client "
-                                                             << clientId
-                                                             << " to be blocked "
-                                                                " for one reason only");
+                CheckBlockedLink(m_staMacs[clientId],
+                                 m_apMac->GetAddress(),
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 id != linkId,
+                                 "Checking links on EMLSR client " + std::to_string(clientId) +
+                                     " at the end of fifth BlockAck");
+                CheckBlockedLink(m_apMac,
+                                 *addr,
+                                 id,
+                                 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                 id != linkId,
+                                 "Checking links of EMLSR client " + std::to_string(clientId) +
+                                     " on the AP MLD at the end of fifth BlockAck");
             }
         });
-        // immediately before the transition delay, all links are still blocked for the EMLSR client
+        // before the end of the CF-End frame, still this link only is not blocked on both the
+        // EMLSR client and the AP MLD
         Simulator::Schedule(
-            txDuration + timeout + m_transitionDelay.at(clientId) - NanoSeconds(1),
+            txDuration + apPhy->GetSifs() + cfEndTxDuration - MicroSeconds(1),
             [=]() {
                 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
                 {
-                    WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
-                    auto mask =
-                        m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
-                    NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                          true,
-                                          "Expected to find a mask for EMLSR link "
-                                              << +id << " of EMLSR client " << clientId);
-                    auto reason = static_cast<std::size_t>(
-                        WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY);
-                    NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
-                                          true,
-                                          "Expected EMLSR link " << +id << " of EMLSR client "
-                                                                 << clientId << " to be blocked");
-                    NS_TEST_EXPECT_MSG_EQ(mask->count(),
-                                          1,
-                                          "Expected EMLSR link " << +id << " of EMLSR client "
-                                                                 << clientId
-                                                                 << " to be blocked "
-                                                                    " for one reason only");
+                    CheckBlockedLink(m_staMacs[clientId],
+                                     m_apMac->GetAddress(),
+                                     id,
+                                     WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                     id != linkId,
+                                     "Checking links on EMLSR client " + std::to_string(clientId) +
+                                         " before the end of CF-End frame");
+                    CheckBlockedLink(m_apMac,
+                                     *addr,
+                                     id,
+                                     WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                     id != linkId,
+                                     "Checking links of EMLSR client " + std::to_string(clientId) +
+                                         " on the AP MLD before the end of CF-End frame");
                 }
             });
-        // immediately after the transition delay, all links are unblocked for the EMLSR client
+        // after the end of the CF-End frame, all links for the EMLSR client are blocked on the
+        // AP MLD
         Simulator::Schedule(
-            txDuration + timeout + m_transitionDelay.at(clientId) + MicroSeconds(1),
+            txDuration + apPhy->GetSifs() + cfEndTxDuration + MicroSeconds(1),
             [=]() {
                 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
                 {
-                    WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
-                    auto mask =
-                        m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
-                    NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
-                                          true,
-                                          "Expected to find a mask for EMLSR link "
-                                              << +id << " of EMLSR client " << clientId);
-                    NS_TEST_EXPECT_MSG_EQ(mask->none(),
-                                          true,
-                                          "Expected EMLSR link " << +id << " of EMLSR client "
-                                                                 << clientId << " to be unblocked");
+                    CheckBlockedLink(
+                        m_apMac,
+                        *addr,
+                        id,
+                        WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
+                        true,
+                        "Checking links of EMLSR client " + std::to_string(clientId) +
+                            " 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(
+            txDuration + apPhy->GetSifs() + cfEndTxDuration + m_transitionDelay.at(clientId) -
+                MicroSeconds(1),
+            [=]() {
+                for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+                {
+                    CheckBlockedLink(
+                        m_apMac,
+                        *addr,
+                        id,
+                        WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
+                        true,
+                        "Checking links of EMLSR client " + std::to_string(clientId) +
+                            " 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(
+            txDuration + apPhy->GetSifs() + cfEndTxDuration + m_transitionDelay.at(clientId) +
+                MicroSeconds(1),
+            [=]() {
+                for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+                {
+                    CheckBlockedLink(
+                        m_apMac,
+                        *addr,
+                        id,
+                        WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
+                        false,
+                        "Checking links of EMLSR client " + std::to_string(clientId) +
+                            " are all unblocked on the AP MLD after the transition delay");
                 }
             });
-
-        // corrupt this BlockAck so that the AP MLD sends a BlockAckReq later on
-        auto uid = psduMap.cbegin()->second->GetPacket()->GetUid();
-        m_errorModel->SetList({uid});
         break;
     }
 }
@@ -2506,6 +2629,449 @@
  * \ingroup wifi-test
  * \ingroup tests
  *
+ * \brief Test the switching of PHYs on EMLSR clients.
+ *
+ * An AP MLD and an EMLSR client setup 3 links, on which EMLSR mode is enabled. The AP MLD
+ * transmits 4 QoS data frames (one after another, each protected by ICF):
+ *
+ * - the first one on the link used for ML setup, hence no PHY switch occurs
+ * - the second one on another link, thus causing the main PHY to switch link
+ * - the third one on the remaining link, thus causing the main PHY to switch link again
+ * - the fourth one on the link used for ML setup; if the aux PHYs switches link, there is
+ *   one aux PHY listening on such a link and the main PHY switches to this link, otherwise
+ *   no PHY is listening on such a link and there is no response to the ICF sent by the AP MLD
+ */
+class EmlsrLinkSwitchTest : public EmlsrOperationsTestBase
+{
+  public:
+    /**
+     * Constructor
+     *
+     * \param switchAuxPhy 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
+     * \param resetCamState whether to reset the state of the ChannelAccessManager associated with
+                            the link on which the main PHY has just switched to
+        \param auxPhyMaxChWidth max channel width (MHz) supported by aux PHYs
+     */
+    EmlsrLinkSwitchTest(bool switchAuxPhy, bool resetCamState, uint16_t auxPhyMaxChWidth);
+
+    ~EmlsrLinkSwitchTest() override = default;
+
+  protected:
+    void DoSetup() override;
+    void DoRun() override;
+    void Transmit(Ptr<WifiMac> mac,
+                  uint8_t phyId,
+                  WifiConstPsduMap psduMap,
+                  WifiTxVector txVector,
+                  double txPowerW) override;
+
+    /**
+     * Check that the simulation produced the expected results.
+     */
+    void CheckResults();
+
+    /**
+     * Check that the Main PHY (and possibly the Aux PHY) correctly switches channel when the
+     * reception of an ICF ends.
+     *
+     * \param psduMap the PSDU carrying the MU-RTS TF
+     * \param txVector the TXVECTOR used to send the PPDU
+     * \param linkId the ID of the given link
+     */
+    void CheckInitialControlFrame(const WifiConstPsduMap& psduMap,
+                                  const WifiTxVector& txVector,
+                                  uint8_t linkId);
+
+    /**
+     * Check that appropriate actions are taken by the AP MLD transmitting a PPDU containing
+     * QoS data frames to the EMLSR client on the given link.
+     *
+     * \param psduMap the PSDU(s) carrying QoS data frames
+     * \param txVector the TXVECTOR used to send the PPDU
+     * \param linkId the ID of the given link
+     */
+    void CheckQosFrames(const WifiConstPsduMap& psduMap,
+                        const WifiTxVector& txVector,
+                        uint8_t linkId);
+
+  private:
+    bool m_switchAuxPhy;  /**< whether AUX PHY should switch channel to operate on the link on which
+                               the Main PHY was operating before moving to the link of Aux PHY */
+    bool m_resetCamState; /**< whether to reset the state of the ChannelAccessManager associated
+                               with the link on which the main PHY has just switched to */
+    uint16_t m_auxPhyMaxChWidth;  //!< max channel width (MHz) supported by aux PHYs
+    std::size_t m_countQoSframes; //!< counter for QoS data frames
+    std::size_t m_txPsdusPos;     //!< a position in the vector of TX PSDUs
+};
+
+EmlsrLinkSwitchTest::EmlsrLinkSwitchTest(bool switchAuxPhy,
+                                         bool resetCamState,
+                                         uint16_t auxPhyMaxChWidth)
+    : EmlsrOperationsTestBase(std::string("Check EMLSR link switching (switchAuxPhy=") +
+                              std::to_string(switchAuxPhy) +
+                              ", resetCamState=" + std::to_string(resetCamState) +
+                              ", auxPhyMaxChWidth=" + std::to_string(auxPhyMaxChWidth) + "MHz )"),
+      m_switchAuxPhy(switchAuxPhy),
+      m_resetCamState(resetCamState),
+      m_auxPhyMaxChWidth(auxPhyMaxChWidth),
+      m_countQoSframes(0),
+      m_txPsdusPos(0)
+{
+    m_nEmlsrStations = 1;
+    m_nNonEmlsrStations = 0;
+    m_linksToEnableEmlsrOn = {0, 1, 2}; // enable EMLSR on all links right after association
+    m_mainPhyId = 1;
+    m_establishBaDl = true;
+    m_duration = Seconds(1.0);
+}
+
+void
+EmlsrLinkSwitchTest::Transmit(Ptr<WifiMac> mac,
+                              uint8_t phyId,
+                              WifiConstPsduMap psduMap,
+                              WifiTxVector txVector,
+                              double txPowerW)
+{
+    EmlsrOperationsTestBase::Transmit(mac, phyId, psduMap, txVector, txPowerW);
+    auto linkId = m_txPsdus.back().linkId;
+
+    auto psdu = psduMap.begin()->second;
+    auto nodeId = mac->GetDevice()->GetNode()->GetId();
+
+    switch (psdu->GetHeader(0).GetType())
+    {
+    case WIFI_MAC_MGT_ASSOCIATION_REQUEST:
+        NS_ASSERT_MSG(nodeId > 0, "APs do not send AssocReq frames");
+        NS_TEST_EXPECT_MSG_EQ(+linkId, +m_mainPhyId, "AssocReq not sent by the main PHY");
+        break;
+
+    case WIFI_MAC_MGT_ACTION: {
+        auto [category, action] = WifiActionHeader::Peek(psdu->GetPayload(0));
+
+        if (nodeId == 1 && category == WifiActionHeader::PROTECTED_EHT &&
+            action.protectedEhtAction ==
+                WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
+        {
+            // the EMLSR client is starting the transmission of the EML OMN frame;
+            // temporarily block transmissions of QoS data frames from the AP MLD to the
+            // non-AP MLD on all the links but the one used for ML setup, so that we know
+            // that the first QoS data frame is sent on the link of the main PHY
+            std::set<uint8_t> linksToBlock;
+            for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+            {
+                if (id != m_mainPhyId)
+                {
+                    linksToBlock.insert(id);
+                }
+            }
+            m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
+                                                         AC_BE,
+                                                         {WIFI_QOSDATA_QUEUE},
+                                                         m_staMacs[0]->GetAddress(),
+                                                         m_apMac->GetAddress(),
+                                                         {0},
+                                                         linksToBlock);
+        }
+        else if (category == WifiActionHeader::BLOCK_ACK &&
+                 action.blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE)
+        {
+            // store the current number of transmitted frame
+            m_txPsdusPos = m_txPsdus.size() - 1;
+        }
+    }
+    break;
+
+    case WIFI_MAC_CTL_TRIGGER:
+        CheckInitialControlFrame(psduMap, txVector, linkId);
+        break;
+
+    case WIFI_MAC_QOSDATA:
+        CheckQosFrames(psduMap, txVector, linkId);
+        break;
+
+    default:;
+    }
+}
+
+void
+EmlsrLinkSwitchTest::DoSetup()
+{
+    Config::SetDefault("ns3::DefaultEmlsrManager::SwitchAuxPhy", BooleanValue(m_switchAuxPhy));
+    Config::SetDefault("ns3::EmlsrManager::ResetCamState", BooleanValue(m_resetCamState));
+    Config::SetDefault("ns3::EmlsrManager::AuxPhyChannelWidth", UintegerValue(m_auxPhyMaxChWidth));
+
+    EmlsrOperationsTestBase::DoSetup();
+
+    // use channels of different widths
+    for (auto mac : std::initializer_list<Ptr<WifiMac>>{m_apMac, m_staMacs[0]})
+    {
+        mac->GetWifiPhy(0)->SetOperatingChannel(
+            WifiPhy::ChannelTuple{4, 40, WIFI_PHY_BAND_2_4GHZ, 1});
+        mac->GetWifiPhy(1)->SetOperatingChannel(
+            WifiPhy::ChannelTuple{58, 80, WIFI_PHY_BAND_5GHZ, 3});
+        mac->GetWifiPhy(2)->SetOperatingChannel(
+            WifiPhy::ChannelTuple{79, 160, WIFI_PHY_BAND_6GHZ, 7});
+    }
+}
+
+void
+EmlsrLinkSwitchTest::DoRun()
+{
+    Simulator::Stop(m_duration);
+    Simulator::Run();
+
+    CheckResults();
+
+    Simulator::Destroy();
+}
+
+void
+EmlsrLinkSwitchTest::CheckQosFrames(const WifiConstPsduMap& psduMap,
+                                    const WifiTxVector& txVector,
+                                    uint8_t linkId)
+{
+    m_countQoSframes++;
+
+    switch (m_countQoSframes)
+    {
+    case 1:
+        // unblock transmissions on all links
+        m_apMac->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
+                                                       AC_BE,
+                                                       {WIFI_QOSDATA_QUEUE},
+                                                       m_staMacs[0]->GetAddress(),
+                                                       m_apMac->GetAddress(),
+                                                       {0},
+                                                       {0, 1, 2});
+        // block transmissions on the link used for ML setup
+        m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
+                                                     AC_BE,
+                                                     {WIFI_QOSDATA_QUEUE},
+                                                     m_staMacs[0]->GetAddress(),
+                                                     m_apMac->GetAddress(),
+                                                     {0},
+                                                     {m_mainPhyId});
+        // generate a new data packet, which will be sent on a link other than the one
+        // used for ML setup, hence triggering a link switching on the EMLSR client
+        m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication(DOWNLINK, 0, 2, 1000));
+        break;
+    case 2:
+        // block transmission on the link used to send this QoS data frame
+        m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
+                                                     AC_BE,
+                                                     {WIFI_QOSDATA_QUEUE},
+                                                     m_staMacs[0]->GetAddress(),
+                                                     m_apMac->GetAddress(),
+                                                     {0},
+                                                     {linkId});
+        // generate a new data packet, which will be sent on the link that has not been used
+        // so far, hence triggering another link switching on the EMLSR client
+        m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication(DOWNLINK, 0, 2, 1000));
+        break;
+    case 3:
+        // block transmission on the link used to send this QoS data frame
+        m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
+                                                     AC_BE,
+                                                     {WIFI_QOSDATA_QUEUE},
+                                                     m_staMacs[0]->GetAddress(),
+                                                     m_apMac->GetAddress(),
+                                                     {0},
+                                                     {linkId});
+        // unblock transmissions on the link used for ML setup
+        m_apMac->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
+                                                       AC_BE,
+                                                       {WIFI_QOSDATA_QUEUE},
+                                                       m_staMacs[0]->GetAddress(),
+                                                       m_apMac->GetAddress(),
+                                                       {0},
+                                                       {m_mainPhyId});
+        // generate a new data packet, which will be sent again on the link used for ML setup,
+        // hence triggering yet another link switching on the EMLSR client
+        m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication(DOWNLINK, 0, 2, 1000));
+        break;
+    }
+}
+
+/**
+ * AUX PHY switching enabled
+ *
+ *  |--------- aux PHY A ---------|------ main PHY ------|-------------- aux PHY B --------------
+ *                            ┌───┐     ┌───┐
+ *                            │ICF│     │QoS│
+ *  ──────────────────────────┴───┴┬───┬┴───┴┬──┬────────────────────────────────────────────────
+ *  [link 0]                       │CTS│     │BA│
+ *                                 └───┘     └──┘
+ *
+ *
+ *  |--------- main PHY ----------|------------------ aux PHY A ----------------|--- main PHY ---
+ *     ┌───┐     ┌───┐                                                      ┌───┐     ┌───┐
+ *     │ICF│     │QoS│                                                      │ICF│     │QoS│
+ *  ───┴───┴┬───┬┴───┴┬──┬──────────────────────────────────────────────────┴───┴┬───┬┴───┴┬──┬──
+ *  [link 1]│CTS│     │BA│                                                       │CTS│     │BA│
+ *          └───┘     └──┘                                                       └───┘     └──┘
+ *
+ *
+ *  |--------------------- aux PHY B --------------------|------ main PHY ------|-- aux PHY A ---
+ *                                                   ┌───┐     ┌───┐
+ *                                                   │ICF│     │QoS│
+ *  ─────────────────────────────────────────────────┴───┴┬───┬┴───┴┬──┬─────────────────────────
+ *  [link 2]                                              │CTS│     │BA│
+ *                                                        └───┘     └──┘
+ *
+ *
+ * AUX PHY switching disabled
+ *
+ *  |--------- aux PHY A ---------|------ main PHY ------|
+ *                            ┌───┐     ┌───┐
+ *                            │ICF│     │QoS│
+ *  ──────────────────────────┴───┴┬───┬┴───┴┬──┬────────────────────────────────────────────────
+ *  [link 0]                       │CTS│     │BA│
+ *                                 └───┘     └──┘
+ *
+ *
+ *  |--------- main PHY ----------|
+ *     ┌───┐     ┌───┐                                                      ┌───┐  ┌───┐  ┌───┐
+ *     │ICF│     │QoS│                                                      │ICF│  │ICF│  │ICF│
+ *  ───┴───┴┬───┬┴───┴┬──┬──────────────────────────────────────────────────┴───┴──┴───┴──┴───┴──
+ *  [link 1]│CTS│     │BA│
+ *          └───┘     └──┘
+ *
+ *
+ *  |--------------------- aux PHY B --------------------|--------------- main PHY --------------
+ *                                                   ┌───┐     ┌───┐
+ *                                                   │ICF│     │QoS│
+ *  ─────────────────────────────────────────────────┴───┴┬───┬┴───┴┬──┬─────────────────────────
+ *  [link 2]                                              │CTS│     │BA│
+ *                                                        └───┘     └──┘
+ */
+
+void
+EmlsrLinkSwitchTest::CheckInitialControlFrame(const WifiConstPsduMap& psduMap,
+                                              const WifiTxVector& txVector,
+                                              uint8_t linkId)
+{
+    if (m_txPsdusPos == 0)
+    {
+        // the iterator has not been set yet, thus we are not done with the establishment of
+        // the BA agreement
+        return;
+    }
+
+    auto mainPhy = m_staMacs[0]->GetDevice()->GetPhy(m_mainPhyId);
+    auto phyRecvIcf = m_staMacs[0]->GetWifiPhy(linkId); // PHY receiving the ICF
+
+    auto currMainPhyLinkId = m_staMacs[0]->GetLinkForPhy(mainPhy);
+    NS_TEST_ASSERT_MSG_EQ(currMainPhyLinkId.has_value(),
+                          true,
+                          "Didn't find the link on which the Main PHY is operating");
+
+    if (phyRecvIcf && phyRecvIcf != mainPhy)
+    {
+        NS_TEST_EXPECT_MSG_LT_OR_EQ(
+            phyRecvIcf->GetChannelWidth(),
+            m_auxPhyMaxChWidth,
+            "Aux PHY that received ICF is operating on a channel whose width exceeds the limit "
+                << m_countQoSframes);
+    }
+
+    auto txDuration =
+        WifiPhy::CalculateTxDuration(psduMap, txVector, m_apMac->GetWifiPhy(linkId)->GetPhyBand());
+
+    // check that PHYs are operating on the expected link after the reception of the ICF
+    Simulator::Schedule(txDuration + NanoSeconds(1), [=]() {
+        std::size_t nRxOk = m_switchAuxPhy ? 4 : 3; // successfully received ICFs
+
+        if (m_countQoSframes < nRxOk)
+        {
+            // the main PHY must be operating on the link where ICF was sent
+            NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(linkId),
+                                  mainPhy,
+                                  "PHY operating on link where ICF was sent is not the main PHY");
+        }
+
+        // the first ICF is received by the main PHY and no channel switch occurs
+        if (m_countQoSframes == 0)
+        {
+            NS_TEST_EXPECT_MSG_EQ(phyRecvIcf,
+                                  mainPhy,
+                                  "PHY that received the ICF is not the main PHY");
+            return;
+        }
+
+        // the behavior of Aux PHYs depends on whether they switch channel or not
+        if (m_switchAuxPhy)
+        {
+            NS_TEST_EXPECT_MSG_LT(m_countQoSframes, nRxOk, "Unexpected number of ICFs");
+            Simulator::Schedule(phyRecvIcf->GetChannelSwitchDelay(), [=]() {
+                NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(*currMainPhyLinkId),
+                                      phyRecvIcf,
+                                      "PHY operating on link where Main PHY was before switching "
+                                      "channel is not the aux PHY that received the ICF");
+            });
+        }
+        else if (m_countQoSframes < nRxOk)
+        {
+            // the first 3 ICFs are actually received by some PHY
+            NS_TEST_EXPECT_MSG_NE(phyRecvIcf, nullptr, "Expected some PHY to receive the ICF");
+            NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(*currMainPhyLinkId),
+                                  nullptr,
+                                  "No PHY expected to operate on link where Main PHY was "
+                                  "before switching channel");
+        }
+        else
+        {
+            // no PHY received the ICF
+            NS_TEST_EXPECT_MSG_EQ(phyRecvIcf,
+                                  nullptr,
+                                  "Expected no PHY to operate on link where ICF is sent");
+        }
+    });
+}
+
+void
+EmlsrLinkSwitchTest::CheckResults()
+{
+    NS_TEST_ASSERT_MSG_NE(m_txPsdusPos, 0, "BA agreement establishment not completed");
+
+    std::size_t nRxOk = m_switchAuxPhy ? 4 : 3; // successfully received ICFs
+
+    NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(),
+                                m_txPsdusPos + 3 + nRxOk * 4,
+                                "Insufficient number of TX PSDUs");
+
+    // m_txPsdusPos points to ADDBA_RESPONSE, then ACK and then ICF
+    auto psduIt = std::next(m_txPsdus.cbegin(), m_txPsdusPos + 2);
+
+    for (std::size_t i = 0; i < nRxOk; i++)
+    {
+        NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
+                               psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsTrigger()),
+                              true,
+                              "Expected a Trigger Frame (ICF)");
+        psduIt++;
+        NS_TEST_EXPECT_MSG_EQ(
+            (psduIt->psduMap.size() == 1 && psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsCts()),
+            true,
+            "Expected a CTS");
+        psduIt++;
+        NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
+                               psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsQosData()),
+                              true,
+                              "Expected a QoS Data frame");
+        psduIt++;
+        NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
+                               psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsBlockAck()),
+                              true,
+                              "Expected a BlockAck");
+        psduIt++;
+    }
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
  * \brief wifi EMLSR Test Suite
  */
 class WifiEmlsrTestSuite : public TestSuite
@@ -2518,14 +3084,12 @@
     : TestSuite("wifi-emlsr", UNIT)
 {
     AddTestCase(new EmlOperatingModeNotificationTest(), TestCase::QUICK);
-    AddTestCase(new EmlNotificationExchangeTest({1, 2}, MicroSeconds(0)), TestCase::QUICK);
-    AddTestCase(new EmlNotificationExchangeTest({1, 2}, MicroSeconds(2048)), TestCase::QUICK);
-    AddTestCase(new EmlNotificationExchangeTest({0, 1, 2, 3}, MicroSeconds(0)), TestCase::QUICK);
-    AddTestCase(new EmlNotificationExchangeTest({0, 1, 2, 3}, MicroSeconds(2048)), TestCase::QUICK);
-    for (const auto& emlsrLinks : {std::set<uint8_t>{0, 1, 2},
-                                   std::set<uint8_t>{1, 2},
-                                   std::set<uint8_t>{0, 2},
-                                   std::set<uint8_t>{0, 1}})
+    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);
+    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,
@@ -2549,6 +3113,18 @@
                                         MicroSeconds(512)),
                     TestCase::QUICK);
     }
+
+    for (bool switchAuxPhy : {true, false})
+    {
+        for (bool resetCamState : {true, false})
+        {
+            for (uint16_t auxPhyMaxChWidth : {20, 40, 80, 160})
+            {
+                AddTestCase(new EmlsrLinkSwitchTest(switchAuxPhy, resetCamState, auxPhyMaxChWidth),
+                            TestCase::QUICK);
+            }
+        }
+    }
 }
 
 static WifiEmlsrTestSuite g_wifiEmlsrTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-mlo-test.cc ns-3.40/src/wifi/test/wifi-mlo-test.cc
--- ns-3.39/src/wifi/test/wifi-mlo-test.cc	2023-07-05 14:23:48.129428400 -0700
+++ ns-3.40/src/wifi/test/wifi-mlo-test.cc	2023-09-27 13:30:37.926839800 -0700
@@ -19,9 +19,8 @@
 
 #include "ns3/ap-wifi-mac.h"
 #include "ns3/config.h"
-#include "ns3/he-configuration.h"
-#include "ns3/he-frame-exchange-manager.h"
-#include "ns3/he-phy.h"
+#include "ns3/eht-configuration.h"
+#include "ns3/frame-exchange-manager.h"
 #include "ns3/log.h"
 #include "ns3/mgt-headers.h"
 #include "ns3/mobility-helper.h"
@@ -54,6 +53,7 @@
 #include <iomanip>
 #include <optional>
 #include <sstream>
+#include <tuple>
 #include <vector>
 
 using namespace ns3;
@@ -193,6 +193,121 @@
  * \ingroup wifi-test
  * \ingroup tests
  *
+ * Test the WifiMac::SwapLinks() method.
+ */
+class MldSwapLinksTest : public TestCase
+{
+    /**
+     * Test WifiMac subclass used to access the SwapLinks method.
+     */
+    class TestWifiMac : public WifiMac
+    {
+      public:
+        ~TestWifiMac() override = default;
+
+        using WifiMac::GetLinks;
+        using WifiMac::SwapLinks;
+
+        bool CanForwardPacketsTo(Mac48Address to) const override
+        {
+            return true;
+        }
+
+        void Enqueue(Ptr<Packet> packet, Mac48Address to) override
+        {
+        }
+    };
+
+  public:
+    MldSwapLinksTest();
+    ~MldSwapLinksTest() override = default;
+
+  protected:
+    void DoRun() override;
+
+  private:
+    /**
+     * Run a single test case.
+     *
+     * \param text string identifying the test case
+     * \param nLinks the number of links of the MLD
+     * \param links a set of pairs (from, to) each mapping a current link ID to the
+     *              link ID it has to become (i.e., link 'from' becomes link 'to')
+     * \param expected maps each link ID to the id of the PHY that is expected
+     *                 to operate on that link after the swap
+     */
+    void RunOne(std::string text,
+                std::size_t nLinks,
+                const std::map<uint8_t, uint8_t>& links,
+                const std::map<uint8_t, uint8_t>& expected);
+};
+
+MldSwapLinksTest::MldSwapLinksTest()
+    : TestCase("Test the WifiMac::SwapLinks() method")
+{
+}
+
+void
+MldSwapLinksTest::RunOne(std::string text,
+                         std::size_t nLinks,
+                         const std::map<uint8_t, uint8_t>& links,
+                         const std::map<uint8_t, uint8_t>& expected)
+{
+    TestWifiMac mac;
+
+    std::vector<Ptr<WifiPhy>> phys;
+    for (std::size_t i = 0; i < nLinks; i++)
+    {
+        phys.emplace_back(CreateObject<SpectrumWifiPhy>());
+    }
+    mac.SetWifiPhys(phys); // create links containing the given PHYs
+
+    mac.SwapLinks(links);
+
+    NS_TEST_EXPECT_MSG_EQ(mac.GetNLinks(), nLinks, "Number of links changed after swapping");
+
+    for (const auto& [linkId, phyId] : expected)
+    {
+        NS_TEST_ASSERT_MSG_EQ(mac.GetLinks().count(linkId),
+                              1,
+                              "Link ID " << +linkId << " does not exist");
+
+        NS_TEST_ASSERT_MSG_LT(+phyId, nLinks, "Invalid PHY ID");
+
+        // the id of the PHY operating on a link is the original ID of the link
+        NS_TEST_EXPECT_MSG_EQ(mac.GetWifiPhy(linkId),
+                              phys.at(phyId),
+                              text << ": Link " << +phyId << " has not been moved to link "
+                                   << +linkId);
+    }
+}
+
+void
+MldSwapLinksTest::DoRun()
+{
+    RunOne("No change needed", 3, {{0, 0}, {1, 1}, {2, 2}}, {{0, 0}, {1, 1}, {2, 2}});
+    RunOne("Circular swapping", 3, {{0, 2}, {1, 0}, {2, 1}}, {{0, 1}, {1, 2}, {2, 0}});
+    RunOne("Swapping two links, one unchanged", 3, {{0, 2}, {2, 0}}, {{0, 2}, {1, 1}, {2, 0}});
+    RunOne("Non-circular swapping, autodetect how to close the loop",
+           3,
+           {{0, 2}, {2, 1}},
+           {{0, 1}, {1, 2}, {2, 0}});
+    RunOne("One move only, autodetect how to complete the swapping",
+           3,
+           {{2, 0}},
+           {{0, 2}, {1, 1}, {2, 0}});
+    RunOne("Create a new link ID (2), remove the unused one (0)",
+           2,
+           {{0, 1}, {1, 2}},
+           {{1, 0}, {2, 1}});
+    RunOne("One move only that creates a new link ID (2)", 2, {{0, 2}}, {{1, 1}, {2, 0}});
+    RunOne("Move all links to a new set of IDs", 2, {{0, 2}, {1, 3}}, {{2, 0}, {3, 1}});
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
  * \brief Base class for Multi-Link Operations tests
  *
  * Three spectrum channels are created, one for each band (2.4 GHz, 5 GHz and 6 GHz).
@@ -203,37 +318,70 @@
 {
   public:
     /**
+     * Configuration parameters common to all subclasses
+     */
+    struct BaseParams
+    {
+        std::vector<std::string>
+            staChannels; //!< the strings specifying the operating channels for the non-AP MLD
+        std::vector<std::string>
+            apChannels; //!< the strings specifying the operating channels for the AP MLD
+        std::vector<uint8_t>
+            fixedPhyBands; //!< list of IDs of non-AP MLD PHYs that cannot switch band
+    };
+
+    /**
      * Constructor
      *
      * \param name The name of the new TestCase created
      * \param nStations the number of stations to create
-     * \param staChannels the strings specifying the operating channels for the STA
-     * \param apChannels the strings specifying the operating channels for the AP
-     * \param fixedPhyBands list of IDs of STA links that cannot switch PHY band
+     * \param baseParams common configuration parameters
      */
     MultiLinkOperationsTestBase(const std::string& name,
                                 uint8_t nStations,
-                                std::vector<std::string> staChannels,
-                                std::vector<std::string> apChannels,
-                                std::vector<uint8_t> fixedPhyBands = {});
+                                const BaseParams& baseParams);
     ~MultiLinkOperationsTestBase() override = default;
 
   protected:
     /**
      * Callback invoked when a FEM passes PSDUs to the PHY.
      *
-     * \param linkId the ID of the link transmitting the PSDUs
-     * \param context the context
+     * \param mac the MAC transmitting the PSDUs
+     * \param phyId the ID of the PHY transmitting the PSDUs
      * \param psduMap the PSDU map
      * \param txVector the TX vector
      * \param txPowerW the tx power in Watts
      */
-    virtual void Transmit(uint8_t linkId,
-                          std::string context,
+    virtual void Transmit(Ptr<WifiMac> mac,
+                          uint8_t phyId,
                           WifiConstPsduMap psduMap,
                           WifiTxVector txVector,
                           double txPowerW);
 
+    /**
+     * Function to trace packets received by the server application
+     * \param nodeId the ID of the node that received the packet
+     * \param p the packet
+     * \param addr the address
+     */
+    virtual void L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr);
+
+    /**
+     * \param sockAddr the packet socket address identifying local outgoing interface
+     *                 and remote address
+     * \param count the number of packets to generate
+     * \param pktSize the size of the packets to generate
+     * \param delay the delay with which traffic generation starts
+     * \param priority user priority for generated packets
+     * \return an application generating the given number packets of the given size destined
+     *         to the given packet socket address
+     */
+    Ptr<PacketSocketClient> GetApplication(const PacketSocketAddress& sockAddr,
+                                           std::size_t count,
+                                           std::size_t pktSize,
+                                           Time delay = Seconds(0),
+                                           uint8_t priority = 0) const;
+
     void DoSetup() override;
 
     /// PHY band-indexed map of spectrum channels
@@ -264,6 +412,7 @@
         WifiConstPsduMap psduMap; ///< transmitted PSDU map
         WifiTxVector txVector;    ///< TXVECTOR
         uint8_t linkId;           ///< link ID
+        uint8_t phyId;            ///< ID of the transmitting PHY
     };
 
     std::vector<FrameInfo> m_txPsdus;             ///< transmitted PSDUs
@@ -274,6 +423,9 @@
     std::vector<Ptr<StaWifiMac>> m_staMacs;       ///< STA wifi MACs
     uint8_t m_nStations;                          ///< number of stations to create
     uint16_t m_lastAid;                           ///< AID of last associated station
+    Time m_duration{Seconds(1)};                  ///< simulation duration
+    std::vector<std::size_t> m_rxPkts; ///< number of packets received at application layer
+                                       ///< by each node (index is node ID)
 
   private:
     /**
@@ -308,16 +460,15 @@
 
 MultiLinkOperationsTestBase::MultiLinkOperationsTestBase(const std::string& name,
                                                          uint8_t nStations,
-                                                         std::vector<std::string> staChannels,
-                                                         std::vector<std::string> apChannels,
-                                                         std::vector<uint8_t> fixedPhyBands)
+                                                         const BaseParams& baseParams)
     : TestCase(name),
-      m_staChannels(staChannels),
-      m_apChannels(apChannels),
-      m_fixedPhyBands(fixedPhyBands),
+      m_staChannels(baseParams.staChannels),
+      m_apChannels(baseParams.apChannels),
+      m_fixedPhyBands(baseParams.fixedPhyBands),
       m_staMacs(nStations),
       m_nStations(nStations),
-      m_lastAid(0)
+      m_lastAid(0),
+      m_rxPkts(nStations + 1)
 {
 }
 
@@ -374,7 +525,7 @@
         bool found = false;
         for (uint8_t i = 0; i < m_nStations; i++)
         {
-            for (uint8_t linkId = 0; linkId < m_staMacs[i]->GetNLinks(); linkId++)
+            for (const auto& linkId : m_staMacs[i]->GetLinkIds())
             {
                 if (m_staMacs[i]->GetFrameExchangeManager(linkId)->GetAddress() == *staAddr)
                 {
@@ -395,21 +546,24 @@
 }
 
 void
-MultiLinkOperationsTestBase::Transmit(uint8_t linkId,
-                                      std::string context,
+MultiLinkOperationsTestBase::Transmit(Ptr<WifiMac> mac,
+                                      uint8_t phyId,
                                       WifiConstPsduMap psduMap,
                                       WifiTxVector txVector,
                                       double txPowerW)
 {
-    m_txPsdus.push_back({Simulator::Now(), psduMap, txVector, linkId});
+    auto linkId = mac->GetLinkForPhy(phyId);
+    NS_TEST_ASSERT_MSG_EQ(linkId.has_value(), true, "No link found for PHY ID " << +phyId);
+    m_txPsdus.push_back({Simulator::Now(), psduMap, txVector, *linkId, phyId});
 
     for (const auto& [aid, psdu] : psduMap)
     {
         std::stringstream ss;
-        ss << std::setprecision(10) << "PSDU #" << m_txPsdus.size() << " Link ID " << +linkId << " "
-           << psdu->GetHeader(0).GetTypeString() << " #MPDUs " << psdu->GetNMpdus()
-           << " duration/ID " << psdu->GetHeader(0).GetDuration() << " RA = " << psdu->GetAddr1()
-           << " TA = " << psdu->GetAddr2() << " ADDR3 = " << psdu->GetHeader(0).GetAddr3()
+        ss << std::setprecision(10) << "PSDU #" << m_txPsdus.size() << " Link ID "
+           << +linkId.value() << " Phy ID " << +phyId << " " << psdu->GetHeader(0).GetTypeString()
+           << " #MPDUs " << psdu->GetNMpdus() << " duration/ID " << psdu->GetHeader(0).GetDuration()
+           << " RA = " << psdu->GetAddr1() << " TA = " << psdu->GetAddr2()
+           << " ADDR3 = " << psdu->GetHeader(0).GetAddr3()
            << " ToDS = " << psdu->GetHeader(0).IsToDs()
            << " FromDS = " << psdu->GetHeader(0).IsFromDs();
         if (psdu->GetHeader(0).IsQosData())
@@ -427,6 +581,13 @@
 }
 
 void
+MultiLinkOperationsTestBase::L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr)
+{
+    NS_LOG_INFO("Packet received by NODE " << +nodeId << "\n");
+    m_rxPkts[nodeId]++;
+}
+
+void
 MultiLinkOperationsTestBase::SetChannels(SpectrumWifiPhyHelper& helper,
                                          const std::vector<std::string>& channels,
                                          const ChannelMap& channelMap)
@@ -526,31 +687,79 @@
     }
 
     // Trace PSDUs passed to the PHY on all devices
-    for (uint8_t linkId = 0; linkId < StaticCast<WifiNetDevice>(apDevices.Get(0))->GetNPhys();
-         linkId++)
+    for (uint8_t phyId = 0; phyId < m_apMac->GetDevice()->GetNPhys(); phyId++)
     {
-        Config::Connect("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
-                            std::to_string(linkId) + "/PhyTxPsduBegin",
-                        MakeCallback(&MultiLinkOperationsTestBase::Transmit, this).Bind(linkId));
+        Config::ConnectWithoutContext(
+            "/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phys/" + std::to_string(phyId) +
+                "/PhyTxPsduBegin",
+            MakeCallback(&MultiLinkOperationsTestBase::Transmit, this).Bind(m_apMac, phyId));
     }
     for (uint8_t i = 0; i < m_nStations; i++)
     {
-        for (uint8_t linkId = 0; linkId < StaticCast<WifiNetDevice>(staDevices.Get(i))->GetNPhys();
-             linkId++)
+        for (uint8_t phyId = 0; phyId < m_staMacs[i]->GetDevice()->GetNPhys(); phyId++)
         {
-            Config::Connect(
-                "/NodeList/" + std::to_string(i + 1) + "/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
-                    std::to_string(linkId) + "/PhyTxPsduBegin",
-                MakeCallback(&MultiLinkOperationsTestBase::Transmit, this).Bind(linkId));
+            Config::ConnectWithoutContext("/NodeList/" + std::to_string(i + 1) +
+                                              "/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
+                                              std::to_string(phyId) + "/PhyTxPsduBegin",
+                                          MakeCallback(&MultiLinkOperationsTestBase::Transmit, this)
+                                              .Bind(m_staMacs[i], phyId));
         }
     }
 
+    // install packet socket on all nodes
+    PacketSocketHelper packetSocket;
+    packetSocket.Install(wifiApNode);
+    packetSocket.Install(wifiStaNodes);
+
+    // install a packet socket server on all nodes
+    for (auto nodeIt = NodeList::Begin(); nodeIt != NodeList::End(); ++nodeIt)
+    {
+        PacketSocketAddress srvAddr;
+        auto device = DynamicCast<WifiNetDevice>((*nodeIt)->GetDevice(0));
+        NS_TEST_ASSERT_MSG_NE(device, nullptr, "Expected a WifiNetDevice");
+        srvAddr.SetSingleDevice(device->GetIfIndex());
+        srvAddr.SetProtocol(1);
+
+        auto server = CreateObject<PacketSocketServer>();
+        server->SetLocal(srvAddr);
+        (*nodeIt)->AddApplication(server);
+        server->SetStartTime(Seconds(0)); // now
+        server->SetStopTime(m_duration);
+    }
+
+    for (std::size_t nodeId = 0; nodeId < NodeList::GetNNodes(); nodeId++)
+    {
+        Config::ConnectWithoutContext(
+            "/NodeList/" + std::to_string(nodeId) +
+                "/ApplicationList/*/$ns3::PacketSocketServer/Rx",
+            MakeCallback(&MultiLinkOperationsTestBase::L7Receive, this).Bind(nodeId));
+    }
+
     // schedule ML setup for one station at a time
     m_apMac->TraceConnectWithoutContext("AssociatedSta",
                                         MakeCallback(&MultiLinkOperationsTestBase::SetSsid, this));
     m_staMacs[0]->SetSsid(Ssid("ns-3-ssid"));
 }
 
+Ptr<PacketSocketClient>
+MultiLinkOperationsTestBase::GetApplication(const PacketSocketAddress& sockAddr,
+                                            std::size_t count,
+                                            std::size_t pktSize,
+                                            Time delay,
+                                            uint8_t priority) const
+{
+    auto client = CreateObject<PacketSocketClient>();
+    client->SetAttribute("PacketSize", UintegerValue(pktSize));
+    client->SetAttribute("MaxPackets", UintegerValue(count));
+    client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
+    client->SetAttribute("Priority", UintegerValue(priority));
+    client->SetRemote(sockAddr);
+    client->SetStartTime(delay);
+    client->SetStopTime(m_duration - Simulator::Now());
+
+    return client;
+}
+
 void
 MultiLinkOperationsTestBase::SetSsid(uint16_t aid, Mac48Address /* addr */)
 {
@@ -583,6 +792,23 @@
  * switch PHY band (if any). The links that are expected to be setup are also provided as input
  * parameters. This test verifies that the management frames exchanged during ML discovery
  * and ML setup contain the expected values and that the two MLDs setup the expected links.
+ *
+ * The negotiated TID-to-link mapping is tested by verifying that generated QoS data frames of
+ * a given TID are transmitted on links which the TID is mapped to. Specifically, the following
+ * operations are performed separately for each direction (downlink and uplink). A first TID
+ * is searched such that it is not mapped on all the setup links. If no such TID is found, only
+ * QoS frames of TID 0 are generated. Otherwise, we also search for a second TID that is mapped
+ * to a link set that is disjoint with the link set to which the first TID is mapped. If such a
+ * TID is found, QoS frames of both the first TID and the second TID are generated; otherwise,
+ * only QoS frames of the first TID are generated. For each TID, a number of QoS frames equal
+ * to the number of setup links is generated. For each TID, we check that the first N QoS frames,
+ * where N is the size of the link set to which the TID is mapped, are transmitted concurrently,
+ * while the following QoS frames are sent after the first QoS frame sent on the same link. We
+ * also check that all the QoS frames are sent on a link belonging to the link set to which the
+ * TID is mapped. If QoS frames of two TIDs are generated, we also check that the first N QoS
+ * frames of a TID, where N is the size of the link set to which that TID is mapped, are sent
+ * concurrently with the first M QoS frames of the other TID, where M is the size of the link
+ * set to which the other TID is mapped.
  */
 class MultiLinkSetupTest : public MultiLinkOperationsTestBase
 {
@@ -590,17 +816,20 @@
     /**
      * Constructor
      *
-     * \param staChannels the strings specifying the operating channels for the STA
-     * \param apChannels the strings specifying the operating channels for the AP
+     * \param baseParams common configuration parameters
      * \param scanType the scan type (active or passive)
-     * \param setupLinks a list of links (STA link ID, AP link ID) that are expected to be setup
-     * \param fixedPhyBands list of IDs of STA links that cannot switch PHY band
+     * \param setupLinks a list of links that are expected to be setup. In case one of the two
+     *                   devices has a single link, the ID of the link on the MLD is indicated
+     * \param apNegSupport TID-to-Link Mapping negotiation supported by the AP MLD (0, 1, or 3)
+     * \param dlTidToLinkMapping DL TID-to-Link Mapping for EHT configuration of non-AP MLD
+     * \param ulTidToLinkMapping UL TID-to-Link Mapping for EHT configuration of non-AP MLD
      */
-    MultiLinkSetupTest(std::vector<std::string> staChannels,
-                       std::vector<std::string> apChannels,
+    MultiLinkSetupTest(const BaseParams& baseParams,
                        WifiScanType scanType,
-                       std::vector<std::pair<uint8_t, uint8_t>> setupLinks,
-                       std::vector<uint8_t> fixedPhyBands = {});
+                       const std::vector<uint8_t>& setupLinks,
+                       uint8_t apNegSupport,
+                       const std::string& dlTidToLinkMapping,
+                       const std::string& ulTidToLinkMapping);
     ~MultiLinkSetupTest() override = default;
 
   protected:
@@ -608,6 +837,8 @@
     void DoRun() override;
 
   private:
+    void StartTraffic() override;
+
     /**
      * Check correctness of Multi-Link Setup procedure.
      */
@@ -650,25 +881,48 @@
      */
     void CheckAssocResponse(Ptr<WifiMpdu> mpdu, uint8_t linkId);
 
-    /// expected links to setup (STA link ID, AP link ID)
-    const std::vector<std::pair<uint8_t, uint8_t>> m_setupLinks;
-    WifiScanType m_scanType;  //!< the scan type (active or passive)
-    std::size_t m_nProbeResp; //!< number of Probe Responses received by the non-AP MLD
+    /**
+     * Check that QoS data frames are sent on links their TID is mapped to.
+     *
+     * \param mpdu the given QoS data frame
+     * \param linkId the ID of the link on which the QoS data frame was transmitted
+     * \param index index of the QoS data frame in the vector of transmitted PSDUs
+     */
+    void CheckQosData(Ptr<WifiMpdu> mpdu, uint8_t linkId, std::size_t index);
+
+    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::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
+                                           //!< MLD and accepted by AP MLD
+    WifiTidLinkMapping m_ulTidLinkMapping; //!< expected UL TID-to-Link Mapping requested by non-AP
+                                           //!< MLD and accepted by AP MLD
+    uint8_t m_dlTid1;                      //!< the TID of the first set of DL QoS data frames
+    uint8_t m_ulTid1;                      //!< the TID of the first set of UL QoS data frames
+    std::optional<uint8_t> m_dlTid2;       //!< the TID of the optional set of DL QoS data frames
+    std::optional<uint8_t> m_ulTid2;       //!< the TID of the optional set of UL QoS data frames
+    std::vector<std::size_t>
+        m_qosFrames1; //!< indices of QoS frames of the first set in the vector of TX PSDUs
+    std::vector<std::size_t>
+        m_qosFrames2; //!< indices of QoS frames of the optional set in the vector of TX PSDUs
 };
 
-MultiLinkSetupTest::MultiLinkSetupTest(std::vector<std::string> staChannels,
-                                       std::vector<std::string> apChannels,
+MultiLinkSetupTest::MultiLinkSetupTest(const BaseParams& baseParams,
                                        WifiScanType scanType,
-                                       std::vector<std::pair<uint8_t, uint8_t>> setupLinks,
-                                       std::vector<uint8_t> fixedPhyBands)
-    : MultiLinkOperationsTestBase("Check correctness of Multi-Link Setup",
-                                  1,
-                                  staChannels,
-                                  apChannels,
-                                  fixedPhyBands),
+                                       const std::vector<uint8_t>& setupLinks,
+                                       uint8_t apNegSupport,
+                                       const std::string& dlTidToLinkMapping,
+                                       const std::string& ulTidToLinkMapping)
+    : MultiLinkOperationsTestBase("Check correctness of Multi-Link Setup", 1, baseParams),
       m_setupLinks(setupLinks),
       m_scanType(scanType),
-      m_nProbeResp(0)
+      m_nProbeResp(0),
+      m_apNegSupport(apNegSupport),
+      m_dlTidLinkMappingStr(dlTidToLinkMapping),
+      m_ulTidLinkMappingStr(ulTidToLinkMapping)
 {
 }
 
@@ -678,6 +932,137 @@
     MultiLinkOperationsTestBase::DoSetup();
 
     m_staMacs[0]->SetAttribute("ActiveProbing", BooleanValue(m_scanType == WifiScanType::ACTIVE));
+    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(3));
+    staEhtConfig->SetAttribute("TidToLinkMappingDl", StringValue(m_dlTidLinkMappingStr));
+    staEhtConfig->SetAttribute("TidToLinkMappingUl", StringValue(m_ulTidLinkMappingStr));
+
+    // the negotiated link mapping matches the one configured in EHT configuration, unless
+    // the AP MLD does not support TID-to-link mapping negotiation or the AP MLD supports
+    // the negotiation type 1 and the non-AP MLD is configured with a link mapping that
+    // maps distinct link sets to the TIDs, in which case the default link mapping is used
+    m_dlTidLinkMapping = staEhtConfig->GetTidLinkMapping(WifiDirection::DOWNLINK);
+    m_ulTidLinkMapping = staEhtConfig->GetTidLinkMapping(WifiDirection::UPLINK);
+
+    if (m_apNegSupport == 0 ||
+        (m_apNegSupport == 1 &&
+         !TidToLinkMappingValidForNegType1(m_dlTidLinkMapping, m_ulTidLinkMapping)))
+    {
+        m_dlTidLinkMapping.clear(); // default link mapping
+        m_ulTidLinkMapping.clear(); // default link mapping
+    }
+
+    // find (if any) a TID that is not mapped to all setup links
+    using TupleRefs = std::tuple<std::reference_wrapper<const WifiTidLinkMapping>,
+                                 std::reference_wrapper<uint8_t>,
+                                 std::reference_wrapper<std::optional<uint8_t>>,
+                                 Ptr<WifiMac>>;
+    for (auto& [mappingRef, tid1Ref, tid2Ref, mac] :
+         {TupleRefs{m_dlTidLinkMapping, m_dlTid1, m_dlTid2, m_apMac},
+          TupleRefs{m_ulTidLinkMapping, m_ulTid1, m_ulTid2, m_staMacs[0]}})
+    {
+        tid1Ref.get() = 0;
+        for (uint8_t tid1 = 0; tid1 < 8; tid1++)
+        {
+            if (auto it1 = mappingRef.get().find(tid1);
+                it1 != mappingRef.get().cend() && it1->second.size() != m_setupLinks.size())
+            {
+                // found. Now search for another TID with a disjoint mapped link set
+                for (uint8_t tid2 = tid1 + 1; tid2 < 8; tid2++)
+                {
+                    if (auto it2 = mappingRef.get().find(tid2);
+                        it2 != mappingRef.get().cend() && it2->second.size() != m_setupLinks.size())
+                    {
+                        std::list<uint8_t> intersection;
+                        std::set_intersection(it1->second.cbegin(),
+                                              it1->second.cend(),
+                                              it2->second.cbegin(),
+                                              it2->second.cend(),
+                                              std::back_inserter(intersection));
+                        if (intersection.empty())
+                        {
+                            // found a second TID
+                            tid2Ref.get() = tid2;
+                            break;
+                        }
+                    }
+                }
+                tid1Ref.get() = tid1;
+                break;
+            }
+        }
+
+        std::list<uint8_t> tids = {tid1Ref.get()};
+        if (tid2Ref.get())
+        {
+            tids.emplace_back(*tid2Ref.get());
+        }
+
+        // prevent aggregation of MPDUs
+        for (auto tid : tids)
+        {
+            std::string attrName;
+            switch (QosUtilsMapTidToAc(tid))
+            {
+            case AC_VI:
+                attrName = "VI_MaxAmpduSize";
+                break;
+            case AC_VO:
+                attrName = "VO_MaxAmpduSize";
+                break;
+            case AC_BE:
+                attrName = "BE_MaxAmpduSize";
+                break;
+            case AC_BK:
+                attrName = "BK_MaxAmpduSize";
+                break;
+            default:
+                NS_FATAL_ERROR("Invalid TID " << +tid);
+            }
+
+            mac->SetAttribute(attrName, UintegerValue(100));
+        }
+    }
+}
+
+void
+MultiLinkSetupTest::StartTraffic()
+{
+    // DL traffic
+    {
+        PacketSocketAddress sockAddr;
+        sockAddr.SetSingleDevice(m_apMac->GetDevice()->GetIfIndex());
+        sockAddr.SetPhysicalAddress(m_staMacs[0]->GetDevice()->GetAddress());
+        sockAddr.SetProtocol(1);
+
+        m_apMac->GetDevice()->GetNode()->AddApplication(
+            GetApplication(sockAddr, m_setupLinks.size(), 500, Seconds(0), m_dlTid1));
+        if (m_dlTid2)
+        {
+            m_apMac->GetDevice()->GetNode()->AddApplication(
+                GetApplication(sockAddr, m_setupLinks.size(), 500, Seconds(0), *m_dlTid2));
+        }
+    }
+
+    // UL Traffic
+    {
+        PacketSocketAddress sockAddr;
+        sockAddr.SetSingleDevice(m_staMacs[0]->GetDevice()->GetIfIndex());
+        sockAddr.SetPhysicalAddress(m_apMac->GetDevice()->GetAddress());
+        sockAddr.SetProtocol(1);
+
+        m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
+            GetApplication(sockAddr, m_setupLinks.size(), 500, MilliSeconds(500), m_ulTid1));
+        if (m_ulTid2)
+        {
+            m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
+                GetApplication(sockAddr, m_setupLinks.size(), 500, MilliSeconds(500), *m_ulTid2));
+        }
+    }
 }
 
 void
@@ -685,12 +1070,14 @@
 {
     Simulator::Schedule(MilliSeconds(500), &MultiLinkSetupTest::CheckMlSetup, this);
 
-    Simulator::Stop(Seconds(1.5));
+    Simulator::Stop(m_duration);
     Simulator::Run();
 
     /**
      * Check content of management frames
      */
+    std::size_t index = 0;
+
     for (const auto& frameInfo : m_txPsdus)
     {
         const auto& mpdu = *frameInfo.psduMap.begin()->second->begin();
@@ -715,9 +1102,15 @@
             CheckAssocResponse(mpdu, linkId);
             break;
 
+        case WIFI_MAC_QOSDATA:
+            CheckQosData(mpdu, linkId, index);
+            break;
+
         default:
             break;
         }
+
+        index++;
     }
 
     CheckDisabledLinks();
@@ -742,6 +1135,24 @@
 
     NS_TEST_EXPECT_MSG_EQ(m_nProbeResp, expectedProbeResp, "Unexpected number of Probe Responses");
 
+    std::size_t expectedRxDlPkts = m_setupLinks.size();
+    if (m_dlTid2)
+    {
+        expectedRxDlPkts *= 2;
+    }
+    NS_TEST_EXPECT_MSG_EQ(m_rxPkts[m_staMacs[0]->GetDevice()->GetNode()->GetId()],
+                          expectedRxDlPkts,
+                          "Unexpected number of DL packets received");
+
+    std::size_t expectedRxUlPkts = m_setupLinks.size();
+    if (m_ulTid2)
+    {
+        expectedRxUlPkts *= 2;
+    }
+    NS_TEST_EXPECT_MSG_EQ(m_rxPkts[m_apMac->GetDevice()->GetNode()->GetId()],
+                          expectedRxUlPkts,
+                          "Unexpected number of UL packets received");
+
     Simulator::Destroy();
 }
 
@@ -882,45 +1293,113 @@
         NS_TEST_EXPECT_MSG_EQ(mle.has_value(),
                               false,
                               "Multi-Link Element in Assoc Request frame from single link STA");
-        return;
     }
-
-    NS_TEST_EXPECT_MSG_EQ(mle.has_value(), true, "No Multi-Link Element in Assoc Request frame");
-    NS_TEST_EXPECT_MSG_EQ(mle->GetMldMacAddress(),
-                          m_staMacs[0]->GetAddress(),
-                          "Incorrect MLD Address advertised in Multi-Link Element");
-    NS_TEST_EXPECT_MSG_EQ(mle->GetNPerStaProfileSubelements(),
-                          m_setupLinks.size() - 1,
-                          "Incorrect number of Per-STA Profile subelements in Multi-Link Element");
-    for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
+    else
     {
-        auto& perStaProfile = mle->GetPerStaProfile(i);
-        NS_TEST_EXPECT_MSG_EQ(perStaProfile.HasStaMacAddress(),
-                              true,
-                              "Per-STA Profile must contain STA MAC address");
-        // find ID of the local link corresponding to this subelement
-        auto staLinkId = m_staMacs[0]->GetLinkIdByAddress(perStaProfile.GetStaMacAddress());
-        NS_TEST_EXPECT_MSG_EQ(
-            staLinkId.has_value(),
-            true,
-            "No link found with the STA MAC address advertised in Per-STA Profile");
-        NS_TEST_EXPECT_MSG_NE(
-            +staLinkId.value(),
-            +linkId,
-            "The STA that sent the Assoc Request should not be included in a Per-STA Profile");
-        auto it = std::find_if(m_setupLinks.begin(), m_setupLinks.end(), [&staLinkId](auto&& pair) {
-            return pair.first == staLinkId.value();
-        });
-        NS_TEST_EXPECT_MSG_EQ((it != m_setupLinks.end()),
+        NS_TEST_EXPECT_MSG_EQ(mle.has_value(),
                               true,
-                              "Not expecting to setup STA link ID " << +staLinkId.value());
+                              "No Multi-Link Element in Assoc Request frame");
+        NS_TEST_EXPECT_MSG_EQ(mle->GetMldMacAddress(),
+                              m_staMacs[0]->GetAddress(),
+                              "Incorrect MLD Address advertised in Multi-Link Element");
         NS_TEST_EXPECT_MSG_EQ(
-            +it->second,
-            +perStaProfile.GetLinkId(),
-            "Not expecting to request association to AP Link ID in Per-STA Profile");
-        NS_TEST_EXPECT_MSG_EQ(perStaProfile.HasAssocRequest(),
+            mle->GetNPerStaProfileSubelements(),
+            m_setupLinks.size() - 1,
+            "Incorrect number of Per-STA Profile subelements in Multi-Link Element");
+        for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
+        {
+            auto& perStaProfile = mle->GetPerStaProfile(i);
+            NS_TEST_EXPECT_MSG_EQ(perStaProfile.HasStaMacAddress(),
+                                  true,
+                                  "Per-STA Profile must contain STA MAC address");
+            // find ID of the local link corresponding to this subelement
+            auto staLinkId = m_staMacs[0]->GetLinkIdByAddress(perStaProfile.GetStaMacAddress());
+            NS_TEST_EXPECT_MSG_EQ(
+                staLinkId.has_value(),
+                true,
+                "No link found with the STA MAC address advertised in Per-STA Profile");
+            NS_TEST_EXPECT_MSG_NE(
+                +staLinkId.value(),
+                +linkId,
+                "The STA that sent the Assoc Request should not be included in a Per-STA Profile");
+            auto it = std::find(m_setupLinks.begin(), m_setupLinks.end(), staLinkId.value());
+            NS_TEST_EXPECT_MSG_EQ((it != m_setupLinks.end()),
+                                  true,
+                                  "Not expecting to setup STA link ID " << +staLinkId.value());
+            NS_TEST_EXPECT_MSG_EQ(
+                +staLinkId.value(),
+                +perStaProfile.GetLinkId(),
+                "Not expecting to request association to AP Link ID in Per-STA Profile");
+            NS_TEST_EXPECT_MSG_EQ(perStaProfile.HasAssocRequest(),
+                                  true,
+                                  "Missing Association Request in Per-STA Profile");
+        }
+    }
+
+    const auto& tlm = assoc.Get<TidToLinkMapping>();
+
+    // 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)
+    {
+        NS_TEST_EXPECT_MSG_EQ(tlm.empty(),
                               true,
-                              "Missing Association Request in Per-STA Profile");
+                              "Didn't expect a TID-to-Link Mapping IE in Assoc Request frame");
+    }
+    else
+    {
+        std::size_t expectedNTlm = (m_dlTidLinkMapping == m_ulTidLinkMapping ? 1 : 2);
+
+        NS_TEST_ASSERT_MSG_EQ(tlm.size(),
+                              expectedNTlm,
+                              "Unexpected number of TID-to-Link Mapping IE in Assoc Request");
+
+        // lambda to check content of TID-to-Link Mapping IE(s)
+        auto checkTlm = [&](std::size_t tlmId, WifiDirection dir) {
+            NS_TEST_EXPECT_MSG_EQ(+static_cast<uint8_t>(tlm[tlmId].m_control.direction),
+                                  +static_cast<uint8_t>(dir),
+                                  "Unexpected direction in TID-to-Link Mapping IE " << tlmId);
+            auto& expectedMapping =
+                (dir == WifiDirection::UPLINK ? m_ulTidLinkMapping : m_dlTidLinkMapping);
+
+            NS_TEST_EXPECT_MSG_EQ(tlm[tlmId].m_control.defaultMapping,
+                                  expectedMapping.empty(),
+                                  "Default Link Mapping bit not set correctly");
+            NS_TEST_EXPECT_MSG_EQ(tlm[tlmId].m_linkMapping.size(),
+                                  expectedMapping.size(),
+                                  "Unexpected number of Link Mapping Of TID n fields");
+            for (uint8_t tid = 0; tid < 8; tid++)
+            {
+                if (auto it = expectedMapping.find(tid); it != expectedMapping.cend())
+                {
+                    NS_TEST_EXPECT_MSG_EQ((tlm[tlmId].GetLinkMappingOfTid(tid) == it->second),
+                                          true,
+                                          "Unexpected link mapping for TID "
+                                              << +tid << " direction " << dir);
+                }
+                else
+                {
+                    NS_TEST_EXPECT_MSG_EQ(tlm[tlmId].GetLinkMappingOfTid(tid).empty(),
+                                          true,
+                                          "Expecting no Link Mapping Of TID n field for TID "
+                                              << +tid << " direction " << dir);
+                }
+            }
+        };
+
+        if (tlm.size() == 1)
+        {
+            checkTlm(0, WifiDirection::BOTH_DIRECTIONS);
+        }
+        else
+        {
+            std::size_t dlId = (tlm[0].m_control.direction == WifiDirection::DOWNLINK ? 0 : 1);
+            std::size_t ulId = (dlId == 0 ? 1 : 0);
+
+            checkTlm(dlId, WifiDirection::DOWNLINK);
+            checkTlm(ulId, WifiDirection::UPLINK);
+        }
     }
 }
 
@@ -974,9 +1453,7 @@
             +apLinkId.value(),
             +linkId,
             "The AP that sent the Assoc Response should not be included in a Per-STA Profile");
-        auto it = std::find_if(m_setupLinks.begin(), m_setupLinks.end(), [&apLinkId](auto&& pair) {
-            return pair.second == apLinkId.value();
-        });
+        auto it = std::find(m_setupLinks.begin(), m_setupLinks.end(), apLinkId.value());
         NS_TEST_EXPECT_MSG_EQ((it != m_setupLinks.end()),
                               true,
                               "Not expecting to setup AP link ID " << +apLinkId.value());
@@ -984,6 +1461,12 @@
                               true,
                               "Missing Association Response in Per-STA Profile");
     }
+
+    // For the moment, the AP MLD always accepts a valid TID-to-Link Mapping request, hence
+    // in every case there is no TID-to-Link Mapping IE in the Association Response
+    NS_TEST_EXPECT_MSG_EQ(assoc.Get<TidToLinkMapping>().empty(),
+                          true,
+                          "Didn't expect to find a TID-to-Link Mapping IE in Association Response");
 }
 
 void
@@ -994,8 +1477,11 @@
      */
     NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->IsAssociated(), true, "Expected the STA to be associated");
 
-    for (const auto& [staLinkId, apLinkId] : m_setupLinks)
+    for (const auto linkId : m_setupLinks)
     {
+        auto staLinkId = (m_staMacs[0]->GetNLinks() > 1 ? linkId : SINGLE_LINK_OP_ID);
+        auto apLinkId = (m_apMac->GetNLinks() > 1 ? linkId : SINGLE_LINK_OP_ID);
+
         auto staAddr = m_staMacs[0]->GetFrameExchangeManager(staLinkId)->GetAddress();
         auto apAddr = m_apMac->GetFrameExchangeManager(apLinkId)->GetAddress();
 
@@ -1060,16 +1546,49 @@
             +m_apMac->GetWifiPhy(apLinkId)->GetOperatingChannel().GetPrimaryChannelIndex(20),
             "Incorrect operating primary channel index for STA on link " << +staLinkId);
     }
+
+    // lambda to check the link mapping stored at wifi MAC
+    auto checkStoredMapping =
+        [this](Ptr<WifiMac> mac, Ptr<WifiMac> dest, WifiDirection dir, bool present) {
+            NS_TEST_ASSERT_MSG_EQ(mac->GetTidToLinkMapping(dest->GetAddress(), dir).has_value(),
+                                  present,
+                                  "Link mapping stored by "
+                                      << (mac->GetTypeOfStation() == AP ? "AP" : "non-AP")
+                                      << " MLD for " << dir << " direction "
+                                      << (present ? "expected" : "not expected"));
+            if (present)
+            {
+                const auto& mapping =
+                    (dir == WifiDirection::DOWNLINK ? m_dlTidLinkMapping : m_ulTidLinkMapping);
+                NS_TEST_EXPECT_MSG_EQ(
+                    (mac->GetTidToLinkMapping(dest->GetAddress(), dir)->get() == mapping),
+                    true,
+                    "Incorrect link mapping stored by "
+                        << (mac->GetTypeOfStation() == AP ? "AP" : "non-AP") << " MLD for " << dir
+                        << " direction");
+            }
+        };
+
+    auto storedMapping =
+        m_apMac->GetNLinks() > 1 && m_staMacs[0]->GetNLinks() > 1 && m_apNegSupport > 0;
+    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);
+    checkStoredMapping(m_staMacs[0], m_apMac, WifiDirection::UPLINK, storedMapping);
 }
 
 void
 MultiLinkSetupTest::CheckDisabledLinks()
 {
-    for (std::size_t linkId = 0; linkId < m_staChannels.size(); linkId++)
+    if (m_staMacs[0]->GetNLinks() == 1)
     {
-        auto it = std::find_if(m_setupLinks.begin(), m_setupLinks.end(), [&linkId](auto&& link) {
-            return link.first == linkId;
-        });
+        // no link is disabled on a single link device
+        return;
+    }
+
+    for (const auto& linkId : m_staMacs[0]->GetLinkIds())
+    {
+        auto it = std::find(m_setupLinks.begin(), m_setupLinks.end(), linkId);
         if (it == m_setupLinks.end())
         {
             // the link has not been setup
@@ -1086,6 +1605,146 @@
     }
 }
 
+void
+MultiLinkSetupTest::CheckQosData(Ptr<WifiMpdu> mpdu, uint8_t linkId, std::size_t index)
+{
+    WifiDirection dir;
+    const auto& hdr = mpdu->GetHeader();
+
+    NS_TEST_ASSERT_MSG_EQ(hdr.IsQosData(), true, "Expected a QoS data frame");
+
+    if (!hdr.IsToDs() && hdr.IsFromDs())
+    {
+        dir = WifiDirection::DOWNLINK;
+    }
+    else if (hdr.IsToDs() && !hdr.IsFromDs())
+    {
+        dir = WifiDirection::UPLINK;
+    }
+    else
+    {
+        NS_ABORT_MSG("Invalid combination for QoS data frame: ToDS(" << hdr.IsToDs() << ") FromDS("
+                                                                     << hdr.IsFromDs() << ")");
+    }
+
+    const auto& tid1 = (dir == WifiDirection::DOWNLINK) ? m_dlTid1 : m_ulTid1;
+    const auto& tid2 = (dir == WifiDirection::DOWNLINK) ? m_dlTid2 : m_ulTid2;
+    uint8_t tid = hdr.GetQosTid();
+
+    NS_TEST_ASSERT_MSG_NE((tid == tid1),
+                          (tid2.has_value() && tid == *tid2),
+                          "QoS frame with unexpected TID " << +tid);
+
+    // lambda to find the link set the given TID is mapped to
+    auto findLinkSet = [this, dir](uint8_t tid) -> std::set<uint8_t> {
+        std::set<uint8_t> linkSet(m_setupLinks.cbegin(), m_setupLinks.cend());
+        if (auto mappingOptRef = m_apMac->GetTidToLinkMapping(m_staMacs[0]->GetAddress(), dir))
+        {
+            // if the TID is not present in the mapping, it is mapped to all setup links
+            if (auto it = mappingOptRef->get().find(tid); it != mappingOptRef->get().cend())
+            {
+                linkSet = it->second;
+                NS_ASSERT_MSG(!linkSet.empty(), "TID " << +tid << " mapped to no link");
+            }
+        }
+        return linkSet;
+    };
+
+    auto linkSet = findLinkSet(tid);
+    auto& qosFrames = (tid == tid1) ? m_qosFrames1 : m_qosFrames2;
+
+    // Let N the size of the link set, the first N QoS data frames are sent simultaneously
+    // on the links of the set, the others (if any) will be sent afterwards on such links
+
+    // number of concurrent frames of the same TID transmitted so far (excluding current frame)
+    std::size_t nConcurFrames = std::min(qosFrames.size(), linkSet.size());
+
+    // iterate over the concurrent frames of the same TID transmitted so far
+    for (std::size_t i = 0; i < nConcurFrames; i++)
+    {
+        auto prev = qosFrames[i];
+
+        // TX duration of i-th frame
+        auto band = m_apMac->GetWifiPhy(m_txPsdus[prev].linkId)->GetPhyBand();
+        Time txDuration =
+            WifiPhy::CalculateTxDuration(m_txPsdus[prev].psduMap, m_txPsdus[prev].txVector, band);
+
+        // the current frame is transmitted concurrently with this previous frame if it is
+        // within the first N (size of the link set) frames, otherwise it is transmitted after
+        // this previous frame if they have been transmitted on the same link
+        if (qosFrames.size() < linkSet.size())
+        {
+            // the current frame can be sent concurrently with this previous frame
+            NS_TEST_EXPECT_MSG_LT(m_txPsdus[index].startTx,
+                                  m_txPsdus[prev].startTx + txDuration,
+                                  "The " << dir << " QoS frame number " << qosFrames.size()
+                                         << " was not sent concurrently with others on link "
+                                         << +linkId << " which TID " << +tid << " is mapped to");
+        }
+        else if (m_txPsdus[prev].linkId == linkId)
+        {
+            // the current  frame is sent afterwards
+            NS_TEST_EXPECT_MSG_GT(m_txPsdus[index].startTx,
+                                  m_txPsdus[prev].startTx + txDuration,
+                                  "The " << dir << " QoS frame number " << qosFrames.size()
+                                         << " was sent concurrently with others on a link "
+                                         << +linkId << " which TID " << +tid << " is mapped to");
+        }
+    }
+
+    if (m_apMac->GetNLinks() > 1 && m_staMacs[0]->GetNLinks() > 1)
+    {
+        NS_TEST_EXPECT_MSG_EQ(std::count(linkSet.cbegin(), linkSet.cend(), linkId),
+                              1,
+                              "QoS frame sent on Link ID "
+                                  << +linkId << " that does not belong to the link set of TID "
+                                  << +tid);
+    }
+
+    if (tid2)
+    {
+        // QoS frames of two distinct TIDs are sent.
+        auto otherTid = (tid == tid1) ? *tid2 : tid1;
+        const auto& otherQosFrames = (tid == tid1) ? m_qosFrames2 : m_qosFrames1;
+        auto otherLinkSet = findLinkSet(otherTid);
+
+        // number of concurrent frames of the other TID transmitted so far
+        std::size_t nOtherConcurFrames = std::min(otherQosFrames.size(), otherLinkSet.size());
+
+        // iterate over the concurrent frames of the other TID
+        for (std::size_t i = 0; i < nOtherConcurFrames; i++)
+        {
+            auto prev = otherQosFrames[i];
+
+            // TX duration of i-th frame
+            auto band = m_apMac->GetWifiPhy(m_txPsdus[prev].linkId)->GetPhyBand();
+            Time txDuration = WifiPhy::CalculateTxDuration(m_txPsdus[prev].psduMap,
+                                                           m_txPsdus[prev].txVector,
+                                                           band);
+
+            // the current frame is transmitted concurrently with this previous frame of the
+            // other TID if it is within the first N (size of the link set) frames of its TID
+            if (qosFrames.size() < linkSet.size())
+            {
+                // the current frame can be sent concurrently with this previous frame
+                NS_TEST_EXPECT_MSG_LT(m_txPsdus[index].startTx,
+                                      m_txPsdus[prev].startTx + txDuration,
+                                      "The " << dir << " QoS frame number " << qosFrames.size()
+                                             << " was not sent concurrently with others with TID "
+                                             << +otherTid);
+            }
+        }
+    }
+
+    // insert the frame
+    qosFrames.emplace_back(index);
+
+    if (qosFrames.size() == m_setupLinks.size())
+    {
+        qosFrames.clear();
+    }
+}
+
 /**
  * Tested traffic patterns.
  */
@@ -1150,34 +1809,22 @@
     /**
      * Constructor
      *
+     * \param baseParams common configuration parameters
      * \param trafficPattern the pattern of traffic to generate
      * \param baEnabled whether BA agreement is enabled or disabled
      * \param useBarAfterMissedBa whether a BAR or Data frames are sent after missed BlockAck
      * \param nMaxInflight the max number of links on which an MPDU can be simultaneously inflight
      *                     (unused if Block Ack agreements are not established)
-     * \param staChannels the strings specifying the operating channels for the STA
-     * \param apChannels the strings specifying the operating channels for the AP
-     * \param fixedPhyBands list of IDs of STA links that cannot switch PHY band
      */
-    MultiLinkTxTest(WifiTrafficPattern trafficPattern,
+    MultiLinkTxTest(const BaseParams& baseParams,
+                    WifiTrafficPattern trafficPattern,
                     WifiBaEnabled baEnabled,
                     WifiUseBarAfterMissedBa useBarAfterMissedBa,
-                    uint8_t nMaxInflight,
-                    const std::vector<std::string>& staChannels,
-                    const std::vector<std::string>& apChannels,
-                    const std::vector<uint8_t>& fixedPhyBands = {});
+                    uint8_t nMaxInflight);
     ~MultiLinkTxTest() override = default;
 
   protected:
     /**
-     * Function to trace packets received by the server application
-     * \param nodeId the ID of the node that received the packet
-     * \param p the packet
-     * \param addr the address
-     */
-    void L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr);
-
-    /**
      * Check the content of a received BlockAck frame when the max number of links on which
      * an MPDU can be inflight is one.
      *
@@ -1187,8 +1834,8 @@
      */
     void CheckBlockAck(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, uint8_t linkId);
 
-    void Transmit(uint8_t linkId,
-                  std::string context,
+    void Transmit(Ptr<WifiMac> mac,
+                  uint8_t phyId,
                   WifiConstPsduMap psduMap,
                   WifiTxVector txVector,
                   double txPowerW) override;
@@ -1201,30 +1848,26 @@
     /// Receiver address-indexed map of list error models
     using RxErrorModelMap = std::unordered_map<Mac48Address, Ptr<ListErrorModel>, WifiAddressHash>;
 
-    RxErrorModelMap m_errorModels;         ///< error rate models to corrupt packets
-    std::list<uint64_t> m_uidList;         ///< list of UIDs of packets to corrupt
-    bool m_dataCorrupted{false};           ///< whether second data frame has been already corrupted
-    WifiTrafficPattern m_trafficPattern;   ///< the pattern of traffic to generate
-    bool m_baEnabled;                      ///< whether BA agreement is enabled or disabled
-    bool m_useBarAfterMissedBa;            ///< whether to send BAR after missed BlockAck
-    std::size_t m_nMaxInflight;            ///< max number of links on which an MPDU can be inflight
-    std::size_t m_nPackets;                ///< number of application packets to generate
-    std::size_t m_blockAckCount{0};        ///< transmitted BlockAck counter
-    std::size_t m_blockAckReqCount{0};     ///< transmitted BlockAckReq counter
-    std::array<std::size_t, 3> m_rxPkts{}; ///< number of packets received at application layer
-                                           ///< by each node (AP, STA 0, STA 1)
+    RxErrorModelMap m_errorModels;       ///< error rate models to corrupt packets
+    std::list<uint64_t> m_uidList;       ///< list of UIDs of packets to corrupt
+    bool m_dataCorrupted{false};         ///< whether second data frame has been already corrupted
+    WifiTrafficPattern m_trafficPattern; ///< the pattern of traffic to generate
+    bool m_baEnabled;                    ///< whether BA agreement is enabled or disabled
+    bool m_useBarAfterMissedBa;          ///< whether to send BAR after missed BlockAck
+    std::size_t m_nMaxInflight;          ///< max number of links on which an MPDU can be inflight
+    std::size_t m_nPackets;              ///< number of application packets to generate
+    std::size_t m_blockAckCount{0};      ///< transmitted BlockAck counter
+    std::size_t m_blockAckReqCount{0};   ///< transmitted BlockAckReq counter
     std::map<uint16_t, std::size_t> m_inflightCount; ///< seqNo-indexed max number of simultaneous
                                                      ///< transmissions of a data frame
     Ptr<WifiMac> m_sourceMac; ///< MAC of the node sending application packets
 };
 
-MultiLinkTxTest::MultiLinkTxTest(WifiTrafficPattern trafficPattern,
+MultiLinkTxTest::MultiLinkTxTest(const BaseParams& baseParams,
+                                 WifiTrafficPattern trafficPattern,
                                  WifiBaEnabled baEnabled,
                                  WifiUseBarAfterMissedBa useBarAfterMissedBa,
-                                 uint8_t nMaxInflight,
-                                 const std::vector<std::string>& staChannels,
-                                 const std::vector<std::string>& apChannels,
-                                 const std::vector<uint8_t>& fixedPhyBands)
+                                 uint8_t nMaxInflight)
     : MultiLinkOperationsTestBase(
           std::string("Check data transmission between MLDs ") +
               (baEnabled == WifiBaEnabled::YES
@@ -1237,9 +1880,7 @@
                                                : "") +
               ")",
           2,
-          staChannels,
-          apChannels,
-          fixedPhyBands),
+          baseParams),
       m_trafficPattern(trafficPattern),
       m_baEnabled(baEnabled == WifiBaEnabled::YES),
       m_useBarAfterMissedBa(useBarAfterMissedBa == WifiUseBarAfterMissedBa::YES),
@@ -1252,12 +1893,15 @@
 }
 
 void
-MultiLinkTxTest::Transmit(uint8_t linkId,
-                          std::string context,
+MultiLinkTxTest::Transmit(Ptr<WifiMac> mac,
+                          uint8_t phyId,
                           WifiConstPsduMap psduMap,
                           WifiTxVector txVector,
                           double txPowerW)
 {
+    MultiLinkOperationsTestBase::Transmit(mac, phyId, psduMap, txVector, txPowerW);
+    auto linkId = m_txPsdus.back().linkId;
+
     auto psdu = psduMap.begin()->second;
 
     switch (psdu->GetHeader(0).GetType())
@@ -1282,7 +1926,7 @@
         {
             // determine the max number of simultaneous transmissions for this MPDU
             // (only if sent by the traffic source and this is not a broadcast frame)
-            if (m_baEnabled && linkId < m_sourceMac->GetNLinks() &&
+            if (m_baEnabled && m_sourceMac->GetLinkIds().count(linkId) == 1 &&
                 m_sourceMac->GetFrameExchangeManager(linkId)->GetAddress() ==
                     mpdu->GetHeader().GetAddr2() &&
                 !mpdu->GetHeader().GetAddr1().IsGroup())
@@ -1361,8 +2005,6 @@
     }
     default:;
     }
-
-    MultiLinkOperationsTestBase::Transmit(linkId, context, psduMap, txVector, txPowerW);
 }
 
 void
@@ -1500,13 +2142,6 @@
 }
 
 void
-MultiLinkTxTest::L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr)
-{
-    NS_LOG_INFO("Packet received by NODE " << +nodeId << "\n");
-    m_rxPkts[nodeId]++;
-}
-
-void
 MultiLinkTxTest::DoSetup()
 {
     MultiLinkOperationsTestBase::DoSetup();
@@ -1530,22 +2165,20 @@
         m_errorModels[m_apMac->GetFrameExchangeManager(linkId)->GetAddress()] = errorModel;
         m_apMac->GetWifiPhy(linkId)->SetPostReceptionErrorModel(errorModel);
     }
-    for (std::size_t linkId = 0; linkId < m_staMacs[0]->GetNLinks(); linkId++)
+    for (std::size_t i : {0, 1})
     {
-        auto errorModel = CreateObject<ListErrorModel>();
-        m_errorModels[m_staMacs[0]->GetFrameExchangeManager(linkId)->GetAddress()] = errorModel;
-        m_staMacs[0]->GetWifiPhy(linkId)->SetPostReceptionErrorModel(errorModel);
-
-        errorModel = CreateObject<ListErrorModel>();
-        m_errorModels[m_staMacs[1]->GetFrameExchangeManager(linkId)->GetAddress()] = errorModel;
-        m_staMacs[1]->GetWifiPhy(linkId)->SetPostReceptionErrorModel(errorModel);
+        for (const auto linkId : m_staMacs[i]->GetLinkIds())
+        {
+            auto errorModel = CreateObject<ListErrorModel>();
+            m_errorModels[m_staMacs[i]->GetFrameExchangeManager(linkId)->GetAddress()] = errorModel;
+            m_staMacs[i]->GetWifiPhy(linkId)->SetPostReceptionErrorModel(errorModel);
+        }
     }
 }
 
 void
 MultiLinkTxTest::StartTraffic()
 {
-    const Time duration = Seconds(1);
     Address destAddr;
 
     switch (m_trafficPattern)
@@ -1572,58 +2205,24 @@
         break;
     }
 
-    PacketSocketHelper packetSocket;
-    packetSocket.Install(m_apMac->GetDevice()->GetNode());
-    packetSocket.Install(m_staMacs[0]->GetDevice()->GetNode());
-    packetSocket.Install(m_staMacs[1]->GetDevice()->GetNode());
-
-    PacketSocketAddress socket;
-    socket.SetSingleDevice(m_sourceMac->GetDevice()->GetIfIndex());
-    socket.SetPhysicalAddress(destAddr);
-    socket.SetProtocol(1);
+    PacketSocketAddress sockAddr;
+    sockAddr.SetSingleDevice(m_sourceMac->GetDevice()->GetIfIndex());
+    sockAddr.SetPhysicalAddress(destAddr);
+    sockAddr.SetProtocol(1);
 
     // install first client application generating at most 4 packets
-    auto client1 = CreateObject<PacketSocketClient>();
-    client1->SetAttribute("PacketSize", UintegerValue(1000));
-    client1->SetAttribute("MaxPackets", UintegerValue(std::min<std::size_t>(m_nPackets, 4)));
-    client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
-    client1->SetRemote(socket);
-    m_sourceMac->GetDevice()->GetNode()->AddApplication(client1);
-    client1->SetStartTime(Seconds(0)); // now
-    client1->SetStopTime(duration);
+    m_sourceMac->GetDevice()->GetNode()->AddApplication(
+        GetApplication(sockAddr, std::min<std::size_t>(m_nPackets, 4), 1000));
 
     if (m_nPackets > 4)
     {
-        // install a second client application generating the remaining packets
-        auto client2 = CreateObject<PacketSocketClient>();
-        client2->SetAttribute("PacketSize", UintegerValue(1000));
-        client2->SetAttribute("MaxPackets", UintegerValue(m_nPackets - 4));
-        client2->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
-        client2->SetRemote(socket);
-        m_sourceMac->GetDevice()->GetNode()->AddApplication(client2);
-        // start during transmission of first A-MPDU, if multiple links are setup
-        client2->SetStartTime(MilliSeconds(4));
-        client2->SetStopTime(duration);
-    }
-
-    // install a server on all nodes
-    for (auto nodeIt = NodeList::Begin(); nodeIt != NodeList::End(); nodeIt++)
-    {
-        Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
-        server->SetLocal(socket);
-        (*nodeIt)->AddApplication(server);
-        server->SetStartTime(Seconds(0)); // now
-        server->SetStopTime(duration);
+        // install a second client application generating the remaining packets and
+        // starting during transmission of first A-MPDU, if multiple links are setup
+        m_sourceMac->GetDevice()->GetNode()->AddApplication(
+            GetApplication(sockAddr, m_nPackets - 4, 1000, MilliSeconds(4)));
     }
 
-    for (std::size_t nodeId = 0; nodeId < NodeList::GetNNodes(); nodeId++)
-    {
-        Config::ConnectWithoutContext("/NodeList/" + std::to_string(nodeId) +
-                                          "/ApplicationList/*/$ns3::PacketSocketServer/Rx",
-                                      MakeCallback(&MultiLinkTxTest::L7Receive, this).Bind(nodeId));
-    }
-
-    Simulator::Stop(duration);
+    Simulator::Stop(m_duration);
 }
 
 void
@@ -1771,32 +2370,20 @@
     /**
      * Constructor
      *
+     * \param baseParams common configuration parameters
      * \param muTrafficPattern the pattern of traffic to generate
      * \param useBarAfterMissedBa whether a BAR or Data frames are sent after missed BlockAck
      * \param nMaxInflight the max number of links on which an MPDU can be simultaneously inflight
      *                     (unused if Block Ack agreements are not established)
-     * \param staChannels the strings specifying the operating channels for the STA
-     * \param apChannels the strings specifying the operating channels for the AP
-     * \param fixedPhyBands list of IDs of STA links that cannot switch PHY band
      */
-    MultiLinkMuTxTest(WifiMuTrafficPattern muTrafficPattern,
+    MultiLinkMuTxTest(const BaseParams& baseParams,
+                      WifiMuTrafficPattern muTrafficPattern,
                       WifiUseBarAfterMissedBa useBarAfterMissedBa,
-                      uint8_t nMaxInflight,
-                      const std::vector<std::string>& staChannels,
-                      const std::vector<std::string>& apChannels,
-                      const std::vector<uint8_t>& fixedPhyBands = {});
+                      uint8_t nMaxInflight);
     ~MultiLinkMuTxTest() override = default;
 
   protected:
     /**
-     * Function to trace packets received by the server application
-     * \param nodeId the ID of the node that received the packet
-     * \param p the packet
-     * \param addr the address
-     */
-    void L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr);
-
-    /**
      * Check the content of a received BlockAck frame when the max number of links on which
      * an MPDU can be inflight is one.
      *
@@ -1806,8 +2393,8 @@
      */
     void CheckBlockAck(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, uint8_t linkId);
 
-    void Transmit(uint8_t linkId,
-                  std::string context,
+    void Transmit(Ptr<WifiMac> mac,
+                  uint8_t phyId,
                   WifiConstPsduMap psduMap,
                   WifiTxVector txVector,
                   double txPowerW) override;
@@ -1836,19 +2423,15 @@
     std::size_t m_nPackets;                     ///< number of application packets to generate
     std::size_t m_blockAckCount{0};             ///< transmitted BlockAck counter
     // std::size_t m_blockAckReqCount{0};     ///< transmitted BlockAckReq counter
-    std::array<std::size_t, 3> m_rxPkts{}; ///< number of packets received at application layer
-                                           ///< by each node (AP, STA 0, STA 1)
     std::map<AddrSeqNoPair, std::size_t> m_inflightCount; ///< max number of simultaneous
                                                           ///< transmissions of each data frame
     Ptr<WifiMac> m_sourceMac; ///< MAC of the node sending application packets
 };
 
-MultiLinkMuTxTest::MultiLinkMuTxTest(WifiMuTrafficPattern muTrafficPattern,
+MultiLinkMuTxTest::MultiLinkMuTxTest(const BaseParams& baseParams,
+                                     WifiMuTrafficPattern muTrafficPattern,
                                      WifiUseBarAfterMissedBa useBarAfterMissedBa,
-                                     uint8_t nMaxInflight,
-                                     const std::vector<std::string>& staChannels,
-                                     const std::vector<std::string>& apChannels,
-                                     const std::vector<uint8_t>& fixedPhyBands)
+                                     uint8_t nMaxInflight)
     : MultiLinkOperationsTestBase(
           std::string("Check MU data transmission between MLDs ") +
               (useBarAfterMissedBa == WifiUseBarAfterMissedBa::YES
@@ -1857,9 +2440,7 @@
               " MU Traffic pattern: " + std::to_string(static_cast<uint8_t>(muTrafficPattern)) +
               ", nMaxInflight=" + std::to_string(nMaxInflight) + ")",
           2,
-          staChannels,
-          apChannels,
-          fixedPhyBands),
+          baseParams),
       m_muTrafficPattern(muTrafficPattern),
       m_useBarAfterMissedBa(useBarAfterMissedBa == WifiUseBarAfterMissedBa::YES),
       m_nMaxInflight(nMaxInflight),
@@ -1869,12 +2450,15 @@
 }
 
 void
-MultiLinkMuTxTest::Transmit(uint8_t linkId,
-                            std::string context,
+MultiLinkMuTxTest::Transmit(Ptr<WifiMac> mac,
+                            uint8_t phyId,
                             WifiConstPsduMap psduMap,
                             WifiTxVector txVector,
                             double txPowerW)
 {
+    MultiLinkOperationsTestBase::Transmit(mac, phyId, psduMap, txVector, txPowerW);
+    auto linkId = m_txPsdus.back().linkId;
+
     CtrlTriggerHeader trigger;
 
     for (const auto& [staId, psdu] : psduMap)
@@ -1976,29 +2560,20 @@
             {
                 m_waitFirstTf = false;
                 // the AP is starting the transmission of the Basic Trigger frame, so generate
-                // the configured number of packets at STAs, which are sent in TB PPDUs
-                auto band = m_apMac->GetWifiPhy(linkId)->GetPhyBand();
+                // the configured number of packets at STAs, which are sent in TB PPDUs, when
+                // transmission of the Trigger Frame ends
+                auto band = mac->GetWifiPhy(linkId)->GetPhyBand();
                 Time txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, band);
                 for (uint8_t i = 0; i < m_nStations; i++)
                 {
-                    Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient>();
-                    client->SetAttribute("PacketSize", UintegerValue(450));
-                    client->SetAttribute("MaxPackets", UintegerValue(m_nPackets));
-                    client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
-                    client->SetAttribute("Priority", UintegerValue(i * 4)); // 0 and 4
-                    client->SetRemote(m_sockets[i]);
-                    m_staMacs[i]->GetDevice()->GetNode()->AddApplication(client);
-                    client->SetStartTime(txDuration);  // start when TX ends
-                    client->SetStopTime(Seconds(1.0)); // stop in a second
-                    client->Initialize();
+                    m_staMacs[i]->GetDevice()->GetNode()->AddApplication(
+                        GetApplication(m_sockets[i], m_nPackets, 450, txDuration, i * 4));
                 }
             }
             break;
         default:;
         }
     }
-
-    MultiLinkOperationsTestBase::Transmit(linkId, context, psduMap, txVector, txPowerW);
 }
 
 void
@@ -2167,13 +2742,6 @@
 }
 
 void
-MultiLinkMuTxTest::L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr)
-{
-    NS_LOG_INFO("Packet received by NODE " << +nodeId << "\n");
-    m_rxPkts[nodeId]++;
-}
-
-void
 MultiLinkMuTxTest::DoSetup()
 {
     switch (m_muTrafficPattern)
@@ -2226,73 +2794,49 @@
         m_errorModels[m_apMac->GetFrameExchangeManager(linkId)->GetAddress()] = errorModel;
         m_apMac->GetWifiPhy(linkId)->SetPostReceptionErrorModel(errorModel);
     }
-    for (std::size_t linkId = 0; linkId < m_staMacs[0]->GetNLinks(); linkId++)
+    for (std::size_t i : {0, 1})
     {
-        auto errorModel = CreateObject<ListErrorModel>();
-        m_errorModels[m_staMacs[0]->GetFrameExchangeManager(linkId)->GetAddress()] = errorModel;
-        m_staMacs[0]->GetWifiPhy(linkId)->SetPostReceptionErrorModel(errorModel);
-
-        errorModel = CreateObject<ListErrorModel>();
-        m_errorModels[m_staMacs[1]->GetFrameExchangeManager(linkId)->GetAddress()] = errorModel;
-        m_staMacs[1]->GetWifiPhy(linkId)->SetPostReceptionErrorModel(errorModel);
+        for (const auto linkId : m_staMacs[i]->GetLinkIds())
+        {
+            auto errorModel = CreateObject<ListErrorModel>();
+            m_errorModels[m_staMacs[i]->GetFrameExchangeManager(linkId)->GetAddress()] = errorModel;
+            m_staMacs[i]->GetWifiPhy(linkId)->SetPostReceptionErrorModel(errorModel);
+        }
     }
 }
 
 void
 MultiLinkMuTxTest::StartTraffic()
 {
-    const Time duration = Seconds(1);
-    Address destAddr;
-
-    PacketSocketHelper packetSocket;
-    packetSocket.Install(m_apMac->GetDevice()->GetNode());
-    packetSocket.Install(m_staMacs[0]->GetDevice()->GetNode());
-    packetSocket.Install(m_staMacs[1]->GetDevice()->GetNode());
-
     if (m_muTrafficPattern < WifiMuTrafficPattern::UL_MU)
     {
         // DL Traffic
         for (uint8_t i = 0; i < m_nStations; i++)
         {
-            PacketSocketAddress socket;
-            socket.SetSingleDevice(m_apMac->GetDevice()->GetIfIndex());
-            socket.SetPhysicalAddress(m_staMacs[i]->GetDevice()->GetAddress());
-            socket.SetProtocol(1);
+            PacketSocketAddress sockAddr;
+            sockAddr.SetSingleDevice(m_apMac->GetDevice()->GetIfIndex());
+            sockAddr.SetPhysicalAddress(m_staMacs[i]->GetDevice()->GetAddress());
+            sockAddr.SetProtocol(1);
 
             // the first client application generates three packets in order
             // to trigger the establishment of a Block Ack agreement
-            auto client1 = CreateObject<PacketSocketClient>();
-            client1->SetAttribute("PacketSize", UintegerValue(450));
-            client1->SetAttribute("MaxPackets", UintegerValue(3));
-            client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
-            client1->SetRemote(socket);
-            m_apMac->GetDevice()->GetNode()->AddApplication(client1);
-            client1->SetStartTime(i * MilliSeconds(50));
-            client1->SetStopTime(duration);
+            m_apMac->GetDevice()->GetNode()->AddApplication(
+                GetApplication(sockAddr, 3, 450, i * MilliSeconds(50)));
 
             // the second client application generates the first half of the selected number
-            // of packets, which are sent in DL MU PPDUs.
-            auto client2 = CreateObject<PacketSocketClient>();
-            client2->SetAttribute("PacketSize", UintegerValue(450));
-            client2->SetAttribute("MaxPackets", UintegerValue(m_nPackets / 2));
-            client2->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
-            client2->SetRemote(socket);
-            m_apMac->GetDevice()->GetNode()->AddApplication(client2);
-            // start after all BA agreements are established
-            client2->SetStartTime(m_nStations * MilliSeconds(50));
-            client2->SetStopTime(duration);
+            // of packets, which are sent in DL MU PPDUs, and starts after all BA agreements
+            // are established
+            m_apMac->GetDevice()->GetNode()->AddApplication(
+                GetApplication(sockAddr, m_nPackets / 2, 450, m_nStations * MilliSeconds(50)));
 
             // the third client application generates the second half of the selected number
-            // of packets, which are sent in DL MU PPDUs.
-            auto client3 = CreateObject<PacketSocketClient>();
-            client3->SetAttribute("PacketSize", UintegerValue(450));
-            client3->SetAttribute("MaxPackets", UintegerValue(m_nPackets / 2));
-            client3->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
-            client3->SetRemote(socket);
-            m_apMac->GetDevice()->GetNode()->AddApplication(client3);
-            // start during transmission of first A-MPDU, if multiple links are setup
-            client3->SetStartTime(m_nStations * MilliSeconds(50) + MilliSeconds(3));
-            client3->SetStopTime(duration);
+            // of packets, which are sent in DL MU PPDUs, and starts during transmission of
+            // first A-MPDU, if multiple links are setup
+            m_apMac->GetDevice()->GetNode()->AddApplication(
+                GetApplication(sockAddr,
+                               m_nPackets / 2,
+                               450,
+                               m_nStations * MilliSeconds(50) + MilliSeconds(3)));
         }
     }
     else
@@ -2306,15 +2850,8 @@
 
             // the first client application generates three packets in order
             // to trigger the establishment of a Block Ack agreement
-            Ptr<PacketSocketClient> client1 = CreateObject<PacketSocketClient>();
-            client1->SetAttribute("PacketSize", UintegerValue(450));
-            client1->SetAttribute("MaxPackets", UintegerValue(3));
-            client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
-            client1->SetAttribute("Priority", UintegerValue(i * 4)); // 0 and 4
-            client1->SetRemote(m_sockets[i]);
-            m_staMacs[i]->GetDevice()->GetNode()->AddApplication(client1);
-            client1->SetStartTime(i * MilliSeconds(50));
-            client1->SetStopTime(duration);
+            m_staMacs[i]->GetDevice()->GetNode()->AddApplication(
+                GetApplication(m_sockets[i], 3, 450, i * MilliSeconds(50), i * 4));
 
             // packets to be included in TB PPDUs are generated (by Transmit()) when
             // the first Basic Trigger Frame is sent by the AP
@@ -2330,26 +2867,7 @@
         });
     }
 
-    // install a server on all nodes and connect traced callback
-    for (auto nodeIt = NodeList::Begin(); nodeIt != NodeList::End(); nodeIt++)
-    {
-        PacketSocketAddress srvAddr;
-        auto device = DynamicCast<WifiNetDevice>((*nodeIt)->GetDevice(0));
-        NS_TEST_ASSERT_MSG_NE(device, nullptr, "Expected a WifiNetDevice");
-        srvAddr.SetSingleDevice(device->GetIfIndex());
-        srvAddr.SetProtocol(1);
-
-        Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
-        server->SetLocal(srvAddr);
-        (*nodeIt)->AddApplication(server);
-        server->SetStartTime(Seconds(0)); // now
-        server->SetStopTime(duration);
-        server->TraceConnectWithoutContext(
-            "Rx",
-            MakeCallback(&MultiLinkMuTxTest::L7Receive, this).Bind(device->GetNode()->GetId()));
-    }
-
-    Simulator::Stop(duration);
+    Simulator::Stop(m_duration);
 }
 
 void
@@ -2441,8 +2959,8 @@
   protected:
     void DoSetup() override;
     void DoRun() override;
-    void Transmit(uint8_t linkId,
-                  std::string context,
+    void Transmit(Ptr<WifiMac> mac,
+                  uint8_t phyId,
                   WifiConstPsduMap psduMap,
                   WifiTxVector txVector,
                   double txPowerW) override;
@@ -2450,12 +2968,7 @@
   private:
     void StartTraffic() override;
 
-    /**
-     * \return the client application generating 4 packets addressed to the non-AP MLD
-     */
-    Ptr<PacketSocketClient> GetApplication() const;
-
-    PacketSocketAddress m_socket;     //!< packet socket address
+    PacketSocketAddress m_sockAddr;   //!< packet socket address
     std::size_t m_nQosDataFrames;     //!< counter for transmitted QoS data frames
     Ptr<ListErrorModel> m_errorModel; //!< error rate model to corrupt first RTS frame
     bool m_rtsCorrupted;              //!< whether the first RTS frame has been corrupted
@@ -2465,8 +2978,9 @@
     : MultiLinkOperationsTestBase(
           "Check sequence numbers after CTS timeout",
           1,
-          {"{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}"}),
+          BaseParams{{"{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}"},
+                     {}}),
       m_nQosDataFrames(0),
       m_errorModel(CreateObject<ListErrorModel>()),
       m_rtsCorrupted(false)
@@ -2482,62 +2996,32 @@
     MultiLinkOperationsTestBase::DoSetup();
 
     // install post reception error model on all STAs affiliated with non-AP MLD
-    for (std::size_t linkId = 0; linkId < m_staMacs[0]->GetNLinks(); linkId++)
+    for (const auto linkId : m_staMacs[0]->GetLinkIds())
     {
         m_staMacs[0]->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_errorModel);
     }
 }
 
-Ptr<PacketSocketClient>
-ReleaseSeqNoAfterCtsTimeoutTest::GetApplication() const
-{
-    const Time duration = Seconds(1);
-
-    auto client = CreateObject<PacketSocketClient>();
-    client->SetAttribute("PacketSize", UintegerValue(1000));
-    client->SetAttribute("MaxPackets", UintegerValue(4));
-    client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
-    client->SetRemote(m_socket);
-    client->SetStartTime(Seconds(0)); // now
-    client->SetStopTime(duration);
-
-    return client;
-}
-
 void
 ReleaseSeqNoAfterCtsTimeoutTest::StartTraffic()
 {
-    const Time duration = Seconds(1);
-
-    PacketSocketHelper packetSocket;
-    packetSocket.Install(m_apMac->GetDevice()->GetNode());
-    packetSocket.Install(m_staMacs[0]->GetDevice()->GetNode());
-
-    m_socket.SetSingleDevice(m_apMac->GetDevice()->GetIfIndex());
-    m_socket.SetPhysicalAddress(m_staMacs[0]->GetAddress());
-    m_socket.SetProtocol(1);
+    m_sockAddr.SetSingleDevice(m_apMac->GetDevice()->GetIfIndex());
+    m_sockAddr.SetPhysicalAddress(m_staMacs[0]->GetAddress());
+    m_sockAddr.SetProtocol(1);
 
     // install client application generating 4 packets
-    m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication());
-
-    // install a server on all nodes
-    for (auto nodeIt = NodeList::Begin(); nodeIt != NodeList::End(); nodeIt++)
-    {
-        Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
-        server->SetLocal(m_socket);
-        (*nodeIt)->AddApplication(server);
-        server->SetStartTime(Seconds(0)); // now
-        server->SetStopTime(duration);
-    }
+    m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication(m_sockAddr, 4, 1000));
 }
 
 void
-ReleaseSeqNoAfterCtsTimeoutTest::Transmit(uint8_t linkId,
-                                          std::string context,
+ReleaseSeqNoAfterCtsTimeoutTest::Transmit(Ptr<WifiMac> mac,
+                                          uint8_t phyId,
                                           WifiConstPsduMap psduMap,
                                           WifiTxVector txVector,
                                           double txPowerW)
 {
+    MultiLinkOperationsTestBase::Transmit(mac, phyId, psduMap, txVector, txPowerW);
+
     auto psdu = psduMap.begin()->second;
 
     if (psdu->GetHeader(0).IsRts() && !m_rtsCorrupted)
@@ -2545,7 +3029,7 @@
         m_errorModel->SetList({psdu->GetPacket()->GetUid()});
         m_rtsCorrupted = true;
         // generate other packets when the first RTS is transmitted
-        m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication());
+        m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication(m_sockAddr, 4, 1000));
     }
     else if (psdu->GetHeader(0).IsQosData())
     {
@@ -2554,17 +3038,15 @@
         if (m_nQosDataFrames == 2)
         {
             // generate other packets when the second QoS data frame is transmitted
-            m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication());
+            m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication(m_sockAddr, 4, 1000));
         }
     }
-
-    MultiLinkOperationsTestBase::Transmit(linkId, context, psduMap, txVector, txPowerW);
 }
 
 void
 ReleaseSeqNoAfterCtsTimeoutTest::DoRun()
 {
-    Simulator::Stop(Seconds(1.0));
+    Simulator::Stop(m_duration);
     Simulator::Run();
 
     NS_TEST_EXPECT_MSG_EQ(m_nQosDataFrames, 3, "Unexpected number of transmitted QoS data frames");
@@ -2624,89 +3106,127 @@
 WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
     : TestSuite("wifi-mlo", UNIT)
 {
-    using ParamsTuple =
-        std::tuple<std::vector<std::string>,                 // non-AP MLD channels
-                   std::vector<std::string>,                 // AP MLD channels
-                   std::vector<std::pair<uint8_t, uint8_t>>, // (STA link ID, AP link ID) of setup
-                                                             // links
-                   std::vector<uint8_t>>; // IDs of link that cannot change PHY band
+    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
 
     AddTestCase(new GetRnrLinkInfoTest(), TestCase::QUICK);
+    AddTestCase(new MldSwapLinksTest(), TestCase::QUICK);
 
-    for (const auto& [staChannels, apChannels, setupLinks, fixedPhyBands] :
+    for (const auto& [baseParams,
+                      setupLinks,
+                      apNegSupport,
+                      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, 0}, {1, 1}, {2, 2}},
-                      {}),
+          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
+                      ),
           // 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}"},
-                      {{1, 0}, {0, 1}, {2, 2}},
-                      {}),
+          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
+                      ""),
           // 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}"},
-                      {{2, 0}, {0, 1}, {1, 2}},
-                      {}),
+          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,
+                      "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
+                      ),
           // the first link of the non-AP MLD cannot change PHY band and no AP is operating on
           // that band, hence only 2 links are setup
           ParamsTuple(
-              {"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
-              {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
-              {{1, 0}, {2, 1}},
-              {0}),
+              {{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
+               {"{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
+              "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
           // that band; the second link of the non-AP MLD cannot change PHY band and there is
           // an AP operating on the same channel; hence 2 links are setup
           ParamsTuple(
-              {"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
-              {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
-              {{1, 0}, {2, 1}},
-              {0, 1}),
+              {{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
+               {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
+               {0, 1}},
+              {0, 1},
+              3,
+              "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
           // that band; the second link of the non-AP MLD cannot change PHY band and there is
           // an AP operating on the same channel; the third link of the non-AP MLD cannot
           // change PHY band and there is an AP operating on the same band (different channel);
           // hence 2 links are setup by switching channel (not band) on the third link
-          ParamsTuple({"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{60, 0, BAND_5GHZ, 0}"},
-                      {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
-                      {{1, 0}, {2, 2}},
-                      {0, 1, 2}),
+          ParamsTuple({{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{60, 0, BAND_5GHZ, 0}"},
+                       {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
+                       {0, 1, 2}},
+                      {0, 2},
+                      3,
+                      "",
+                      ""),
           // the first link of the non-AP MLD cannot change PHY band and no AP is operating on
           // that band; the second link of the non-AP MLD cannot change PHY band and there is
           // an AP operating on the same channel; hence one link only is setup
-          ParamsTuple({"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
-                      {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
-                      {{1, 0}},
-                      {0, 1}),
+          ParamsTuple({{"{2, 0, BAND_2_4GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
+                       {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
+                       {0, 1}},
+                      {2},
+                      3,
+                      "",
+                      ""),
           // non-AP MLD has only two STAs and setups two links
-          ParamsTuple({"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
-                      {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
-                      {{0, 1}, {1, 0}},
-                      {}),
+          ParamsTuple({{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
+                       {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
+                       {}},
+                      {1, 0},
+                      3,
+                      "0,1,2,3  1",
+                      ""),
           // single link non-AP STA associates with an AP affiliated with an AP MLD
-          ParamsTuple({"{120, 0, BAND_5GHZ, 0}"},
-                      {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
-                      {{0, 2}},
-                      {}),
+          ParamsTuple({{"{120, 0, BAND_5GHZ, 0}"},
+                       {"{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,
+                      "",
+                      ""),
           // a STA affiliated with a non-AP MLD associates with a single link AP
-          ParamsTuple({"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
-                      {"{120, 0, BAND_5GHZ, 0}"},
-                      {{2, 0}},
-                      {})})
+          ParamsTuple({{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
+                       {"{120, 0, BAND_5GHZ, 0}"},
+                       {}},
+                      {2}, // link ID of non-AP MLD only (AP is single link)
+                      0,
+                      "0,1,2,3  0,1;  4,5,6,7  0,1", // ignored by single link AP
+                      "")})
     {
-        AddTestCase(new MultiLinkSetupTest(staChannels,
-                                           apChannels,
+        AddTestCase(new MultiLinkSetupTest(baseParams,
                                            WifiScanType::PASSIVE,
                                            setupLinks,
-                                           fixedPhyBands),
+                                           apNegSupport,
+                                           dlTidLinkMapping,
+                                           ulTidLinkMapping),
                     TestCase::QUICK);
-        AddTestCase(new MultiLinkSetupTest(staChannels,
-                                           apChannels,
+        AddTestCase(new MultiLinkSetupTest(baseParams,
                                            WifiScanType::ACTIVE,
                                            setupLinks,
-                                           fixedPhyBands),
+                                           apNegSupport,
+                                           dlTidLinkMapping,
+                                           ulTidLinkMapping),
                     TestCase::QUICK);
 
         for (const auto& trafficPattern : {WifiTrafficPattern::STA_TO_STA,
@@ -2716,34 +3236,28 @@
                                            WifiTrafficPattern::STA_TO_BCAST})
         {
             // No Block Ack agreement
-            AddTestCase(new MultiLinkTxTest(trafficPattern,
+            AddTestCase(new MultiLinkTxTest(baseParams,
+                                            trafficPattern,
                                             WifiBaEnabled::NO,
                                             WifiUseBarAfterMissedBa::NO,
-                                            1,
-                                            staChannels,
-                                            apChannels,
-                                            fixedPhyBands),
+                                            1),
                         TestCase::QUICK);
             for (const auto& useBarAfterMissedBa :
                  {WifiUseBarAfterMissedBa::YES, WifiUseBarAfterMissedBa::NO})
             {
                 // Block Ack agreement with nMaxInflight=1
-                AddTestCase(new MultiLinkTxTest(trafficPattern,
+                AddTestCase(new MultiLinkTxTest(baseParams,
+                                                trafficPattern,
                                                 WifiBaEnabled::YES,
                                                 useBarAfterMissedBa,
-                                                1,
-                                                staChannels,
-                                                apChannels,
-                                                fixedPhyBands),
+                                                1),
                             TestCase::QUICK);
                 // Block Ack agreement with nMaxInflight=2
-                AddTestCase(new MultiLinkTxTest(trafficPattern,
+                AddTestCase(new MultiLinkTxTest(baseParams,
+                                                trafficPattern,
                                                 WifiBaEnabled::YES,
                                                 useBarAfterMissedBa,
-                                                2,
-                                                staChannels,
-                                                apChannels,
-                                                fixedPhyBands),
+                                                2),
                             TestCase::QUICK);
             }
         }
@@ -2757,21 +3271,13 @@
                  {WifiUseBarAfterMissedBa::YES, WifiUseBarAfterMissedBa::NO})
             {
                 // Block Ack agreement with nMaxInflight=1
-                AddTestCase(new MultiLinkMuTxTest(muTrafficPattern,
-                                                  useBarAfterMissedBa,
-                                                  1,
-                                                  staChannels,
-                                                  apChannels,
-                                                  fixedPhyBands),
-                            TestCase::QUICK);
+                AddTestCase(
+                    new MultiLinkMuTxTest(baseParams, muTrafficPattern, useBarAfterMissedBa, 1),
+                    TestCase::QUICK);
                 // Block Ack agreement with nMaxInflight=2
-                AddTestCase(new MultiLinkMuTxTest(muTrafficPattern,
-                                                  useBarAfterMissedBa,
-                                                  2,
-                                                  staChannels,
-                                                  apChannels,
-                                                  fixedPhyBands),
-                            TestCase::QUICK);
+                AddTestCase(
+                    new MultiLinkMuTxTest(baseParams, muTrafficPattern, useBarAfterMissedBa, 2),
+                    TestCase::QUICK);
             }
         }
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-non-ht-dup-test.cc ns-3.40/src/wifi/test/wifi-non-ht-dup-test.cc
--- ns-3.39/src/wifi/test/wifi-non-ht-dup-test.cc	2023-07-05 14:23:48.129428400 -0700
+++ ns-3.40/src/wifi/test/wifi-non-ht-dup-test.cc	2023-09-27 13:30:37.926839800 -0700
@@ -386,6 +386,11 @@
                                           std::vector<bool> /*statusPerMpdu*/)
 {
     NS_LOG_FUNCTION(this << index << *psdu << rxSignalInfo << txVector);
+    const auto expectedWidth =
+        std::min(m_phyAp->GetChannelWidth(), m_phyStas.at(index)->GetChannelWidth());
+    NS_TEST_ASSERT_MSG_EQ(txVector.GetChannelWidth(),
+                          expectedWidth,
+                          "Incorrect channel width in TXVECTOR");
     m_countRxSuccessStas.at(index)++;
 }
 
@@ -616,16 +621,26 @@
  * The test is checking whether the reception of multiple identical CTS frames as a response to a
  * MU-RTS frame is successfully received by the AP PHY and that only a single CTS frame is forwarded
  * up to the MAC. Since the test is focusing on the PHY reception of multiple CTS response, the
- * transmission of the MU-RTS frame is faked.
+ * transmission of the MU-RTS frame is faked. The test also checks the correct channel width is
+ * passed to the MAC layer through the TXVECTOR. The test also consider the case some STAs do not
+ * respond to verify the largest channel width of the successfully CTS responses is reported to the
+ * MAC.
  */
 class TestMultipleCtsResponsesFromMuRts : public TestCase
 {
   public:
+    /// Information about CTS responses to expect in the test
+    struct CtsTxInfos
+    {
+        uint16_t bw{20};     ///< the width in MHz of the CTS response
+        bool discard{false}; ///< flag whether the CTS response shall be discarded
+    };
+
     /**
      * Constructor
-     * \param bwPerSta the bandwidth to use for each STA (in MHz)
+     * \param ctsTxInfosPerSta the information about CTS responses to generate
      */
-    TestMultipleCtsResponsesFromMuRts(const std::vector<uint16_t>& bwPerSta);
+    TestMultipleCtsResponsesFromMuRts(const std::vector<CtsTxInfos>& ctsTxInfosPerSta);
 
   private:
     void DoSetup() override;
@@ -634,71 +649,81 @@
 
     /**
      * Function called to fake the transmission of a MU-RTS.
-     *
-     * \param bw the bandwidth to use for the transmission in MHz
      */
-    void FakePreviousMuRts(uint16_t bw);
+    void FakePreviousMuRts();
 
     /**
      * Function called to trigger a CTS frame sent by a STA using non-HT duplicate.
      *
-     * \param phy the PHY of the STA
-     * \param bw the bandwidth to use for the transmission in MHz
+     * \param phyIndex the index of the TX PHY
      */
-    void TxNonHtDuplicateCts(Ptr<SpectrumWifiPhy> phy, uint16_t bw);
+    void TxNonHtDuplicateCts(std::size_t phyIndex);
 
     /**
      * CTS RX success function
+     * \param phyIndex the index of the PHY (0 for AP)
      * \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 RxCtsSuccess(Ptr<const WifiPsdu> psdu,
+    void RxCtsSuccess(std::size_t phyIndex,
+                      Ptr<const WifiPsdu> psdu,
                       RxSignalInfo rxSignalInfo,
                       WifiTxVector txVector,
                       std::vector<bool> statusPerMpdu);
 
     /**
      * CTS RX failure function
+     * \param phyIndex the index of the PHY (0 for AP)
      * \param psdu the PSDU
      */
-    void RxCtsFailure(Ptr<const WifiPsdu> psdu);
+    void RxCtsFailure(std::size_t phyIndex, Ptr<const WifiPsdu> psdu);
 
     /**
      * Check the results
-     * \param expectedRxCtsSuccess the expected number of CTS RX success
-     * \param expectedRxCtsFailure the expected number of CTS RX failures
      */
-    void CheckResults(std::size_t expectedRxCtsSuccess, std::size_t expectedRxCtsFailure);
+    void CheckResults();
 
     Ptr<MuRtsCtsSpectrumWifiPhy> m_phyAp;                ///< AP PHY
     std::vector<Ptr<MuRtsCtsSpectrumWifiPhy>> m_phyStas; ///< STAs PHYs
-    Ptr<SpectrumWifiPhy> m_nonHePhySta;                  ///< non-HE STA PHY
 
-    std::vector<uint16_t> m_bwPerSta; ///< Bandwidth per STA in MHz
+    std::vector<CtsTxInfos> m_ctsTxInfosPerSta; ///< information about CTS responses
 
-    std::size_t m_countRxCtsSuccess; ///< count the number of successfully received CTS frames
-    std::size_t m_countRxCtsFailure; ///< count the number of unsuccessfully received CTS frames
+    std::size_t
+        m_countApRxCtsSuccess; ///< count the number of successfully received CTS frames by the AP
+    std::size_t
+        m_countApRxCtsFailure; ///< count the number of unsuccessfully received CTS frames by the AP
+    std::size_t m_countStaRxCtsSuccess; ///< count the number of successfully received CTS frames by
+                                        ///< the non-participating STA
+    std::size_t m_countStaRxCtsFailure; ///< count the number of unsuccessfully received CTS frames
+                                        ///< by the non-participating STA
 
     double m_stasTxPowerDbm; ///< TX power in dBm configured for the STAs
 };
 
 TestMultipleCtsResponsesFromMuRts::TestMultipleCtsResponsesFromMuRts(
-    const std::vector<uint16_t>& bwPerSta)
+    const std::vector<CtsTxInfos>& ctsTxInfosPerSta)
     : TestCase{"test PHY reception of multiple CTS frames following a MU-RTS frame"},
-      m_bwPerSta{bwPerSta},
-      m_countRxCtsSuccess{0},
-      m_countRxCtsFailure{0},
+      m_ctsTxInfosPerSta{ctsTxInfosPerSta},
+      m_countApRxCtsSuccess{0},
+      m_countApRxCtsFailure{0},
+      m_countStaRxCtsSuccess{0},
+      m_countStaRxCtsFailure{0},
       m_stasTxPowerDbm(10.0)
 {
 }
 
 void
-TestMultipleCtsResponsesFromMuRts::FakePreviousMuRts(uint16_t bw)
+TestMultipleCtsResponsesFromMuRts::FakePreviousMuRts()
 {
-    NS_LOG_FUNCTION(this << bw);
+    NS_LOG_FUNCTION(this);
 
+    const auto bw =
+        std::max_element(m_ctsTxInfosPerSta.cbegin(),
+                         m_ctsTxInfosPerSta.cend(),
+                         [](const auto& lhs, const auto& rhs) { return lhs.bw < rhs.bw; })
+            ->bw;
     WifiTxVector txVector;
     txVector.SetChannelWidth(bw); // only the channel width matters for this test
 
@@ -714,9 +739,16 @@
 }
 
 void
-TestMultipleCtsResponsesFromMuRts::TxNonHtDuplicateCts(Ptr<SpectrumWifiPhy> phy, uint16_t bw)
+TestMultipleCtsResponsesFromMuRts::TxNonHtDuplicateCts(std::size_t phyIndex)
 {
-    NS_LOG_FUNCTION(this << phy << bw);
+    const auto bw = m_ctsTxInfosPerSta.at(phyIndex).bw;
+    const auto discarded = m_ctsTxInfosPerSta.at(phyIndex).discard;
+    NS_LOG_FUNCTION(this << phyIndex << bw << discarded);
+
+    if (discarded)
+    {
+        return;
+    }
 
     WifiTxVector txVector =
         WifiTxVector(OfdmPhy::GetOfdmRate54Mbps(), // use less robust modulation for test purpose
@@ -742,40 +774,84 @@
     auto mpdu = Create<WifiMpdu>(pkt, hdr);
     auto psdu = Create<WifiPsdu>(mpdu, false);
 
-    phy->Send(psdu, txVector);
+    m_phyStas.at(phyIndex)->Send(psdu, txVector);
 }
 
 void
-TestMultipleCtsResponsesFromMuRts::RxCtsSuccess(Ptr<const WifiPsdu> psdu,
+TestMultipleCtsResponsesFromMuRts::RxCtsSuccess(std::size_t phyIndex,
+                                                Ptr<const WifiPsdu> psdu,
                                                 RxSignalInfo rxSignalInfo,
                                                 WifiTxVector txVector,
                                                 std::vector<bool> /*statusPerMpdu*/)
 {
-    NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
-    NS_TEST_EXPECT_MSG_EQ_TOL(rxSignalInfo.rssi,
-                              WToDbm(DbmToW(m_stasTxPowerDbm) * m_bwPerSta.size()),
-                              0.1,
-                              "RX power is not correct!");
-    m_countRxCtsSuccess++;
+    NS_LOG_FUNCTION(this << phyIndex << *psdu << rxSignalInfo << txVector);
+    std::vector<CtsTxInfos> successfulCtsInfos{};
+    std::copy_if(m_ctsTxInfosPerSta.cbegin(),
+                 m_ctsTxInfosPerSta.cend(),
+                 std::back_inserter(successfulCtsInfos),
+                 [](const auto& info) { return !info.discard; });
+    const auto isAp = (phyIndex == 0);
+    if (isAp)
+    {
+        NS_TEST_EXPECT_MSG_EQ_TOL(rxSignalInfo.rssi,
+                                  WToDbm(DbmToW(m_stasTxPowerDbm) * successfulCtsInfos.size()),
+                                  0.1,
+                                  "RX power is not correct!");
+    }
+    auto expectedWidth =
+        std::max_element(successfulCtsInfos.cbegin(),
+                         successfulCtsInfos.cend(),
+                         [](const auto& lhs, const auto& rhs) { return lhs.bw < rhs.bw; })
+            ->bw;
+    if (!isAp)
+    {
+        expectedWidth = std::min(m_ctsTxInfosPerSta.at(phyIndex - 1).bw, expectedWidth);
+    }
+    NS_TEST_ASSERT_MSG_EQ(txVector.GetChannelWidth(),
+                          expectedWidth,
+                          "Incorrect channel width in TXVECTOR");
+    if (isAp)
+    {
+        m_countApRxCtsSuccess++;
+    }
+    else
+    {
+        m_countStaRxCtsSuccess++;
+    }
 }
 
 void
-TestMultipleCtsResponsesFromMuRts::RxCtsFailure(Ptr<const WifiPsdu> psdu)
+TestMultipleCtsResponsesFromMuRts::RxCtsFailure(std::size_t phyIndex, Ptr<const WifiPsdu> psdu)
 {
-    NS_LOG_FUNCTION(this << *psdu);
-    m_countRxCtsFailure++;
+    NS_LOG_FUNCTION(this << phyIndex << *psdu);
+    const auto isAp = (phyIndex == 0);
+    if (isAp)
+    {
+        m_countApRxCtsFailure++;
+    }
+    else
+    {
+        m_countStaRxCtsFailure++;
+    }
 }
 
 void
-TestMultipleCtsResponsesFromMuRts::CheckResults(std::size_t expectedRxCtsSuccess,
-                                                std::size_t expectedRxCtsFailure)
+TestMultipleCtsResponsesFromMuRts::CheckResults()
 {
-    NS_TEST_ASSERT_MSG_EQ(m_countRxCtsSuccess,
-                          expectedRxCtsSuccess,
+    NS_TEST_ASSERT_MSG_EQ(m_countApRxCtsSuccess,
+                          1,
                           "The number of successfully received CTS frames by AP is not correct!");
-    NS_TEST_ASSERT_MSG_EQ(m_countRxCtsFailure,
-                          expectedRxCtsFailure,
+    NS_TEST_ASSERT_MSG_EQ(
+        m_countStaRxCtsSuccess,
+        m_ctsTxInfosPerSta.size(),
+        "The number of successfully received CTS frames by non-participating STAs is not correct!");
+    NS_TEST_ASSERT_MSG_EQ(m_countApRxCtsFailure,
+                          0,
                           "The number of unsuccessfully received CTS frames by AP is not correct!");
+    NS_TEST_ASSERT_MSG_EQ(m_countStaRxCtsFailure,
+                          0,
+                          "The number of unsuccessfully received CTS frames by non-participating "
+                          "STAs is not correct!");
 }
 
 void
@@ -809,11 +885,15 @@
     m_phyAp->AssignStreams(streamNumber);
 
     m_phyAp->SetReceiveOkCallback(
-        MakeCallback(&TestMultipleCtsResponsesFromMuRts::RxCtsSuccess, this));
+        MakeCallback(&TestMultipleCtsResponsesFromMuRts::RxCtsSuccess, this).Bind(0));
     m_phyAp->SetReceiveErrorCallback(
-        MakeCallback(&TestMultipleCtsResponsesFromMuRts::RxCtsFailure, this));
+        MakeCallback(&TestMultipleCtsResponsesFromMuRts::RxCtsFailure, this).Bind(0));
 
-    const auto apBw = *std::max_element(m_bwPerSta.cbegin(), m_bwPerSta.cend());
+    const auto apBw =
+        std::max_element(m_ctsTxInfosPerSta.cbegin(),
+                         m_ctsTxInfosPerSta.cend(),
+                         [](const auto& lhs, const auto& rhs) { return lhs.bw < rhs.bw; })
+            ->bw;
     auto apChannelNum = std::get<0>(
         *WifiPhyOperatingChannel::FindFirst(0, 0, apBw, WIFI_STANDARD_80211ac, WIFI_PHY_BAND_5GHZ));
 
@@ -828,7 +908,7 @@
     apNode->AggregateObject(apMobility);
     apNode->AddDevice(apDev);
 
-    for (std::size_t i = 0; i < m_bwPerSta.size(); ++i)
+    for (std::size_t i = 0; i < m_ctsTxInfosPerSta.size(); ++i)
     {
         auto staNode = CreateObject<Node>();
         auto staDev = CreateObject<WifiNetDevice>();
@@ -844,14 +924,15 @@
         phySta->SetTxPowerStart(m_stasTxPowerDbm);
         phySta->SetTxPowerEnd(m_stasTxPowerDbm);
 
-        auto channelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
-                                                                          0,
-                                                                          m_bwPerSta.at(i),
-                                                                          WIFI_STANDARD_80211ac,
-                                                                          WIFI_PHY_BAND_5GHZ));
+        auto channelNum =
+            std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
+                                                            0,
+                                                            m_ctsTxInfosPerSta.at(i).bw,
+                                                            WIFI_STANDARD_80211ac,
+                                                            WIFI_PHY_BAND_5GHZ));
 
         phySta->SetOperatingChannel(
-            WifiPhy::ChannelTuple{channelNum, m_bwPerSta.at(i), WIFI_PHY_BAND_5GHZ, 0});
+            WifiPhy::ChannelTuple{channelNum, m_ctsTxInfosPerSta.at(i).bw, WIFI_PHY_BAND_5GHZ, 0});
 
         auto staMobility = CreateObject<ConstantPositionMobilityModel>();
         phySta->SetMobility(staMobility);
@@ -861,26 +942,55 @@
         staNode->AggregateObject(staMobility);
         staNode->AddDevice(staDev);
         m_phyStas.push_back(phySta);
+
+        // non-participating HE STA
+        auto nonParticipatingHeStaNode = CreateObject<Node>();
+        auto nonParticipatingHeStaDev = CreateObject<WifiNetDevice>();
+        auto nonParticipatingHePhySta = CreateObject<SpectrumWifiPhy>();
+        auto nonParticipatingHeStaInterferenceHelper = CreateObject<InterferenceHelper>();
+        nonParticipatingHePhySta->SetInterferenceHelper(nonParticipatingHeStaInterferenceHelper);
+        auto nonParticipatingHeStaErrorModel = CreateObject<NistErrorRateModel>();
+        nonParticipatingHePhySta->SetErrorRateModel(nonParticipatingHeStaErrorModel);
+        nonParticipatingHePhySta->SetDevice(nonParticipatingHeStaDev);
+        nonParticipatingHePhySta->AddChannel(spectrumChannel);
+        nonParticipatingHePhySta->ConfigureStandard(WIFI_STANDARD_80211ax);
+
+        nonParticipatingHePhySta->SetOperatingChannel(
+            WifiPhy::ChannelTuple{channelNum, m_ctsTxInfosPerSta.at(i).bw, WIFI_PHY_BAND_5GHZ, 0});
+
+        auto nonParticipatingHeStaMobility = CreateObject<ConstantPositionMobilityModel>();
+        nonParticipatingHePhySta->SetMobility(nonParticipatingHeStaMobility);
+        nonParticipatingHeStaDev->SetPhy(nonParticipatingHePhySta);
+        nonParticipatingHeStaDev->SetStandard(WIFI_STANDARD_80211ax);
+        nonParticipatingHeStaDev->SetHeConfiguration(CreateObject<HeConfiguration>());
+        nonParticipatingHePhySta->AssignStreams(streamNumber);
+        nonParticipatingHeStaNode->AggregateObject(nonParticipatingHeStaMobility);
+        nonParticipatingHeStaNode->AddDevice(nonParticipatingHeStaDev);
+
+        nonParticipatingHePhySta->SetReceiveOkCallback(
+            MakeCallback(&TestMultipleCtsResponsesFromMuRts::RxCtsSuccess, this).Bind(i + 1));
+        nonParticipatingHePhySta->SetReceiveErrorCallback(
+            MakeCallback(&TestMultipleCtsResponsesFromMuRts::RxCtsFailure, this).Bind(i + 1));
     }
 
     // non-HE STA
     auto nonHeStaNode = CreateObject<Node>();
     auto nonHeStaDev = CreateObject<WifiNetDevice>();
-    m_nonHePhySta = CreateObject<SpectrumWifiPhy>();
+    auto nonHePhySta = CreateObject<SpectrumWifiPhy>();
     auto nonHeStaInterferenceHelper = CreateObject<InterferenceHelper>();
-    m_nonHePhySta->SetInterferenceHelper(nonHeStaInterferenceHelper);
+    nonHePhySta->SetInterferenceHelper(nonHeStaInterferenceHelper);
     auto nonHeStaErrorModel = CreateObject<NistErrorRateModel>();
-    m_nonHePhySta->SetErrorRateModel(nonHeStaErrorModel);
-    m_nonHePhySta->SetDevice(nonHeStaDev);
-    m_nonHePhySta->AddChannel(spectrumChannel);
-    m_nonHePhySta->ConfigureStandard(WIFI_STANDARD_80211ac);
-    m_nonHePhySta->SetOperatingChannel(
+    nonHePhySta->SetErrorRateModel(nonHeStaErrorModel);
+    nonHePhySta->SetDevice(nonHeStaDev);
+    nonHePhySta->AddChannel(spectrumChannel);
+    nonHePhySta->ConfigureStandard(WIFI_STANDARD_80211ac);
+    nonHePhySta->SetOperatingChannel(
         WifiPhy::ChannelTuple{apChannelNum, apBw, WIFI_PHY_BAND_5GHZ, 0});
     auto nonHeStaMobility = CreateObject<ConstantPositionMobilityModel>();
-    m_nonHePhySta->SetMobility(nonHeStaMobility);
-    nonHeStaDev->SetPhy(m_nonHePhySta);
+    nonHePhySta->SetMobility(nonHeStaMobility);
+    nonHeStaDev->SetPhy(nonHePhySta);
     nonHeStaDev->SetStandard(WIFI_STANDARD_80211ac);
-    m_nonHePhySta->AssignStreams(streamNumber);
+    nonHePhySta->AssignStreams(streamNumber);
     nonHeStaNode->AggregateObject(nonHeStaMobility);
     nonHeStaNode->AddDevice(nonHeStaDev);
 }
@@ -902,28 +1012,22 @@
 TestMultipleCtsResponsesFromMuRts::DoRun()
 {
     // Fake transmission of a MU-RTS frame preceding the CTS responses
-    Simulator::Schedule(Seconds(0.0),
-                        &TestMultipleCtsResponsesFromMuRts::FakePreviousMuRts,
-                        this,
-                        *std::max_element(m_bwPerSta.cbegin(), m_bwPerSta.cend()));
+    Simulator::Schedule(Seconds(0.0), &TestMultipleCtsResponsesFromMuRts::FakePreviousMuRts, this);
 
-    std::size_t index = 1;
-    for (auto& phySta : m_phyStas)
+    for (std::size_t index = 0; index < m_phyStas.size(); ++index)
     {
         // Transmit CTS responses over their operating bandwidth with 1 nanosecond delay between
         // each other
-        const auto delay = index * NanoSeconds(1.0);
-        Simulator::Schedule(Seconds(0.0) + delay,
+        const auto delay = (index + 1) * NanoSeconds(1.0);
+        Simulator::Schedule(delay,
                             &TestMultipleCtsResponsesFromMuRts::TxNonHtDuplicateCts,
                             this,
-                            phySta,
-                            m_bwPerSta.at(index - 1));
-        index++;
+                            index);
     }
 
     // Verify successful reception of the CTS frames: since multiple copies are sent
     // simultaneously, a single CTS frame should be forwarded up to the MAC.
-    Simulator::Schedule(Seconds(1.0), &TestMultipleCtsResponsesFromMuRts::CheckResults, this, 1, 0);
+    Simulator::Schedule(Seconds(1.0), &TestMultipleCtsResponsesFromMuRts::CheckResults, this);
 
     Simulator::Run();
     Simulator::Destroy();
@@ -994,18 +1098,34 @@
                                                     {WIFI_STANDARD_80211ac, 5230, 0}},
                                                    {false, true, false, false}),
                 TestCase::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::QUICK);
     /* 4 STAs operating on 40 MHz */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({40, 40, 40, 40}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{40}, {40}, {40}, {40}}), TestCase::QUICK);
     /* 4 STAs operating on 80 MHz */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({80, 80, 80, 80}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{80}, {80}, {80}, {80}}), TestCase::QUICK);
     /* 4 STAs operating on 160 MHz */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({160, 160, 160, 160}), TestCase::QUICK);
-    /* 4 STAs operating on different bandwidths: 160, 80, 40 and 20 MHz */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({160, 80, 40, 20}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{160}, {160}, {160}, {160}}),
+                TestCase::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);
+    /* 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);
+    /* 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);
+    /* 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);
+    /* 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);
+    /* 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);
 }
 
 static WifiNonHtDuplicateTestSuite wifiNonHtDuplicateTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-phy-mu-mimo-test.cc ns-3.40/src/wifi/test/wifi-phy-mu-mimo-test.cc
--- ns-3.39/src/wifi/test/wifi-phy-mu-mimo-test.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/src/wifi/test/wifi-phy-mu-mimo-test.cc	2023-09-27 13:30:37.926839800 -0700
@@ -0,0 +1,1870 @@
+/*
+ * Copyright (c) 2022 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 "ns3/ap-wifi-mac.h"
+#include "ns3/boolean.h"
+#include "ns3/double.h"
+#include "ns3/he-configuration.h"
+#include "ns3/he-phy.h"
+#include "ns3/interference-helper.h"
+#include "ns3/log.h"
+#include "ns3/multi-model-spectrum-channel.h"
+#include "ns3/nist-error-rate-model.h"
+#include "ns3/node.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/test.h"
+#include "ns3/uinteger.h"
+#include "ns3/wifi-mac-header.h"
+#include "ns3/wifi-net-device.h"
+#include "ns3/wifi-psdu.h"
+#include "ns3/wifi-spectrum-value-helper.h"
+#include "ns3/wifi-utils.h"
+
+#include <list>
+#include <tuple>
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE("WifiPhyMuMimoTest");
+
+constexpr uint32_t DEFAULT_FREQUENCY = 5180;   // MHz
+constexpr uint16_t DEFAULT_CHANNEL_WIDTH = 20; // MHz
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
+ * \brief DL MU TX-VECTOR test
+ */
+class TestDlMuTxVector : public TestCase
+{
+  public:
+    TestDlMuTxVector();
+
+  private:
+    void DoRun() override;
+
+    /**
+     * Build a TXVECTOR for DL MU with the given bandwidth and user information.
+     *
+     * \param bw the channel width of the PPDU in MHz
+     * \param userInfos the list of HE MU specific user transmission parameters
+     *
+     * \return the configured MU TXVECTOR
+     */
+    static WifiTxVector BuildTxVector(uint16_t bw, const std::list<HeMuUserInfo>& userInfos);
+};
+
+TestDlMuTxVector::TestDlMuTxVector()
+    : TestCase("Check for valid combinations of MU TX-VECTOR")
+{
+}
+
+WifiTxVector
+TestDlMuTxVector::BuildTxVector(uint16_t bw, const std::list<HeMuUserInfo>& userInfos)
+{
+    WifiTxVector txVector;
+    txVector.SetPreambleType(WIFI_PREAMBLE_HE_MU);
+    txVector.SetChannelWidth(bw);
+    std::list<uint16_t> staIds;
+    uint16_t staId = 1;
+    for (const auto& userInfo : userInfos)
+    {
+        txVector.SetHeMuUserInfo(staId, userInfo);
+        staIds.push_back(staId++);
+    }
+    return txVector;
+}
+
+void
+TestDlMuTxVector::DoRun()
+{
+    // Verify TxVector is OFDMA
+    std::list<HeMuUserInfo> userInfos;
+    userInfos.push_back({{HeRu::RU_106_TONE, 1, true}, 11, 1});
+    userInfos.push_back({{HeRu::RU_106_TONE, 2, true}, 10, 2});
+    WifiTxVector txVector = BuildTxVector(20, userInfos);
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsDlOfdma(),
+                          true,
+                          "TX-VECTOR should indicate an OFDMA transmission");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsDlMuMimo(),
+                          false,
+                          "TX-VECTOR should not indicate a MU-MIMO transmission");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsSigBCompression(),
+                          false,
+                          "TX-VECTOR should not indicate a SIG-B compression");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsValid(),
+                          true,
+                          "TX-VECTOR should indicate all checks are passed");
+    userInfos.clear();
+
+    // Verify TxVector is a full BW MU-MIMO
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 1});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 2});
+    txVector = BuildTxVector(20, userInfos);
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsDlOfdma(),
+                          false,
+                          "TX-VECTOR should indicate a MU-MIMO transmission");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsDlMuMimo(),
+                          true,
+                          "TX-VECTOR should not indicate an OFDMA transmission");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsSigBCompression(),
+                          true,
+                          "TX-VECTOR should indicate a SIG-B compression");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsValid(),
+                          true,
+                          "TX-VECTOR should indicate all checks are passed");
+    userInfos.clear();
+
+    // Verify TxVector is not valid if there are more than 8 STAs using the same RU
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 1});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 1});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 9, 1});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 8, 1});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 7, 1});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 6, 1});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 5, 1});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 4, 1});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 3, 1});
+    txVector = BuildTxVector(20, userInfos);
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsDlOfdma(),
+                          false,
+                          "TX-VECTOR should indicate a MU-MIMO transmission");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsDlMuMimo(),
+                          true,
+                          "TX-VECTOR should not indicate an OFDMA transmission");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsSigBCompression(),
+                          true,
+                          "TX-VECTOR should indicate a SIG-B compression");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsValid(),
+                          false,
+                          "TX-VECTOR should not indicate all checks are passed");
+
+    // Verify TxVector is not valid if the total number of antennas in a full BW MU-MIMO is above 8
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 2});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 2});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 9, 3});
+    userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 8, 3});
+    txVector = BuildTxVector(20, userInfos);
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsDlOfdma(),
+                          false,
+                          "TX-VECTOR should indicate a MU-MIMO transmission");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsDlMuMimo(),
+                          true,
+                          "TX-VECTOR should not indicate an OFDMA transmission");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsSigBCompression(),
+                          true,
+                          "TX-VECTOR should indicate a SIG-B compression");
+    NS_TEST_EXPECT_MSG_EQ(txVector.IsValid(),
+                          false,
+                          "TX-VECTOR should not indicate all checks are passed");
+}
+
+/**
+ * HE PHY slightly modified so as to return a given
+ * STA-ID in case of DL MU for MuMimoSpectrumWifiPhy.
+ */
+class MuMimoTestHePhy : public HePhy
+{
+  public:
+    /**
+     * Constructor
+     *
+     * \param staId the ID of the STA to which this PHY belongs to
+     */
+    MuMimoTestHePhy(uint16_t staId);
+
+    /**
+     * Return the STA ID that has been assigned to the station this PHY belongs to.
+     * This is typically called for MU PPDUs, in order to pick the correct PSDU.
+     *
+     * \param ppdu the PPDU for which the STA ID is requested
+     * \return the STA ID
+     */
+    uint16_t GetStaId(const Ptr<const WifiPpdu> ppdu) const override;
+
+    /**
+     * Set the global PPDU UID counter.
+     *
+     * \param uid the value to which the global PPDU UID counter should be set
+     */
+    void SetGlobalPpduUid(uint64_t uid);
+
+  private:
+    uint16_t m_staId; ///< ID of the STA to which this PHY belongs to
+};                    // class MuMimoTestHePhy
+
+MuMimoTestHePhy::MuMimoTestHePhy(uint16_t staId)
+    : HePhy(),
+      m_staId(staId)
+{
+}
+
+uint16_t
+MuMimoTestHePhy::GetStaId(const Ptr<const WifiPpdu> ppdu) const
+{
+    if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
+    {
+        return m_staId;
+    }
+    return HePhy::GetStaId(ppdu);
+}
+
+void
+MuMimoTestHePhy::SetGlobalPpduUid(uint64_t uid)
+{
+    m_globalPpduUid = uid;
+}
+
+/**
+ * SpectrumWifiPhy used for testing MU-MIMO.
+ */
+class MuMimoSpectrumWifiPhy : public SpectrumWifiPhy
+{
+  public:
+    /**
+     * \brief Get the type ID.
+     * \return the object TypeId
+     */
+    static TypeId GetTypeId();
+    /**
+     * Constructor
+     *
+     * \param staId the ID of the STA to which this PHY belongs to
+     */
+    MuMimoSpectrumWifiPhy(uint16_t staId);
+    ~MuMimoSpectrumWifiPhy() override;
+
+    /**
+     * Set the global PPDU UID counter.
+     *
+     * \param uid the value to which the global PPDU UID counter should be set
+     */
+    void SetPpduUid(uint64_t uid);
+
+    /**
+     * Since we assume trigger frame was previously received from AP, this is used to set its UID
+     *
+     * \param uid the PPDU UID of the trigger frame
+     */
+    void SetTriggerFrameUid(uint64_t uid);
+
+    /**
+     * \return the current event
+     */
+    Ptr<Event> GetCurrentEvent();
+
+  private:
+    void DoInitialize() override;
+    void DoDispose() override;
+
+    Ptr<MuMimoTestHePhy> m_ofdmTestHePhy; ///< Pointer to HE PHY instance used for MU-MIMO test
+};                                        // class MuMimoSpectrumWifiPhy
+
+TypeId
+MuMimoSpectrumWifiPhy::GetTypeId()
+{
+    static TypeId tid =
+        TypeId("ns3::MuMimoSpectrumWifiPhy").SetParent<SpectrumWifiPhy>().SetGroupName("Wifi");
+    return tid;
+}
+
+MuMimoSpectrumWifiPhy::MuMimoSpectrumWifiPhy(uint16_t staId)
+    : SpectrumWifiPhy()
+{
+    m_ofdmTestHePhy = Create<MuMimoTestHePhy>(staId);
+    m_ofdmTestHePhy->SetOwner(this);
+}
+
+MuMimoSpectrumWifiPhy::~MuMimoSpectrumWifiPhy()
+{
+}
+
+void
+MuMimoSpectrumWifiPhy::DoInitialize()
+{
+    // Replace HE PHY instance with test instance
+    m_phyEntities[WIFI_MOD_CLASS_HE] = m_ofdmTestHePhy;
+    SpectrumWifiPhy::DoInitialize();
+}
+
+void
+MuMimoSpectrumWifiPhy::DoDispose()
+{
+    m_ofdmTestHePhy = nullptr;
+    SpectrumWifiPhy::DoDispose();
+}
+
+void
+MuMimoSpectrumWifiPhy::SetPpduUid(uint64_t uid)
+{
+    m_ofdmTestHePhy->SetGlobalPpduUid(uid);
+    m_previouslyRxPpduUid = uid;
+}
+
+void
+MuMimoSpectrumWifiPhy::SetTriggerFrameUid(uint64_t uid)
+{
+    m_previouslyRxPpduUid = uid;
+}
+
+Ptr<Event>
+MuMimoSpectrumWifiPhy::GetCurrentEvent()
+{
+    return m_currentEvent;
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
+ * \brief DL MU-MIMO PHY test
+ */
+class TestDlMuMimoPhyTransmission : public TestCase
+{
+  public:
+    TestDlMuMimoPhyTransmission();
+
+  private:
+    void DoSetup() override;
+    void DoTeardown() override;
+    void DoRun() override;
+
+    /**
+     * Receive success function for STA 1
+     * \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 RxSuccessSta1(Ptr<const WifiPsdu> psdu,
+                       RxSignalInfo rxSignalInfo,
+                       WifiTxVector txVector,
+                       std::vector<bool> statusPerMpdu);
+    /**
+     * Receive success function for STA 2
+     * \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 RxSuccessSta2(Ptr<const WifiPsdu> psdu,
+                       RxSignalInfo rxSignalInfo,
+                       WifiTxVector txVector,
+                       std::vector<bool> statusPerMpdu);
+    /**
+     * Receive success function for STA 3
+     * \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 RxSuccessSta3(Ptr<const WifiPsdu> psdu,
+                       RxSignalInfo rxSignalInfo,
+                       WifiTxVector txVector,
+                       std::vector<bool> statusPerMpdu);
+
+    /**
+     * Receive failure function for STA 1
+     * \param psdu the PSDU
+     */
+    void RxFailureSta1(Ptr<const WifiPsdu> psdu);
+    /**
+     * Receive failure function for STA 2
+     * \param psdu the PSDU
+     */
+    void RxFailureSta2(Ptr<const WifiPsdu> psdu);
+    /**
+     * Receive failure function for STA 3
+     * \param psdu the PSDU
+     */
+    void RxFailureSta3(Ptr<const WifiPsdu> psdu);
+
+    /**
+     * Check the results for STA 1
+     * \param expectedRxSuccess the expected number of RX success
+     * \param expectedRxFailure the expected number of RX failures
+     * \param expectedRxBytes the expected number of RX bytes
+     */
+    void CheckResultsSta1(uint32_t expectedRxSuccess,
+                          uint32_t expectedRxFailure,
+                          uint32_t expectedRxBytes);
+    /**
+     * Check the results for STA 2
+     * \param expectedRxSuccess the expected number of RX success
+     * \param expectedRxFailure the expected number of RX failures
+     * \param expectedRxBytes the expected number of RX bytes
+     */
+    void CheckResultsSta2(uint32_t expectedRxSuccess,
+                          uint32_t expectedRxFailure,
+                          uint32_t expectedRxBytes);
+    /**
+     * Check the results for STA 3
+     * \param expectedRxSuccess the expected number of RX success
+     * \param expectedRxFailure the expected number of RX failures
+     * \param expectedRxBytes the expected number of RX bytes
+     */
+    void CheckResultsSta3(uint32_t expectedRxSuccess,
+                          uint32_t expectedRxFailure,
+                          uint32_t expectedRxBytes);
+
+    /**
+     * Reset the results
+     */
+    void ResetResults();
+
+    /**
+     * STA info
+     */
+    struct StaInfo
+    {
+        uint16_t staId; //!< STA ID
+        uint8_t staNss; //!< Number of spatial streams used for the STA
+    };
+
+    /**
+     * Send DL MU-MIMO PPDU function
+     * \param staInfos the STAs infos
+     */
+    void SendMuPpdu(const std::vector<StaInfo>& staInfos);
+
+    /**
+     * Generate interference function
+     * \param interferencePsd the PSD of the interference to be generated
+     * \param duration the duration of the interference
+     */
+    void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
+    /**
+     * Stop interference function
+     */
+    void StopInterference();
+
+    /**
+     * Run one function
+     */
+    void RunOne();
+
+    /**
+     * Schedule now to check  the PHY state
+     * \param phy the PHY
+     * \param expectedState the expected state of the PHY
+     */
+    void CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
+    /**
+     * Check the PHY state now
+     * \param phy the PHY
+     * \param expectedState the expected state of the PHY
+     */
+    void DoCheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
+
+    uint32_t m_countRxSuccessSta1; ///< count RX success for STA 1
+    uint32_t m_countRxSuccessSta2; ///< count RX success for STA 2
+    uint32_t m_countRxSuccessSta3; ///< count RX success for STA 3
+    uint32_t m_countRxFailureSta1; ///< count RX failure for STA 1
+    uint32_t m_countRxFailureSta2; ///< count RX failure for STA 2
+    uint32_t m_countRxFailureSta3; ///< count RX failure for STA 3
+    uint32_t m_countRxBytesSta1;   ///< count RX bytes for STA 1
+    uint32_t m_countRxBytesSta2;   ///< count RX bytes for STA 2
+    uint32_t m_countRxBytesSta3;   ///< count RX bytes for STA 3
+
+    Ptr<SpectrumWifiPhy> m_phyAp;         ///< PHY of AP
+    Ptr<MuMimoSpectrumWifiPhy> m_phySta1; ///< PHY of STA 1
+    Ptr<MuMimoSpectrumWifiPhy> m_phySta2; ///< PHY of STA 2
+    Ptr<MuMimoSpectrumWifiPhy> m_phySta3; ///< PHY of STA 3
+
+    uint8_t m_nss;               ///< number of spatial streams per STA
+    uint16_t m_frequency;        ///< frequency in MHz
+    uint16_t m_channelWidth;     ///< channel width in MHz
+    Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
+};
+
+TestDlMuMimoPhyTransmission::TestDlMuMimoPhyTransmission()
+    : TestCase("DL MU-MIMO PHY test"),
+      m_countRxSuccessSta1{0},
+      m_countRxSuccessSta2{0},
+      m_countRxSuccessSta3{0},
+      m_countRxFailureSta1{0},
+      m_countRxFailureSta2{0},
+      m_countRxFailureSta3{0},
+      m_countRxBytesSta1{0},
+      m_countRxBytesSta2{0},
+      m_countRxBytesSta3{0},
+      m_nss{1},
+      m_frequency{DEFAULT_FREQUENCY},
+      m_channelWidth{DEFAULT_CHANNEL_WIDTH},
+      m_expectedPpduDuration{NanoSeconds(306400)}
+{
+}
+
+void
+TestDlMuMimoPhyTransmission::ResetResults()
+{
+    m_countRxSuccessSta1 = 0;
+    m_countRxSuccessSta2 = 0;
+    m_countRxSuccessSta3 = 0;
+    m_countRxFailureSta1 = 0;
+    m_countRxFailureSta2 = 0;
+    m_countRxFailureSta3 = 0;
+    m_countRxBytesSta1 = 0;
+    m_countRxBytesSta2 = 0;
+    m_countRxBytesSta3 = 0;
+}
+
+void
+TestDlMuMimoPhyTransmission::SendMuPpdu(const std::vector<StaInfo>& staInfos)
+{
+    NS_LOG_FUNCTION(this << staInfos.size());
+    NS_ASSERT(staInfos.size() > 1);
+
+    WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs7(),
+                                         0,
+                                         WIFI_PREAMBLE_HE_MU,
+                                         800,
+                                         1,
+                                         1,
+                                         0,
+                                         m_channelWidth,
+                                         false,
+                                         false);
+
+    WifiConstPsduMap psdus;
+    HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
+    for (const auto& staInfo : staInfos)
+    {
+        txVector.SetRu(ru, staInfo.staId);
+        txVector.SetMode(HePhy::GetHeMcs7(), staInfo.staId);
+        txVector.SetNss(staInfo.staNss, staInfo.staId);
+
+        Ptr<Packet> pkt = Create<Packet>(1000 + (8 * staInfo.staId));
+        WifiMacHeader hdr;
+        hdr.SetType(WIFI_MAC_QOSDATA);
+        hdr.SetQosTid(0);
+        std::ostringstream addr;
+        addr << "00:00:00:00:00:0" << staInfo.staId;
+        hdr.SetAddr1(Mac48Address(addr.str().c_str()));
+        hdr.SetSequenceNumber(1 + staInfo.staId);
+        Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
+        psdus.insert(std::make_pair(staInfo.staId, psdu));
+    }
+
+    txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
+
+    NS_ASSERT(txVector.IsDlMuMimo());
+    NS_ASSERT(!txVector.IsDlOfdma());
+
+    m_phyAp->Send(psdus, txVector);
+}
+
+void
+TestDlMuMimoPhyTransmission::RxSuccessSta1(Ptr<const WifiPsdu> psdu,
+                                           RxSignalInfo rxSignalInfo,
+                                           WifiTxVector txVector,
+                                           std::vector<bool> /*statusPerMpdu*/)
+{
+    NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
+    m_countRxSuccessSta1++;
+    m_countRxBytesSta1 += (psdu->GetSize() - 30);
+}
+
+void
+TestDlMuMimoPhyTransmission::RxSuccessSta2(Ptr<const WifiPsdu> psdu,
+                                           RxSignalInfo rxSignalInfo,
+                                           WifiTxVector txVector,
+                                           std::vector<bool> /*statusPerMpdu*/)
+{
+    NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
+    m_countRxSuccessSta2++;
+    m_countRxBytesSta2 += (psdu->GetSize() - 30);
+}
+
+void
+TestDlMuMimoPhyTransmission::RxSuccessSta3(Ptr<const WifiPsdu> psdu,
+                                           RxSignalInfo rxSignalInfo,
+                                           WifiTxVector txVector,
+                                           std::vector<bool> /*statusPerMpdu*/)
+{
+    NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
+    m_countRxSuccessSta3++;
+    m_countRxBytesSta3 += (psdu->GetSize() - 30);
+}
+
+void
+TestDlMuMimoPhyTransmission::RxFailureSta1(Ptr<const WifiPsdu> psdu)
+{
+    NS_LOG_FUNCTION(this << *psdu);
+    m_countRxFailureSta1++;
+}
+
+void
+TestDlMuMimoPhyTransmission::RxFailureSta2(Ptr<const WifiPsdu> psdu)
+{
+    NS_LOG_FUNCTION(this << *psdu);
+    m_countRxFailureSta2++;
+}
+
+void
+TestDlMuMimoPhyTransmission::RxFailureSta3(Ptr<const WifiPsdu> psdu)
+{
+    NS_LOG_FUNCTION(this << *psdu);
+    m_countRxFailureSta3++;
+}
+
+void
+TestDlMuMimoPhyTransmission::CheckResultsSta1(uint32_t expectedRxSuccess,
+                                              uint32_t expectedRxFailure,
+                                              uint32_t expectedRxBytes)
+{
+    NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessSta1,
+                          expectedRxSuccess,
+                          "The number of successfully received packets by STA 1 is not correct!");
+    NS_TEST_ASSERT_MSG_EQ(m_countRxFailureSta1,
+                          expectedRxFailure,
+                          "The number of unsuccessfully received packets by STA 1 is not correct!");
+    NS_TEST_ASSERT_MSG_EQ(m_countRxBytesSta1,
+                          expectedRxBytes,
+                          "The number of bytes received by STA 1 is not correct!");
+}
+
+void
+TestDlMuMimoPhyTransmission::CheckResultsSta2(uint32_t expectedRxSuccess,
+                                              uint32_t expectedRxFailure,
+                                              uint32_t expectedRxBytes)
+{
+    NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessSta2,
+                          expectedRxSuccess,
+                          "The number of successfully received packets by STA 2 is not correct!");
+    NS_TEST_ASSERT_MSG_EQ(m_countRxFailureSta2,
+                          expectedRxFailure,
+                          "The number of unsuccessfully received packets by STA 2 is not correct!");
+    NS_TEST_ASSERT_MSG_EQ(m_countRxBytesSta2,
+                          expectedRxBytes,
+                          "The number of bytes received by STA 2 is not correct!");
+}
+
+void
+TestDlMuMimoPhyTransmission::CheckResultsSta3(uint32_t expectedRxSuccess,
+                                              uint32_t expectedRxFailure,
+                                              uint32_t expectedRxBytes)
+{
+    NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessSta3,
+                          expectedRxSuccess,
+                          "The number of successfully received packets by STA 3 is not correct!");
+    NS_TEST_ASSERT_MSG_EQ(m_countRxFailureSta3,
+                          expectedRxFailure,
+                          "The number of unsuccessfully received packets by STA 3 is not correct!");
+    NS_TEST_ASSERT_MSG_EQ(m_countRxBytesSta3,
+                          expectedRxBytes,
+                          "The number of bytes received by STA 3 is not correct!");
+}
+
+void
+TestDlMuMimoPhyTransmission::CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy,
+                                           WifiPhyState expectedState)
+{
+    // This is needed to make sure PHY state will be checked as the last event if a state change
+    // occurred at the exact same time as the check
+    Simulator::ScheduleNow(&TestDlMuMimoPhyTransmission::DoCheckPhyState, this, phy, expectedState);
+}
+
+void
+TestDlMuMimoPhyTransmission::DoCheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy,
+                                             WifiPhyState expectedState)
+{
+    WifiPhyState currentState;
+    PointerValue ptr;
+    phy->GetAttribute("State", ptr);
+    Ptr<WifiPhyStateHelper> state = DynamicCast<WifiPhyStateHelper>(ptr.Get<WifiPhyStateHelper>());
+    currentState = state->GetState();
+    NS_LOG_FUNCTION(this << currentState << expectedState);
+    NS_TEST_ASSERT_MSG_EQ(currentState,
+                          expectedState,
+                          "PHY State " << currentState << " does not match expected state "
+                                       << expectedState << " at " << Simulator::Now());
+}
+
+void
+TestDlMuMimoPhyTransmission::DoSetup()
+{
+    Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
+    Ptr<ConstantSpeedPropagationDelayModel> delayModel =
+        CreateObject<ConstantSpeedPropagationDelayModel>();
+    spectrumChannel->SetPropagationDelayModel(delayModel);
+
+    Ptr<Node> apNode = CreateObject<Node>();
+    Ptr<WifiNetDevice> apDev = CreateObject<WifiNetDevice>();
+    m_phyAp = CreateObject<SpectrumWifiPhy>();
+    Ptr<InterferenceHelper> apInterferenceHelper = CreateObject<InterferenceHelper>();
+    m_phyAp->SetInterferenceHelper(apInterferenceHelper);
+    Ptr<ErrorRateModel> apErrorModel = CreateObject<NistErrorRateModel>();
+    m_phyAp->SetErrorRateModel(apErrorModel);
+    m_phyAp->SetDevice(apDev);
+    m_phyAp->AddChannel(spectrumChannel);
+    m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
+    apDev->SetPhy(m_phyAp);
+    apNode->AddDevice(apDev);
+
+    Ptr<Node> sta1Node = CreateObject<Node>();
+    Ptr<WifiNetDevice> sta1Dev = CreateObject<WifiNetDevice>();
+    m_phySta1 = CreateObject<MuMimoSpectrumWifiPhy>(1);
+    Ptr<InterferenceHelper> sta1InterferenceHelper = CreateObject<InterferenceHelper>();
+    m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
+    Ptr<ErrorRateModel> sta1ErrorModel = CreateObject<NistErrorRateModel>();
+    m_phySta1->SetErrorRateModel(sta1ErrorModel);
+    m_phySta1->SetDevice(sta1Dev);
+    m_phySta1->AddChannel(spectrumChannel);
+    m_phySta1->ConfigureStandard(WIFI_STANDARD_80211ax);
+    m_phySta1->SetReceiveOkCallback(
+        MakeCallback(&TestDlMuMimoPhyTransmission::RxSuccessSta1, this));
+    m_phySta1->SetReceiveErrorCallback(
+        MakeCallback(&TestDlMuMimoPhyTransmission::RxFailureSta1, this));
+    sta1Dev->SetPhy(m_phySta1);
+    sta1Node->AddDevice(sta1Dev);
+
+    Ptr<Node> sta2Node = CreateObject<Node>();
+    Ptr<WifiNetDevice> sta2Dev = CreateObject<WifiNetDevice>();
+    m_phySta2 = CreateObject<MuMimoSpectrumWifiPhy>(2);
+    Ptr<InterferenceHelper> sta2InterferenceHelper = CreateObject<InterferenceHelper>();
+    m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
+    Ptr<ErrorRateModel> sta2ErrorModel = CreateObject<NistErrorRateModel>();
+    m_phySta2->SetErrorRateModel(sta2ErrorModel);
+    m_phySta2->SetDevice(sta2Dev);
+    m_phySta2->AddChannel(spectrumChannel);
+    m_phySta2->ConfigureStandard(WIFI_STANDARD_80211ax);
+    m_phySta2->SetReceiveOkCallback(
+        MakeCallback(&TestDlMuMimoPhyTransmission::RxSuccessSta2, this));
+    m_phySta2->SetReceiveErrorCallback(
+        MakeCallback(&TestDlMuMimoPhyTransmission::RxFailureSta2, this));
+    sta2Dev->SetPhy(m_phySta2);
+    sta2Node->AddDevice(sta2Dev);
+
+    Ptr<Node> sta3Node = CreateObject<Node>();
+    Ptr<WifiNetDevice> sta3Dev = CreateObject<WifiNetDevice>();
+    m_phySta3 = CreateObject<MuMimoSpectrumWifiPhy>(3);
+    Ptr<InterferenceHelper> sta3InterferenceHelper = CreateObject<InterferenceHelper>();
+    m_phySta3->SetInterferenceHelper(sta3InterferenceHelper);
+    Ptr<ErrorRateModel> sta3ErrorModel = CreateObject<NistErrorRateModel>();
+    m_phySta3->SetErrorRateModel(sta3ErrorModel);
+    m_phySta3->SetDevice(sta3Dev);
+    m_phySta3->AddChannel(spectrumChannel);
+    m_phySta3->ConfigureStandard(WIFI_STANDARD_80211ax);
+    m_phySta3->SetReceiveOkCallback(
+        MakeCallback(&TestDlMuMimoPhyTransmission::RxSuccessSta3, this));
+    m_phySta3->SetReceiveErrorCallback(
+        MakeCallback(&TestDlMuMimoPhyTransmission::RxFailureSta3, this));
+    sta3Dev->SetPhy(m_phySta3);
+    sta3Node->AddDevice(sta3Dev);
+}
+
+void
+TestDlMuMimoPhyTransmission::DoTeardown()
+{
+    m_phyAp->Dispose();
+    m_phyAp = nullptr;
+    m_phySta1->Dispose();
+    m_phySta1 = nullptr;
+    m_phySta2->Dispose();
+    m_phySta2 = nullptr;
+    m_phySta3->Dispose();
+    m_phySta3 = nullptr;
+}
+
+void
+TestDlMuMimoPhyTransmission::RunOne()
+{
+    RngSeedManager::SetSeed(1);
+    RngSeedManager::SetRun(1);
+    int64_t streamNumber = 0;
+    m_phyAp->AssignStreams(streamNumber);
+    m_phySta1->AssignStreams(streamNumber);
+    m_phySta2->AssignStreams(streamNumber);
+
+    auto channelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
+                                                                      m_frequency,
+                                                                      m_channelWidth,
+                                                                      WIFI_STANDARD_80211ax,
+                                                                      WIFI_PHY_BAND_5GHZ));
+
+    m_phyAp->SetOperatingChannel(
+        WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0});
+    m_phySta1->SetOperatingChannel(
+        WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0});
+    m_phySta2->SetOperatingChannel(
+        WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0});
+    m_phySta3->SetOperatingChannel(
+        WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0});
+
+    m_phyAp->SetNumberOfAntennas(8);
+    m_phyAp->SetMaxSupportedTxSpatialStreams(8);
+
+    //----------------------------------------------------------------------------------------------------
+    // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
+    // STA 1 and STA 2 should receive their PSDUs, whereas STA 3 should not receive any PSDU
+    // but should keep its PHY busy during all PPDU duration.
+    Simulator::Schedule(Seconds(1.0),
+                        &TestDlMuMimoPhyTransmission::SendMuPpdu,
+                        this,
+                        std::vector<StaInfo>{{1, m_nss}, {2, m_nss}});
+
+    // Since it takes m_expectedPpduDuration to transmit the PPDU,
+    // all 3 PHYs should be back to IDLE at the same time,
+    // even the PHY that has no PSDU addressed to it.
+    Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta1,
+                        WifiPhyState::RX);
+    Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta2,
+                        WifiPhyState::RX);
+    Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta3,
+                        WifiPhyState::CCA_BUSY);
+    Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta1,
+                        WifiPhyState::IDLE);
+    Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta2,
+                        WifiPhyState::IDLE);
+    Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta3,
+                        WifiPhyState::IDLE);
+
+    // One PSDU of 1008 bytes should have been successfully received by STA 1
+    Simulator::Schedule(Seconds(1.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta1,
+                        this,
+                        1,
+                        0,
+                        1008);
+    // One PSDU of 1016 bytes should have been successfully received by STA 2
+    Simulator::Schedule(Seconds(1.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta2,
+                        this,
+                        1,
+                        0,
+                        1016);
+    // No PSDU should have been received by STA 3
+    Simulator::Schedule(Seconds(1.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta3,
+                        this,
+                        0,
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
+
+    //----------------------------------------------------------------------------------------------------
+    // Send MU PPDU with two PSDUs addressed to STA 1 and STA 3:
+    // STA 1 and STA 3 should receive their PSDUs, whereas STA 2 should not receive any PSDU
+    // but should keep its PHY busy during all PPDU duration.
+    Simulator::Schedule(Seconds(2.0),
+                        &TestDlMuMimoPhyTransmission::SendMuPpdu,
+                        this,
+                        std::vector<StaInfo>{{1, m_nss}, {3, m_nss}});
+
+    // Since it takes m_expectedPpduDuration to transmit the PPDU,
+    // all 3 PHYs should be back to IDLE at the same time,
+    // even the PHY that has no PSDU addressed to it.
+    Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta1,
+                        WifiPhyState::RX);
+    Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta2,
+                        WifiPhyState::CCA_BUSY);
+    Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta3,
+                        WifiPhyState::RX);
+    Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta1,
+                        WifiPhyState::IDLE);
+    Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta2,
+                        WifiPhyState::IDLE);
+    Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta3,
+                        WifiPhyState::IDLE);
+
+    // One PSDU of 1008 bytes should have been successfully received by STA 1
+    Simulator::Schedule(Seconds(2.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta1,
+                        this,
+                        1,
+                        0,
+                        1008);
+    // No PSDU should have been received by STA 2
+    Simulator::Schedule(Seconds(2.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta2,
+                        this,
+                        0,
+                        0,
+                        0);
+    // One PSDU of 1024 bytes should have been successfully received by STA 3
+    Simulator::Schedule(Seconds(2.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta3,
+                        this,
+                        1,
+                        0,
+                        1024);
+
+    Simulator::Schedule(Seconds(2.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
+
+    //----------------------------------------------------------------------------------------------------
+    // Send MU PPDU with two PSDUs addressed to STA 2 and STA 3:
+    // STA 2 and STA 3 should receive their PSDUs, whereas STA 1 should not receive any PSDU
+    // but should keep its PHY busy during all PPDU duration.
+    Simulator::Schedule(Seconds(3.0),
+                        &TestDlMuMimoPhyTransmission::SendMuPpdu,
+                        this,
+                        std::vector<StaInfo>{{2, m_nss}, {3, m_nss}});
+
+    // Since it takes m_expectedPpduDuration to transmit the PPDU,
+    // all 3 PHYs should be back to IDLE at the same time,
+    // even the PHY that has no PSDU addressed to it.
+    Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta1,
+                        WifiPhyState::CCA_BUSY);
+    Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta2,
+                        WifiPhyState::RX);
+    Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta3,
+                        WifiPhyState::RX);
+    Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta1,
+                        WifiPhyState::IDLE);
+    Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta2,
+                        WifiPhyState::IDLE);
+    Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta3,
+                        WifiPhyState::IDLE);
+
+    // No PSDU should have been received by STA 1
+    Simulator::Schedule(Seconds(3.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta1,
+                        this,
+                        0,
+                        0,
+                        0);
+    // One PSDU of 1016 bytes should have been successfully received by STA 2
+    Simulator::Schedule(Seconds(3.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta2,
+                        this,
+                        1,
+                        0,
+                        1016);
+    // One PSDU of 1024 bytes should have been successfully received by STA 3
+    Simulator::Schedule(Seconds(3.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta3,
+                        this,
+                        1,
+                        0,
+                        1024);
+
+    Simulator::Schedule(Seconds(3.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
+
+    //----------------------------------------------------------------------------------------------------
+    // Send MU PPDU with three PSDUs addressed to STA 1, STA 2 and STA 3:
+    // All STAs should receive their PSDUs.
+    Simulator::Schedule(Seconds(4.0),
+                        &TestDlMuMimoPhyTransmission::SendMuPpdu,
+                        this,
+                        std::vector<StaInfo>{{1, m_nss}, {2, m_nss}, {3, m_nss}});
+
+    // Since it takes m_expectedPpduDuration to transmit the PPDU,
+    // all 3 PHYs should be back to IDLE at the same time.
+    Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta1,
+                        WifiPhyState::RX);
+    Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta2,
+                        WifiPhyState::RX);
+    Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta3,
+                        WifiPhyState::RX);
+    Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta1,
+                        WifiPhyState::IDLE);
+    Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta2,
+                        WifiPhyState::IDLE);
+    Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration,
+                        &TestDlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phySta3,
+                        WifiPhyState::IDLE);
+
+    // One PSDU of 1008 bytes should have been successfully received by STA 1
+    Simulator::Schedule(Seconds(4.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta1,
+                        this,
+                        1,
+                        0,
+                        1008);
+    // One PSDU of 1016 bytes should have been successfully received by STA 2
+    Simulator::Schedule(Seconds(4.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta2,
+                        this,
+                        1,
+                        0,
+                        1016);
+    // One PSDU of 1024 bytes should have been successfully received by STA 3
+    Simulator::Schedule(Seconds(4.1),
+                        &TestDlMuMimoPhyTransmission::CheckResultsSta3,
+                        this,
+                        1,
+                        0,
+                        1024);
+
+    Simulator::Schedule(Seconds(4.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
+
+    Simulator::Run();
+}
+
+void
+TestDlMuMimoPhyTransmission::DoRun()
+{
+    std::vector<uint8_t> nssToTest{1, 2};
+    for (auto nss : nssToTest)
+    {
+        m_nss = nss;
+        m_frequency = 5180;
+        m_channelWidth = 20;
+        m_expectedPpduDuration = (nss > 1) ? NanoSeconds(110400) : NanoSeconds(156800);
+        RunOne();
+
+        m_frequency = 5190;
+        m_channelWidth = 40;
+        m_expectedPpduDuration = (nss > 1) ? NanoSeconds(83200) : NanoSeconds(102400);
+        RunOne();
+
+        m_frequency = 5210;
+        m_channelWidth = 80;
+        m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(75200);
+        RunOne();
+
+        m_frequency = 5250;
+        m_channelWidth = 160;
+        m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(61600);
+        RunOne();
+    }
+    // FIXME: test also different nss over STAs once RX durations when receiving different PPDUs
+    // with different nss over STAs are fixed
+
+    Simulator::Destroy();
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
+ * \brief UL MU-MIMO PHY test
+ */
+class TestUlMuMimoPhyTransmission : public TestCase
+{
+  public:
+    TestUlMuMimoPhyTransmission();
+
+  private:
+    void DoSetup() override;
+    void DoTeardown() override;
+    void DoRun() override;
+
+    /**
+     * Get TXVECTOR for HE TB PPDU.
+     * \param txStaId the ID of the TX STA
+     * \param nss the number of spatial streams used for the transmission
+     * \param bssColor the BSS color of the TX STA
+     * \return the TXVECTOR for HE TB PPDU
+     */
+    WifiTxVector GetTxVectorForHeTbPpdu(uint16_t txStaId, uint8_t nss, uint8_t bssColor) const;
+    /**
+     * Set TRIGVECTOR for HE TB PPDU
+     *
+     * \param staIds the IDs of the STAs sollicited for the HE TB transmission
+     * \param bssColor the BSS color of the TX STA
+     */
+    void SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor);
+    /**
+     * Send HE TB PPDU function
+     * \param txStaId the ID of the TX STA
+     * \param nss the number of spatial streams used for the transmission
+     * \param payloadSize the size of the payload in bytes
+     * \param uid the UID of the trigger frame that is initiating this transmission
+     * \param bssColor the BSS color of the TX STA
+     */
+    void SendHeTbPpdu(uint16_t txStaId,
+                      uint8_t nss,
+                      std::size_t payloadSize,
+                      uint64_t uid,
+                      uint8_t bssColor);
+
+    /**
+     * Send HE SU PPDU function
+     * \param txStaId the ID of the TX STA
+     * \param payloadSize the size of the payload in bytes
+     * \param uid the UID of the trigger frame that is initiating this transmission
+     * \param bssColor the BSS color of the TX STA
+     */
+    void SendHeSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor);
+
+    /**
+     * Set the BSS color
+     * \param phy the PHY
+     * \param bssColor the BSS color
+     */
+    void SetBssColor(Ptr<WifiPhy> phy, uint8_t bssColor);
+
+    /**
+     * Run one function
+     */
+    void RunOne();
+
+    /**
+     * Check the received PSDUs from a given STA
+     * \param staId the ID of the STA to check
+     * \param expectedSuccess the expected number of success
+     * \param expectedFailures the expected number of failures
+     * \param expectedBytes the expected number of bytes
+     */
+    void CheckRxFromSta(uint16_t staId,
+                        uint32_t expectedSuccess,
+                        uint32_t expectedFailures,
+                        uint32_t expectedBytes);
+
+    /**
+     * Verify all events are cleared at end of TX or RX
+     */
+    void VerifyEventsCleared();
+
+    /**
+     * Check the PHY state
+     * \param phy the PHY
+     * \param expectedState the expected state of the PHY
+     */
+    void CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
+    /// \copydoc CheckPhyState
+    void DoCheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
+
+    /**
+     * Reset function
+     */
+    void Reset();
+
+    /**
+     * Receive success function
+     * \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(Ptr<const WifiPsdu> psdu,
+                   RxSignalInfo rxSignalInfo,
+                   WifiTxVector txVector,
+                   std::vector<bool> statusPerMpdu);
+
+    /**
+     * Receive failure function
+     * \param psdu the PSDU
+     */
+    void RxFailure(Ptr<const WifiPsdu> psdu);
+
+    /**
+     * Schedule test to perform.
+     * The interference generation should be scheduled apart.
+     *
+     * \param delay the reference delay to schedule the events
+     * \param txStaIds the IDs of the STAs planned to transmit an HE TB PPDU
+     * \param expectedStateAtEnd the expected state of the PHY at the end of the reception
+     * \param expectedCountersPerSta the expected counters per STA
+     */
+    void ScheduleTest(
+        Time delay,
+        const std::vector<uint16_t>& txStaIds,
+        WifiPhyState expectedStateAtEnd,
+        const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta);
+
+    /**
+     * Log scenario description
+     *
+     * \param log the scenario description to add to log
+     */
+    void LogScenario(const std::string& log) const;
+
+    Ptr<MuMimoSpectrumWifiPhy> m_phyAp;                ///< PHY of AP
+    std::vector<Ptr<MuMimoSpectrumWifiPhy>> m_phyStas; ///< PHYs of STAs
+
+    std::vector<uint32_t> m_countRxSuccessFromStas; ///< count RX success from STAs
+    std::vector<uint32_t> m_countRxFailureFromStas; ///< count RX failure from STAs
+    std::vector<uint32_t> m_countRxBytesFromStas;   ///< count RX bytes from STAs
+
+    Time m_delayStart;           ///< delay between the start of each HE TB PPDUs
+    uint16_t m_frequency;        ///< frequency in MHz
+    uint16_t m_channelWidth;     ///< channel width in MHz
+    Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
+};
+
+TestUlMuMimoPhyTransmission::TestUlMuMimoPhyTransmission()
+    : TestCase("UL MU-MIMO PHY test"),
+      m_countRxSuccessFromStas{},
+      m_countRxFailureFromStas{},
+      m_countRxBytesFromStas{},
+      m_delayStart{Seconds(0)},
+      m_frequency{DEFAULT_FREQUENCY},
+      m_channelWidth{DEFAULT_CHANNEL_WIDTH},
+      m_expectedPpduDuration{NanoSeconds(271200)}
+{
+}
+
+void
+TestUlMuMimoPhyTransmission::SendHeSuPpdu(uint16_t txStaId,
+                                          std::size_t payloadSize,
+                                          uint64_t uid,
+                                          uint8_t bssColor)
+{
+    NS_LOG_FUNCTION(this << txStaId << payloadSize << uid << +bssColor);
+    WifiConstPsduMap psdus;
+
+    WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs7(),
+                                         0,
+                                         WIFI_PREAMBLE_HE_SU,
+                                         800,
+                                         1,
+                                         1,
+                                         0,
+                                         m_channelWidth,
+                                         false,
+                                         false,
+                                         false,
+                                         bssColor);
+
+    Ptr<Packet> pkt = Create<Packet>(payloadSize);
+    WifiMacHeader hdr;
+    hdr.SetType(WIFI_MAC_QOSDATA);
+    hdr.SetQosTid(0);
+    hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
+    std::ostringstream addr;
+    addr << "00:00:00:00:00:0" << txStaId;
+    hdr.SetAddr2(Mac48Address(addr.str().c_str()));
+    hdr.SetSequenceNumber(1);
+    Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
+    psdus.insert(std::make_pair(SU_STA_ID, psdu));
+
+    Ptr<MuMimoSpectrumWifiPhy> phy = (txStaId == 0) ? m_phyAp : m_phyStas.at(txStaId - 1);
+    phy->SetPpduUid(uid);
+    phy->Send(psdus, txVector);
+}
+
+WifiTxVector
+TestUlMuMimoPhyTransmission::GetTxVectorForHeTbPpdu(uint16_t txStaId,
+                                                    uint8_t nss,
+                                                    uint8_t bssColor) const
+{
+    WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs7(),
+                                         0,
+                                         WIFI_PREAMBLE_HE_TB,
+                                         1600,
+                                         1,
+                                         nss,
+                                         0,
+                                         m_channelWidth,
+                                         false,
+                                         false,
+                                         false,
+                                         bssColor);
+
+    HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
+    txVector.SetRu(ru, txStaId);
+    txVector.SetMode(HePhy::GetHeMcs7(), txStaId);
+    txVector.SetNss(nss, txStaId);
+
+    return txVector;
+}
+
+void
+TestUlMuMimoPhyTransmission::SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor)
+{
+    WifiTxVector txVector(HePhy::GetHeMcs7(),
+                          0,
+                          WIFI_PREAMBLE_HE_TB,
+                          1600,
+                          1,
+                          1,
+                          0,
+                          m_channelWidth,
+                          false,
+                          false,
+                          false,
+                          bssColor);
+
+    HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
+    for (auto staId : staIds)
+    {
+        txVector.SetRu(ru, staId);
+        txVector.SetMode(HePhy::GetHeMcs7(), staId);
+        txVector.SetNss(1, staId);
+    }
+
+    uint16_t length;
+    std::tie(length, m_expectedPpduDuration) =
+        HePhy::ConvertHeTbPpduDurationToLSigLength(m_expectedPpduDuration,
+                                                   txVector,
+                                                   m_phyAp->GetPhyBand());
+    txVector.SetLength(length);
+    auto hePhyAp = DynamicCast<HePhy>(m_phyAp->GetPhyEntity(WIFI_MOD_CLASS_HE));
+    hePhyAp->SetTrigVector(txVector, m_expectedPpduDuration);
+}
+
+void
+TestUlMuMimoPhyTransmission::SendHeTbPpdu(uint16_t txStaId,
+                                          uint8_t nss,
+                                          std::size_t payloadSize,
+                                          uint64_t uid,
+                                          uint8_t bssColor)
+{
+    NS_LOG_FUNCTION(this << txStaId << +nss << payloadSize << uid << +bssColor);
+    WifiConstPsduMap psdus;
+
+    WifiTxVector txVector = GetTxVectorForHeTbPpdu(txStaId, nss, bssColor);
+    Ptr<Packet> pkt = Create<Packet>(payloadSize);
+    WifiMacHeader hdr;
+    hdr.SetType(WIFI_MAC_QOSDATA);
+    hdr.SetQosTid(0);
+    hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
+    std::ostringstream addr;
+    addr << "00:00:00:00:00:0" << txStaId;
+    hdr.SetAddr2(Mac48Address(addr.str().c_str()));
+    hdr.SetSequenceNumber(1);
+    Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
+    psdus.insert(std::make_pair(txStaId, psdu));
+
+    Ptr<MuMimoSpectrumWifiPhy> phy = m_phyStas.at(txStaId - 1);
+    Time txDuration =
+        phy->CalculateTxDuration(psdu->GetSize(), txVector, phy->GetPhyBand(), txStaId);
+    txVector.SetLength(
+        HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector, phy->GetPhyBand()).first);
+
+    phy->SetPpduUid(uid);
+    phy->Send(psdus, txVector);
+}
+
+void
+TestUlMuMimoPhyTransmission::RxSuccess(Ptr<const WifiPsdu> psdu,
+                                       RxSignalInfo rxSignalInfo,
+                                       WifiTxVector txVector,
+                                       std::vector<bool> /*statusPerMpdu*/)
+{
+    NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2() << RatioToDb(rxSignalInfo.snr) << txVector);
+    NS_TEST_ASSERT_MSG_EQ((RatioToDb(rxSignalInfo.snr) > 0), true, "Incorrect SNR value");
+    for (std::size_t index = 0; index < m_countRxSuccessFromStas.size(); ++index)
+    {
+        std::ostringstream addr;
+        addr << "00:00:00:00:00:0" << index + 1;
+        if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
+        {
+            m_countRxSuccessFromStas.at(index)++;
+            m_countRxBytesFromStas.at(index) += (psdu->GetSize() - 30);
+            break;
+        }
+    }
+}
+
+void
+TestUlMuMimoPhyTransmission::RxFailure(Ptr<const WifiPsdu> psdu)
+{
+    NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2());
+    for (std::size_t index = 0; index < m_countRxFailureFromStas.size(); ++index)
+    {
+        std::ostringstream addr;
+        addr << "00:00:00:00:00:0" << index + 1;
+        if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
+        {
+            m_countRxFailureFromStas.at(index)++;
+            break;
+        }
+    }
+}
+
+void
+TestUlMuMimoPhyTransmission::CheckRxFromSta(uint16_t staId,
+                                            uint32_t expectedSuccess,
+                                            uint32_t expectedFailures,
+                                            uint32_t expectedBytes)
+{
+    NS_LOG_FUNCTION(this << staId << expectedSuccess << expectedFailures << expectedBytes);
+    NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessFromStas[staId - 1],
+                          expectedSuccess,
+                          "The number of successfully received packets from STA "
+                              << staId << " is not correct!");
+    NS_TEST_ASSERT_MSG_EQ(m_countRxFailureFromStas[staId - 1],
+                          expectedFailures,
+                          "The number of unsuccessfully received packets from STA "
+                              << staId << " is not correct!");
+    NS_TEST_ASSERT_MSG_EQ(m_countRxBytesFromStas[staId - 1],
+                          expectedBytes,
+                          "The number of bytes received from STA " << staId << " is not correct!");
+}
+
+void
+TestUlMuMimoPhyTransmission::VerifyEventsCleared()
+{
+    NS_TEST_ASSERT_MSG_EQ(m_phyAp->GetCurrentEvent(),
+                          nullptr,
+                          "m_currentEvent for AP was not cleared");
+    std::size_t sta = 1;
+    for (auto& phy : m_phyStas)
+    {
+        NS_TEST_ASSERT_MSG_EQ(phy->GetCurrentEvent(),
+                              nullptr,
+                              "m_currentEvent for STA " << sta << " was not cleared");
+        sta++;
+    }
+}
+
+void
+TestUlMuMimoPhyTransmission::CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy,
+                                           WifiPhyState expectedState)
+{
+    // This is needed to make sure PHY state will be checked as the last event if a state change
+    // occurred at the exact same time as the check
+    Simulator::ScheduleNow(&TestUlMuMimoPhyTransmission::DoCheckPhyState, this, phy, expectedState);
+}
+
+void
+TestUlMuMimoPhyTransmission::DoCheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy,
+                                             WifiPhyState expectedState)
+{
+    WifiPhyState currentState;
+    PointerValue ptr;
+    phy->GetAttribute("State", ptr);
+    Ptr<WifiPhyStateHelper> state = DynamicCast<WifiPhyStateHelper>(ptr.Get<WifiPhyStateHelper>());
+    currentState = state->GetState();
+    NS_LOG_FUNCTION(this << currentState << expectedState);
+    NS_TEST_ASSERT_MSG_EQ(currentState,
+                          expectedState,
+                          "PHY State " << currentState << " does not match expected state "
+                                       << expectedState << " at " << Simulator::Now());
+}
+
+void
+TestUlMuMimoPhyTransmission::Reset()
+{
+    for (auto& counter : m_countRxSuccessFromStas)
+    {
+        counter = 0;
+    }
+    for (auto& counter : m_countRxFailureFromStas)
+    {
+        counter = 0;
+    }
+    for (auto& counter : m_countRxBytesFromStas)
+    {
+        counter = 0;
+    }
+    for (auto& phy : m_phyStas)
+    {
+        phy->SetPpduUid(0);
+        phy->SetTriggerFrameUid(0);
+    }
+    SetBssColor(m_phyAp, 0);
+}
+
+void
+TestUlMuMimoPhyTransmission::SetBssColor(Ptr<WifiPhy> phy, uint8_t bssColor)
+{
+    Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice>(phy->GetDevice());
+    Ptr<HeConfiguration> heConfiguration = device->GetHeConfiguration();
+    heConfiguration->SetAttribute("BssColor", UintegerValue(bssColor));
+}
+
+void
+TestUlMuMimoPhyTransmission::DoSetup()
+{
+    // WifiHelper::EnableLogComponents();
+    // LogComponentEnable("WifiPhyMuMimoTest", LOG_LEVEL_ALL);
+
+    Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
+    Ptr<ConstantSpeedPropagationDelayModel> delayModel =
+        CreateObject<ConstantSpeedPropagationDelayModel>();
+    spectrumChannel->SetPropagationDelayModel(delayModel);
+
+    Ptr<Node> apNode = CreateObject<Node>();
+    Ptr<WifiNetDevice> apDev = CreateObject<WifiNetDevice>();
+    apDev->SetStandard(WIFI_STANDARD_80211ax);
+    Ptr<ApWifiMac> apMac = CreateObject<ApWifiMac>();
+    apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
+    apDev->SetMac(apMac);
+    m_phyAp = CreateObject<MuMimoSpectrumWifiPhy>(0);
+    Ptr<HeConfiguration> heConfiguration = CreateObject<HeConfiguration>();
+    apDev->SetHeConfiguration(heConfiguration);
+    Ptr<InterferenceHelper> apInterferenceHelper = CreateObject<InterferenceHelper>();
+    m_phyAp->SetInterferenceHelper(apInterferenceHelper);
+    Ptr<ErrorRateModel> apErrorModel = CreateObject<NistErrorRateModel>();
+    m_phyAp->SetErrorRateModel(apErrorModel);
+    m_phyAp->SetDevice(apDev);
+    m_phyAp->AddChannel(spectrumChannel);
+    m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
+    m_phyAp->SetReceiveOkCallback(MakeCallback(&TestUlMuMimoPhyTransmission::RxSuccess, this));
+    m_phyAp->SetReceiveErrorCallback(MakeCallback(&TestUlMuMimoPhyTransmission::RxFailure, this));
+    apDev->SetPhy(m_phyAp);
+    apNode->AddDevice(apDev);
+
+    for (std::size_t i = 1; i <= 4; ++i)
+    {
+        Ptr<Node> staNode = CreateObject<Node>();
+        Ptr<WifiNetDevice> staDev = CreateObject<WifiNetDevice>();
+        staDev->SetStandard(WIFI_STANDARD_80211ax);
+        Ptr<MuMimoSpectrumWifiPhy> phy = CreateObject<MuMimoSpectrumWifiPhy>(i);
+        staDev->SetHeConfiguration(CreateObject<HeConfiguration>());
+        Ptr<InterferenceHelper> staInterferenceHelper = CreateObject<InterferenceHelper>();
+        phy->SetInterferenceHelper(staInterferenceHelper);
+        Ptr<ErrorRateModel> staErrorModel = CreateObject<NistErrorRateModel>();
+        phy->SetErrorRateModel(staErrorModel);
+        phy->SetDevice(staDev);
+        phy->AddChannel(spectrumChannel);
+        phy->ConfigureStandard(WIFI_STANDARD_80211ax);
+        phy->SetAttribute("TxGain", DoubleValue(1.0));
+        phy->SetAttribute("TxPowerStart", DoubleValue(16.0));
+        phy->SetAttribute("TxPowerEnd", DoubleValue(16.0));
+        phy->SetAttribute("PowerDensityLimit", DoubleValue(100.0)); // no impact by default
+        phy->SetAttribute("RxGain", DoubleValue(2.0));
+        staDev->SetPhy(phy);
+        staNode->AddDevice(staDev);
+        m_phyStas.push_back(phy);
+        m_countRxSuccessFromStas.push_back(0);
+        m_countRxFailureFromStas.push_back(0);
+        m_countRxBytesFromStas.push_back(0);
+    }
+}
+
+void
+TestUlMuMimoPhyTransmission::DoTeardown()
+{
+    for (auto& phy : m_phyStas)
+    {
+        phy->Dispose();
+        phy = nullptr;
+    }
+}
+
+void
+TestUlMuMimoPhyTransmission::LogScenario(const std::string& log) const
+{
+    NS_LOG_INFO(log);
+}
+
+void
+TestUlMuMimoPhyTransmission::ScheduleTest(
+    Time delay,
+    const std::vector<uint16_t>& txStaIds,
+    WifiPhyState expectedStateAtEnd,
+    const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta)
+{
+    static uint64_t uid = 0;
+
+    // AP sends an SU packet preceding HE TB PPDUs
+    Simulator::Schedule(delay - MilliSeconds(10),
+                        &TestUlMuMimoPhyTransmission::SendHeSuPpdu,
+                        this,
+                        0,
+                        50,
+                        ++uid,
+                        0);
+
+    Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::SetTrigVector, this, txStaIds, 0);
+
+    // STAs send MU UL PPDUs addressed to AP
+    uint16_t payloadSize = 1000;
+    std::size_t index = 0;
+    for (auto txStaId : txStaIds)
+    {
+        Simulator::Schedule(delay + (index * m_delayStart),
+                            &TestUlMuMimoPhyTransmission::SendHeTbPpdu,
+                            this,
+                            txStaId,
+                            1,
+                            payloadSize,
+                            uid,
+                            0);
+        payloadSize++;
+        index++;
+    }
+
+    // Verify it takes m_expectedPpduDuration to transmit the PPDUs
+    Simulator::Schedule(delay + m_expectedPpduDuration - NanoSeconds(1),
+                        &TestUlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phyAp,
+                        WifiPhyState::RX);
+    Simulator::Schedule(delay + m_expectedPpduDuration +
+                            (m_delayStart * expectedCountersPerSta.size()),
+                        &TestUlMuMimoPhyTransmission::CheckPhyState,
+                        this,
+                        m_phyAp,
+                        expectedStateAtEnd);
+
+    delay += MilliSeconds(100);
+    // Check reception state from STAs
+    uint16_t staId = 1;
+    for (const auto& expectedCounters : expectedCountersPerSta)
+    {
+        uint16_t expectedSuccessFromSta = std::get<0>(expectedCounters);
+        uint16_t expectedFailuresFromSta = std::get<1>(expectedCounters);
+        uint16_t expectedBytesFromSta = std::get<2>(expectedCounters);
+        Simulator::Schedule(delay + (m_delayStart * (staId - 1)),
+                            &TestUlMuMimoPhyTransmission::CheckRxFromSta,
+                            this,
+                            staId,
+                            expectedSuccessFromSta,
+                            expectedFailuresFromSta,
+                            expectedBytesFromSta);
+        staId++;
+    }
+
+    // Verify events data have been cleared
+    Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::VerifyEventsCleared, this);
+
+    delay += MilliSeconds(100);
+    Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::Reset, this);
+}
+
+void
+TestUlMuMimoPhyTransmission::RunOne()
+{
+    RngSeedManager::SetSeed(1);
+    RngSeedManager::SetRun(1);
+    int64_t streamNumber = 0;
+    m_phyAp->AssignStreams(streamNumber);
+    for (auto& phy : m_phyStas)
+    {
+        phy->AssignStreams(streamNumber);
+    }
+
+    auto channelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
+                                                                      m_frequency,
+                                                                      m_channelWidth,
+                                                                      WIFI_STANDARD_80211ax,
+                                                                      WIFI_PHY_BAND_5GHZ));
+
+    m_phyAp->SetOperatingChannel(
+        WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0});
+    for (auto& phy : m_phyStas)
+    {
+        phy->SetOperatingChannel(
+            WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, 0});
+    }
+
+    Time delay = Seconds(0.0);
+    Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::Reset, this);
+    delay += Seconds(1.0);
+
+    //---------------------------------------------------------------------------
+    // Verify that all HE TB PPDUs using full BW MU-MIMO have been corrected received
+    Simulator::Schedule(delay,
+                        &TestUlMuMimoPhyTransmission::LogScenario,
+                        this,
+                        "Reception of HE TB PPDUs using full BW MU-MIMO");
+    ScheduleTest(delay,
+                 {1, 2, 3},
+                 WifiPhyState::IDLE,
+                 {
+                     std::make_tuple(1, 0, 1000), // One PSDU of 1000 bytes should have been
+                                                  // successfully received from STA 1
+                     std::make_tuple(1, 0, 1001), // One PSDU of 1001 bytes should have been
+                                                  // successfully received from STA 2
+                     std::make_tuple(1, 0, 1002)  // One PSDU of 1002 bytes should have been
+                                                  // successfully received from STA 3
+                 });
+    delay += Seconds(1.0);
+
+    //---------------------------------------------------------------------------
+    // Send an HE SU PPDU during 400 ns window and verify that all HE TB PPDUs using full BW MU-MIMO
+    // have been impacted
+    Simulator::Schedule(delay,
+                        &TestUlMuMimoPhyTransmission::LogScenario,
+                        this,
+                        "Reception of HE TB PPDUs HE TB PPDUs using full BW MU-MIMO with an HE SU "
+                        "PPDU arriving during the 400 ns window");
+    // One HE SU arrives at AP during the 400ns window
+    Simulator::Schedule(delay + NanoSeconds(150),
+                        &TestUlMuMimoPhyTransmission::SendHeSuPpdu,
+                        this,
+                        4,
+                        1002,
+                        2,
+                        0);
+    ScheduleTest(delay,
+                 {1, 2, 3},
+                 WifiPhyState::IDLE,
+                 {
+                     std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
+                                               // failed (since interference from STA 4)
+                     std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
+                                               // failed (since interference from STA 4)
+                     std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
+                                              // (since interference from STA 4)
+                 });
+    delay += Seconds(1.0);
+
+    //---------------------------------------------------------------------------
+    // Send an HE SU PPDU during HE portion reception and verify that all HE TB PPDUs have been
+    // impacted
+    Simulator::Schedule(delay,
+                        &TestUlMuMimoPhyTransmission::LogScenario,
+                        this,
+                        "Reception of HE TB PPDUs using full BW MU-MIMO with an HE SU PPDU "
+                        "arriving during the HE portion");
+    // One HE SU arrives at AP during the HE portion
+    Simulator::Schedule(delay + MicroSeconds(40),
+                        &TestUlMuMimoPhyTransmission::SendHeSuPpdu,
+                        this,
+                        4,
+                        1002,
+                        2,
+                        0);
+    ScheduleTest(delay,
+                 {1, 2, 3},
+                 WifiPhyState::CCA_BUSY,
+                 {
+                     std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
+                                               // failed (since interference from STA 4)
+                     std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
+                                               // failed (since interference from STA 4)
+                     std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
+                                              // (since interference from STA 4)
+                 });
+    delay += Seconds(1.0);
+
+    Simulator::Run();
+}
+
+void
+TestUlMuMimoPhyTransmission::DoRun()
+{
+    std::vector<Time> startDelays{NanoSeconds(0), NanoSeconds(100)};
+
+    for (const auto& delayStart : startDelays)
+    {
+        m_delayStart = delayStart;
+
+        m_frequency = 5180;
+        m_channelWidth = 20;
+        m_expectedPpduDuration = NanoSeconds(163200);
+        NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
+                     << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
+                     << m_delayStart);
+        RunOne();
+
+        m_frequency = 5190;
+        m_channelWidth = 40;
+        m_expectedPpduDuration = NanoSeconds(105600);
+        NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
+                     << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
+                     << m_delayStart);
+        RunOne();
+
+        m_frequency = 5210;
+        m_channelWidth = 80;
+        m_expectedPpduDuration = NanoSeconds(76800);
+        NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
+                     << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
+                     << m_delayStart);
+        RunOne();
+
+        m_frequency = 5250;
+        m_channelWidth = 160;
+        m_expectedPpduDuration = NanoSeconds(62400);
+        NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
+                     << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
+                     << m_delayStart);
+        RunOne();
+    }
+
+    Simulator::Destroy();
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
+ * \brief wifi PHY MU-MIMO Test Suite
+ */
+class WifiPhyMuMimoTestSuite : public TestSuite
+{
+  public:
+    WifiPhyMuMimoTestSuite();
+};
+
+WifiPhyMuMimoTestSuite::WifiPhyMuMimoTestSuite()
+    : TestSuite("wifi-phy-mu-mimo", UNIT)
+{
+    AddTestCase(new TestDlMuTxVector, TestCase::QUICK);
+    AddTestCase(new TestDlMuMimoPhyTransmission, TestCase::QUICK);
+    AddTestCase(new TestUlMuMimoPhyTransmission, TestCase::QUICK);
+}
+
+static WifiPhyMuMimoTestSuite WifiPhyMuMimoTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-phy-ofdma-test.cc ns-3.40/src/wifi/test/wifi-phy-ofdma-test.cc
--- ns-3.39/src/wifi/test/wifi-phy-ofdma-test.cc	2023-07-05 14:23:48.129428400 -0700
+++ ns-3.40/src/wifi/test/wifi-phy-ofdma-test.cc	2023-09-27 13:30:37.926839800 -0700
@@ -2430,9 +2430,8 @@
                                       HePpdu::PSD_NON_HE_PORTION);
 
     // Send non-OFDMA part
-    Time nonOfdmaDuration = m_phy->GetHePhy()->CalculateNonOfdmaDurationForHeTb(txVector);
-    uint32_t centerFrequency =
-        m_phy->GetHePhy()->GetCenterFrequencyForNonOfdmaPart(txVector, staId);
+    Time nonOfdmaDuration = m_phy->GetHePhy()->CalculateNonHeDurationForHeTb(txVector);
+    uint32_t centerFrequency = m_phy->GetHePhy()->GetCenterFrequencyForNonHePart(txVector, staId);
     uint16_t ruWidth = HeRu::GetBandwidth(txVector.GetRu(staId).GetRuType());
     uint16_t channelWidth = ruWidth < 20 ? 20 : ruWidth;
     Ptr<SpectrumValue> rxPsd = WifiSpectrumValueHelper::CreateHeOfdmTxPowerSpectralDensity(
@@ -2445,7 +2444,6 @@
     rxParams->txPhy = nullptr;
     rxParams->duration = nonOfdmaDuration;
     rxParams->ppdu = ppdu;
-    rxParams->txWidth = channelWidth;
 
     uint16_t length;
     std::tie(length, ppduDuration) =
@@ -2472,7 +2470,6 @@
     rxParamsOfdma->txPhy = nullptr;
     rxParamsOfdma->duration = ppduDuration - nonOfdmaDuration;
     rxParamsOfdma->ppdu = ppduOfdma;
-    rxParamsOfdma->txWidth = DEFAULT_CHANNEL_WIDTH;
     Simulator::Schedule(nonOfdmaDuration,
                         &TestMultipleHeTbPreambles::RxHeTbPpduOfdmaPart,
                         this,
@@ -3982,8 +3979,8 @@
     WifiTxVector txVectorSta1 = GetTxVectorForHeTbPpdu(1, 1, 0);
     WifiTxVector txVectorSta2 = GetTxVectorForHeTbPpdu(2, 2, 0);
     Ptr<const HePhy> hePhy = m_phyAp->GetHePhy();
-    Time nonOfdmaDuration = hePhy->CalculateNonOfdmaDurationForHeTb(txVectorSta2);
-    NS_ASSERT(nonOfdmaDuration == hePhy->CalculateNonOfdmaDurationForHeTb(txVectorSta1));
+    Time nonOfdmaDuration = hePhy->CalculateNonHeDurationForHeTb(txVectorSta2);
+    NS_ASSERT(nonOfdmaDuration == hePhy->CalculateNonHeDurationForHeTb(txVectorSta1));
 
     std::vector<double> rxPowerNonOfdma{rxPowerNonOfdmaRu1, rxPowerNonOfdmaRu2};
     std::vector<WifiSpectrumBandInfo> nonOfdmaBand{hePhy->GetNonOfdmaBand(txVectorSta1, 1),
@@ -4891,7 +4888,7 @@
                                          DEFAULT_CHANNEL_WIDTH,
                                          false,
                                          false,
-                                         1);
+                                         true);
 
     HeRu::RuSpec ru(HeRu::RU_106_TONE, index, false);
     txVector.SetRu(ru, txStaId);
@@ -5187,7 +5184,7 @@
                             DEFAULT_CHANNEL_WIDTH,
                             false,
                             false,
-                            1);
+                            true);
     trigVector.SetRu(HeRu::RuSpec(HeRu::RU_106_TONE, 1, false), 1);
     trigVector.SetMode(HePhy::GetHeMcs7(), 1);
     trigVector.SetNss(1, 1);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-phy-reception-test.cc ns-3.40/src/wifi/test/wifi-phy-reception-test.cc
--- ns-3.39/src/wifi/test/wifi-phy-reception-test.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wifi/test/wifi-phy-reception-test.cc	2023-09-27 13:30:37.926839800 -0700
@@ -145,7 +145,6 @@
     txParams->txPhy = nullptr;
     txParams->duration = txDuration;
     txParams->ppdu = ppdu;
-    txParams->txWidth = CHANNEL_WIDTH;
 
     m_phy->StartRx(txParams, nullptr);
 }
@@ -2805,7 +2804,6 @@
     txParams->txPhy = nullptr;
     txParams->duration = txDuration;
     txParams->ppdu = ppdu;
-    txParams->txWidth = CHANNEL_WIDTH;
 
     m_phy->StartRx(txParams, nullptr);
 }
@@ -4328,7 +4326,6 @@
     txParams->txPhy = nullptr;
     txParams->duration = txDuration;
     txParams->ppdu = ppdu;
-    txParams->txWidth = bandwidthMhz;
 
     m_rxPhy->StartRx(txParams, nullptr);
 }
@@ -4619,12 +4616,8 @@
                           "PPDU is " << (expectedP20Overlap ? "expected" : "not expected")
                                      << " to overlap with the P20");
 
-    auto p20Covered =
-        m_rxPhy->GetPhyEntity(WIFI_STANDARD_80211ax)
-            ->CanStartRx(
-                ppdu,
-                ppdu->GetTxVector()
-                    .GetChannelWidth()); // CanStartRx returns true is the P20 is fully covered
+    auto p20Covered = m_rxPhy->GetPhyEntity(WIFI_STANDARD_80211ax)
+                          ->CanStartRx(ppdu); // CanStartRx returns true is the P20 is fully covered
     NS_TEST_ASSERT_MSG_EQ(p20Covered,
                           expectedP20Covered,
                           "PPDU is " << (expectedP20Covered ? "expected" : "not expected")
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-phy-thresholds-test.cc ns-3.40/src/wifi/test/wifi-phy-thresholds-test.cc
--- ns-3.39/src/wifi/test/wifi-phy-thresholds-test.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wifi/test/wifi-phy-thresholds-test.cc	2023-09-27 13:30:37.926839800 -0700
@@ -179,7 +179,6 @@
     txParams->txPhy = nullptr;
     txParams->duration = txDuration;
     txParams->ppdu = ppdu;
-    txParams->txWidth = CHANNEL_WIDTH;
     return txParams;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-primary-channels-test.cc ns-3.40/src/wifi/test/wifi-primary-channels-test.cc
--- ns-3.39/src/wifi/test/wifi-primary-channels-test.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wifi/test/wifi-primary-channels-test.cc	2023-09-27 13:30:37.926839800 -0700
@@ -665,7 +665,7 @@
         {
             for (unsigned int type = 0; type < 7; type++)
             {
-                HeRu::RuType ruType = static_cast<HeRu::RuType>(type);
+                auto ruType = static_cast<HeRu::RuType>(type);
                 std::size_t nRus = HeRu::GetNRus(txChannelWidth, ruType);
                 std::set<uint8_t> txBss;
                 if (nRus > 0)
@@ -713,7 +713,7 @@
         {
             for (unsigned int type = 0; type < 7; type++)
             {
-                HeRu::RuType ruType = static_cast<HeRu::RuType>(type);
+                auto ruType = static_cast<HeRu::RuType>(type);
                 std::size_t nRus = HeRu::GetNRus(txChannelWidth, ruType);
                 std::set<uint8_t> txBss;
                 if (nRus > 0)
@@ -1375,10 +1375,13 @@
     // 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);
+#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);
+#endif
     AddTestCase(new Wifi20MHzChannelIndicesTest(), TestCase::QUICK);
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-test.cc ns-3.40/src/wifi/test/wifi-test.cc
--- ns-3.39/src/wifi/test/wifi-test.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wifi/test/wifi-test.cc	2023-09-27 13:30:37.926839800 -0700
@@ -1185,7 +1185,6 @@
         staDevice = wifi.Install(phy, macSta, wifiStaNode.Get(0));
         phySta = GetYansWifiPhyPtr(staDevice);
         phySta->SetAttribute("ChannelSettings", StringValue("{3, 20, BAND_2_4GHZ, 0}"));
-        return;
         // Post-install reconfiguration to a 40 MHz channel
         std::ostringstream path;
         path << "/NodeList/*/DeviceList/" << staDevice.Get(0)->GetIfIndex()
@@ -1579,9 +1578,7 @@
     FreqWidthSubbandModulationTuple tupleForCurrentTx =
         std::make_tuple(startingFreq, m_channelWidth, numBands, modulationClass);
     bool found = false;
-    for (std::vector<FreqWidthSubbandModulationTuple>::const_iterator it = m_distinctTuples.begin();
-         it != m_distinctTuples.end();
-         it++)
+    for (auto it = m_distinctTuples.begin(); it != m_distinctTuples.end(); it++)
     {
         if (*it == tupleForCurrentTx)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wifi/test/wifi-transmit-mask-test.cc ns-3.40/src/wifi/test/wifi-transmit-mask-test.cc
--- ns-3.39/src/wifi/test/wifi-transmit-mask-test.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wifi/test/wifi-transmit-mask-test.cc	2023-09-27 13:30:37.926839800 -0700
@@ -994,7 +994,7 @@
                                                maskSlopes,
                                                tol,
                                                prec,
-                                               {1, 0, 0, 0}),
+                                               {true, false, false, false}),
                 TestCase::QUICK);
 
     // ============================================================================================
@@ -1038,7 +1038,7 @@
                                                maskSlopes,
                                                tol,
                                                prec,
-                                               {0, 1, 0, 0}),
+                                               {false, true, false, false}),
                 TestCase::QUICK);
 
     // ============================================================================================
@@ -1082,7 +1082,7 @@
                                                maskSlopes,
                                                tol,
                                                prec,
-                                               {0, 0, 1, 0}),
+                                               {false, false, true, false}),
                 TestCase::QUICK);
 
     // ============================================================================================
@@ -1122,7 +1122,7 @@
                                                maskSlopes,
                                                tol,
                                                prec,
-                                               {0, 0, 0, 1}),
+                                               {false, false, false, true}),
                 TestCase::QUICK);
 
     // ============================================================================================
@@ -1162,15 +1162,16 @@
         std::make_pair(6144, -40.0),    // Outer band right (stop)
     };
 
-    AddTestCase(new WifiOfdmMaskSlopesTestCase("11ax_5GHz 160MHz first subchannels punctured",
-                                               WIFI_STANDARD_80211ax,
-                                               WIFI_PHY_BAND_5GHZ,
-                                               160,
-                                               maskSlopes,
-                                               tol,
-                                               prec,
-                                               {1, 1, 0, 0, 0, 0, 0, 0}),
-                TestCase::QUICK);
+    AddTestCase(
+        new WifiOfdmMaskSlopesTestCase("11ax_5GHz 160MHz first subchannels punctured",
+                                       WIFI_STANDARD_80211ax,
+                                       WIFI_PHY_BAND_5GHZ,
+                                       160,
+                                       maskSlopes,
+                                       tol,
+                                       prec,
+                                       {true, true, false, false, false, false, false, false}),
+        TestCase::QUICK);
 
     // ============================================================================================
     // 11ax 160MHz @ 5GHz - third and fourth 20 MHz subchannels punctured
@@ -1219,7 +1220,7 @@
                                        maskSlopes,
                                        tol,
                                        prec,
-                                       {0, 0, 1, 1, 0, 0, 0, 0}),
+                                       {false, false, true, true, false, false, false, false}),
         TestCase::QUICK);
 
     // ============================================================================================
@@ -1269,7 +1270,7 @@
                                        maskSlopes,
                                        tol,
                                        prec,
-                                       {0, 0, 0, 0, 1, 1, 0, 0}),
+                                       {false, false, false, false, true, true, false, false}),
         TestCase::QUICK);
 
     // ============================================================================================
@@ -1309,13 +1310,14 @@
         std::make_pair(6144, -40.0),   // Outer band right (stop)
     };
 
-    AddTestCase(new WifiOfdmMaskSlopesTestCase("11ax_5GHz 160MHz last subchannels punctured",
-                                               WIFI_STANDARD_80211ax,
-                                               WIFI_PHY_BAND_5GHZ,
-                                               160,
-                                               maskSlopes,
-                                               tol,
-                                               prec,
-                                               {0, 0, 0, 0, 0, 0, 1, 1}),
-                TestCase::QUICK);
+    AddTestCase(
+        new WifiOfdmMaskSlopesTestCase("11ax_5GHz 160MHz last subchannels punctured",
+                                       WIFI_STANDARD_80211ax,
+                                       WIFI_PHY_BAND_5GHZ,
+                                       160,
+                                       maskSlopes,
+                                       tol,
+                                       prec,
+                                       {false, false, false, false, false, false, true, true}),
+        TestCase::QUICK);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/examples/wimax-ipv4.cc ns-3.40/src/wimax/examples/wimax-ipv4.cc
--- ns-3.39/src/wimax/examples/wimax-ipv4.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/examples/wimax-ipv4.cc	2023-09-27 13:30:37.926839800 -0700
@@ -117,7 +117,7 @@
                            WimaxHelper::SIMPLE_PHY_TYPE_OFDM,
                            scheduler);
 
-    Ptr<SubscriberStationNetDevice>* ss = new Ptr<SubscriberStationNetDevice>[nbSS];
+    auto ss = new Ptr<SubscriberStationNetDevice>[nbSS];
 
     for (int i = 0; i < nbSS; i++)
     {
@@ -146,10 +146,10 @@
         WimaxHelper::EnableLogComponents(); // Turn on all wimax logging
     }
     /*------------------------------*/
-    UdpServerHelper* udpServer = new UdpServerHelper[nbSS / 2];
-    ApplicationContainer* serverApps = new ApplicationContainer[nbSS / 2];
-    UdpClientHelper* udpClient = new UdpClientHelper[nbSS / 2];
-    ApplicationContainer* clientApps = new ApplicationContainer[nbSS / 2];
+    auto udpServer = new UdpServerHelper[nbSS / 2];
+    auto serverApps = new ApplicationContainer[nbSS / 2];
+    auto udpClient = new UdpClientHelper[nbSS / 2];
+    auto clientApps = new ApplicationContainer[nbSS / 2];
 
     for (int i = 0; i < nbSS / 2; i++)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/helper/wimax-helper.cc ns-3.40/src/wimax/helper/wimax-helper.cc
--- ns-3.39/src/wimax/helper/wimax-helper.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/helper/wimax-helper.cc	2023-09-27 13:30:37.926839800 -0700
@@ -224,7 +224,7 @@
                      double frameDuration)
 {
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); i++)
+    for (auto i = c.Begin(); i != c.End(); i++)
     {
         Ptr<Node> node = *i;
         Ptr<WimaxPhy> phy = CreatePhy(phyType);
@@ -268,7 +268,7 @@
                      SchedulerType schedulerType)
 {
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); i++)
+    for (auto i = c.Begin(); i != c.End(); i++)
     {
         Ptr<Node> node = *i;
         Ptr<WimaxPhy> phy = CreatePhy(phyType);
@@ -309,11 +309,11 @@
                      SchedulerType schedulerType)
 {
     NetDeviceContainer devices;
-    for (NodeContainer::Iterator i = c.Begin(); i != c.End(); i++)
+    for (auto i = c.Begin(); i != c.End(); i++)
     {
         Ptr<Node> node = *i;
 
-        Ptr<WimaxPhy> phy = CreatePhyWithoutChannel(phyType, (char*)"dummy", 0);
+        Ptr<WimaxPhy> phy = CreatePhyWithoutChannel(phyType, (char*)"dummy", false);
         Ptr<WimaxNetDevice> device;
         Ptr<UplinkScheduler> uplinkScheduler = CreateUplinkScheduler(schedulerType);
         Ptr<BSScheduler> bsScheduler = CreateBSScheduler(schedulerType);
@@ -349,7 +349,7 @@
                      SchedulerType schedulerType)
 {
     // Ptr<WimaxPhy> phy = CreatePhyWithoutChannel (phyType);
-    Ptr<WimaxPhy> phy = CreatePhyWithoutChannel(phyType, (char*)"dummy", 0);
+    Ptr<WimaxPhy> phy = CreatePhyWithoutChannel(phyType, (char*)"dummy", false);
     Ptr<WimaxNetDevice> device;
     Ptr<UplinkScheduler> uplinkScheduler = CreateUplinkScheduler(schedulerType);
     Ptr<BSScheduler> bsScheduler = CreateBSScheduler(schedulerType);
@@ -637,7 +637,7 @@
 PcapSniffTxRxEvent(Ptr<PcapFileWrapper> file, Ptr<const PacketBurst> burst)
 {
     std::list<Ptr<Packet>> packets = burst->GetPackets();
-    for (std::list<Ptr<Packet>>::iterator iter = packets.begin(); iter != packets.end(); ++iter)
+    for (auto iter = packets.begin(); iter != packets.end(); ++iter)
     {
         Ptr<Packet> p = (*iter)->Copy();
         WimaxMacToMacHeader m2m(p->GetSize());
@@ -696,7 +696,7 @@
 {
     int64_t currentStream = stream;
     Ptr<NetDevice> netDevice;
-    for (NetDeviceContainer::Iterator i = c.Begin(); i != c.End(); ++i)
+    for (auto i = c.Begin(); i != c.End(); ++i)
     {
         netDevice = (*i);
         Ptr<WimaxNetDevice> wimax = DynamicCast<WimaxNetDevice>(netDevice);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/bandwidth-manager.cc ns-3.40/src/wimax/model/bandwidth-manager.cc
--- ns-3.39/src/wimax/model/bandwidth-manager.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/bandwidth-manager.cc	2023-09-27 13:30:37.926839800 -0700
@@ -129,9 +129,7 @@
     std::vector<ServiceFlow*> serviceFlows =
         ss->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_ALL);
 
-    for (std::vector<ServiceFlow*>::iterator iter = serviceFlows.begin();
-         iter != serviceFlows.end();
-         ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         serviceFlow = *iter;
         if (serviceFlow->GetSchedulingType() == ServiceFlow::SF_TYPE_RTPS ||
@@ -229,15 +227,11 @@
     uint32_t allocationPerFrame = 0;
 
     std::vector<SSRecord*>* ssRecords = bs->GetSSManager()->GetSSRecords();
-    for (std::vector<SSRecord*>::const_iterator iter1 = ssRecords->begin();
-         iter1 != ssRecords->end();
-         ++iter1)
+    for (auto iter1 = ssRecords->begin(); iter1 != ssRecords->end(); ++iter1)
     {
         std::vector<ServiceFlow*> ssServiceFlows =
             (*iter1)->GetServiceFlows(ServiceFlow::SF_TYPE_ALL);
-        for (std::vector<ServiceFlow*>::const_iterator iter2 = ssServiceFlows.begin();
-             iter2 != ssServiceFlows.end();
-             ++iter2)
+        for (auto iter2 = ssServiceFlows.begin(); iter2 != ssServiceFlows.end(); ++iter2)
         {
             allocationPerFrame += (*iter2)->GetRecord()->GetGrantSize();
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/bs-link-manager.cc ns-3.40/src/wimax/model/bs-link-manager.cc
--- ns-3.39/src/wimax/model/bs-link-manager.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/bs-link-manager.cc	2023-09-27 13:30:37.926839800 -0700
@@ -257,7 +257,7 @@
 
             if (ssRecord->GetInvitedRangRetries() == m_bs->GetMaxInvitedRangRetries())
             {
-                RngRsp* rngrsp = new RngRsp();
+                auto rngrsp = new RngRsp();
                 AbortRanging(ssRecord->GetBasicCid(), rngrsp, ssRecord, true);
             } // else keep polling
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/bs-net-device.cc ns-3.40/src/wimax/model/bs-net-device.cc
--- ns-3.39/src/wimax/model/bs-net-device.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/bs-net-device.cc	2023-09-27 13:30:37.926839800 -0700
@@ -851,9 +851,7 @@
 
                     // DEFRAGMENTATION
                     NS_LOG_INFO("\t BS PACKET DEFRAGMENTATION" << std::endl);
-                    for (std::list<Ptr<const Packet>>::const_iterator iter = fragmentsQueue.begin();
-                         iter != fragmentsQueue.end();
-                         ++iter)
+                    for (auto iter = fragmentsQueue.begin(); iter != fragmentsQueue.end(); ++iter)
                     {
                         // Create the whole Packet
                         fullPacket->AddAtEnd(*iter);
@@ -1029,10 +1027,7 @@
     std::list<std::pair<OfdmDlMapIe*, Ptr<PacketBurst>>>* downlinkBursts =
         m_scheduler->GetDownlinkBursts();
 
-    for (std::list<std::pair<OfdmDlMapIe*, Ptr<PacketBurst>>>::iterator iter =
-             downlinkBursts->begin();
-         iter != downlinkBursts->end();
-         ++iter)
+    for (auto iter = downlinkBursts->begin(); iter != downlinkBursts->end(); ++iter)
     {
         iter->first->SetPreamblePresent(0);
         iter->first->SetStartTime(0);
@@ -1096,9 +1091,7 @@
 
     std::list<OfdmUlMapIe> uplinkAllocations = m_uplinkScheduler->GetUplinkAllocations();
 
-    for (std::list<OfdmUlMapIe>::iterator iter = uplinkAllocations.begin();
-         iter != uplinkAllocations.end();
-         ++iter)
+    for (auto iter = uplinkAllocations.begin(); iter != uplinkAllocations.end(); ++iter)
     {
         ulmap.AddUlMapElement(*iter);
     }
@@ -1197,9 +1190,7 @@
 {
     uint16_t symbolsToAllocation = 0;
     std::list<OfdmUlMapIe> uplinkAllocations = m_uplinkScheduler->GetUplinkAllocations();
-    for (std::list<OfdmUlMapIe>::iterator iter = uplinkAllocations.begin();
-         iter != uplinkAllocations.end();
-         ++iter)
+    for (auto iter = uplinkAllocations.begin(); iter != uplinkAllocations.end(); ++iter)
     {
         OfdmUlMapIe uplinkAllocation = *iter;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/bs-net-device.h ns-3.40/src/wimax/model/bs-net-device.h
--- ns-3.39/src/wimax/model/bs-net-device.h	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/bs-net-device.h	2023-09-27 13:30:37.926839800 -0700
@@ -21,12 +21,12 @@
 #ifndef WIMAX_BS_NET_DEVICE_H
 #define WIMAX_BS_NET_DEVICE_H
 
+#include "bs-service-flow-manager.h"
 #include "dl-mac-messages.h"
 #include "ipcs-classifier.h"
 #include "wimax-connection.h"
 #include "wimax-net-device.h"
 
-#include "ns3/bs-service-flow-manager.h"
 #include "ns3/event-id.h"
 #include "ns3/ipv4-address.h"
 #include "ns3/mac48-address.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/bs-scheduler-rtps.cc ns-3.40/src/wimax/model/bs-scheduler-rtps.cc
--- ns-3.39/src/wimax/model/bs-scheduler-rtps.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/bs-scheduler-rtps.cc	2023-09-27 13:30:37.926839800 -0700
@@ -96,7 +96,7 @@
                                   WimaxPhy::ModulationType modulationType,
                                   Ptr<PacketBurst> burst)
 {
-    OfdmDlMapIe* dlMapIe = new OfdmDlMapIe();
+    auto dlMapIe = new OfdmDlMapIe();
     dlMapIe->SetCid(connection->GetCid());
     dlMapIe->SetDiuc(diuc);
 
@@ -319,11 +319,10 @@
     Ptr<Packet> packet;
     Ptr<PacketBurst> burst = Create<PacketBurst>();
 
-    std::vector<Ptr<WimaxConnection>>::const_iterator iter;
     std::vector<Ptr<WimaxConnection>> connections;
 
     connections = GetBs()->GetConnectionManager()->GetConnections(Cid::BASIC);
-    for (iter = connections.begin(); iter != connections.end(); ++iter)
+    for (auto iter = connections.begin(); iter != connections.end(); ++iter)
     {
         while ((*iter)->HasPackets() && availableSymbols > 0)
         {
@@ -381,11 +380,10 @@
     Ptr<Packet> packet;
     Ptr<PacketBurst> burst = Create<PacketBurst>();
 
-    std::vector<Ptr<WimaxConnection>>::const_iterator iter;
     std::vector<Ptr<WimaxConnection>> connections;
 
     connections = GetBs()->GetConnectionManager()->GetConnections(Cid::PRIMARY);
-    for (iter = connections.begin(); iter != connections.end(); ++iter)
+    for (auto iter = connections.begin(); iter != connections.end(); ++iter)
     {
         while ((*iter)->HasPackets() && availableSymbols > 0)
         {
@@ -444,12 +442,11 @@
 
     Time currentTime = Simulator::Now();
 
-    std::vector<ServiceFlow*>::iterator iter;
     ServiceFlowRecord* serviceFlowRecord;
     std::vector<ServiceFlow*> serviceFlows;
 
     serviceFlows = GetBs()->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_UGS);
-    for (iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         serviceFlowRecord = (*iter)->GetRecord();
         // if latency would exceed in case grant is allocated in next frame then allocate in current
@@ -503,7 +500,6 @@
     Time currentTime = Simulator::Now();
 
     std::vector<Ptr<WimaxConnection>> connections;
-    std::vector<ServiceFlow*>::iterator iter2;
     ServiceFlowRecord* serviceFlowRecord;
     std::vector<ServiceFlow*> serviceFlows;
 
@@ -520,7 +516,7 @@
 
     serviceFlows = GetBs()->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_RTPS);
     nbConnection = 0;
-    for (iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
+    for (auto iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
     {
         // DL RTPS Scheduler works for all rtPS connection that have packets to transmitt!!!
         serviceFlowRecord = (*iter2)->GetRecord();
@@ -644,11 +640,10 @@
     Ptr<Packet> packet;
     Ptr<PacketBurst> burst = Create<PacketBurst>();
 
-    std::vector<ServiceFlow*>::iterator iter;
     std::vector<ServiceFlow*> serviceFlows;
 
     serviceFlows = GetBs()->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_NRTPS);
-    for (iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         connection = (*iter)->GetConnection();
 
@@ -702,11 +697,10 @@
     Ptr<Packet> packet;
     Ptr<PacketBurst> burst = Create<PacketBurst>();
 
-    std::vector<ServiceFlow*>::iterator iter;
     std::vector<ServiceFlow*> serviceFlows;
 
     serviceFlows = GetBs()->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_BE);
-    for (iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         connection = (*iter)->GetConnection();
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/bs-scheduler-simple.cc ns-3.40/src/wimax/model/bs-scheduler-simple.cc
--- ns-3.39/src/wimax/model/bs-scheduler-simple.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/bs-scheduler-simple.cc	2023-09-27 13:30:37.926839800 -0700
@@ -94,7 +94,7 @@
                                     WimaxPhy::ModulationType modulationType,
                                     Ptr<PacketBurst> burst)
 {
-    OfdmDlMapIe* dlMapIe = new OfdmDlMapIe();
+    auto dlMapIe = new OfdmDlMapIe();
     dlMapIe->SetCid(connection->GetCid());
     dlMapIe->SetDiuc(diuc);
 
@@ -243,8 +243,6 @@
 {
     connection = nullptr;
     Time currentTime = Simulator::Now();
-    std::vector<Ptr<WimaxConnection>>::const_iterator iter1;
-    std::vector<ServiceFlow*>::iterator iter2;
     ServiceFlowRecord* serviceFlowRecord;
     NS_LOG_INFO("BS Scheduler: Selecting connection...");
     if (GetBs()->GetBroadcastConnection()->HasPackets())
@@ -265,7 +263,7 @@
         std::vector<ServiceFlow*> serviceFlows;
 
         connections = GetBs()->GetConnectionManager()->GetConnections(Cid::BASIC);
-        for (iter1 = connections.begin(); iter1 != connections.end(); ++iter1)
+        for (auto iter1 = connections.begin(); iter1 != connections.end(); ++iter1)
         {
             if ((*iter1)->HasPackets())
             {
@@ -276,7 +274,7 @@
         }
 
         connections = GetBs()->GetConnectionManager()->GetConnections(Cid::PRIMARY);
-        for (iter1 = connections.begin(); iter1 != connections.end(); ++iter1)
+        for (auto iter1 = connections.begin(); iter1 != connections.end(); ++iter1)
         {
             if ((*iter1)->HasPackets())
             {
@@ -287,7 +285,7 @@
         }
 
         serviceFlows = GetBs()->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_UGS);
-        for (iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
+        for (auto iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
         {
             serviceFlowRecord = (*iter2)->GetRecord();
             NS_LOG_INFO("processing UGS: HAS PACKET="
@@ -310,7 +308,7 @@
         }
 
         serviceFlows = GetBs()->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_RTPS);
-        for (iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
+        for (auto iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
         {
             serviceFlowRecord = (*iter2)->GetRecord();
             // if latency would exceed in case poll is allocated in next frame then allocate in
@@ -329,7 +327,7 @@
 
         serviceFlows =
             GetBs()->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_NRTPS);
-        for (iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
+        for (auto iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
         {
             // unused: serviceFlowRecord = (*iter2)->GetRecord ();
             if ((*iter2)->HasPackets())
@@ -342,7 +340,7 @@
         }
 
         serviceFlows = GetBs()->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_BE);
-        for (iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
+        for (auto iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
         {
             // unused: serviceFlowRecord = (*iter2)->GetRecord ();
             if ((*iter2)->HasPackets())
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/bs-service-flow-manager.cc ns-3.40/src/wimax/model/bs-service-flow-manager.cc
--- ns-3.39/src/wimax/model/bs-service-flow-manager.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/bs-service-flow-manager.cc	2023-09-27 13:30:37.926839800 -0700
@@ -223,7 +223,7 @@
 void
 BsServiceFlowManager::AddMulticastServiceFlow(ServiceFlow sf, WimaxPhy::ModulationType modulation)
 {
-    ServiceFlow* serviceFlow = new ServiceFlow();
+    auto serviceFlow = new ServiceFlow();
     serviceFlow->CopyParametersFrom(sf);
     Ptr<BaseStationNetDevice> bs = m_device->GetObject<BaseStationNetDevice>();
     Ptr<WimaxConnection> multicastConnection =
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/bs-uplink-scheduler-mbqos.cc ns-3.40/src/wimax/model/bs-uplink-scheduler-mbqos.cc
--- ns-3.39/src/wimax/model/bs-uplink-scheduler-mbqos.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/bs-uplink-scheduler-mbqos.cc	2023-09-27 13:30:37.926839800 -0700
@@ -175,17 +175,14 @@
     std::vector<SSRecord*>* ssRecords = GetBs()->GetSSManager()->GetSSRecords();
 
     // For each SS
-    for (std::vector<SSRecord*>::iterator iter = ssRecords->begin(); iter != ssRecords->end();
-         ++iter)
+    for (auto iter = ssRecords->begin(); iter != ssRecords->end(); ++iter)
     {
         SSRecord* ssRecord = *iter;
         std::vector<ServiceFlow*> serviceFlows =
             ssRecord->GetServiceFlows(ServiceFlow::SF_TYPE_ALL);
 
         // For each flow
-        for (std::vector<ServiceFlow*>::iterator iter2 = serviceFlows.begin();
-             iter2 != serviceFlows.end();
-             ++iter2)
+        for (auto iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
         {
             ServiceFlow* serviceFlow = *iter2;
             if ((serviceFlow->GetSchedulingType() == ServiceFlow::SF_TYPE_RTPS) ||
@@ -235,8 +232,7 @@
     AllocateInitialRangingInterval(symbolsToAllocation, availableSymbols);
 
     std::vector<SSRecord*>* ssRecords = GetBs()->GetSSManager()->GetSSRecords();
-    for (std::vector<SSRecord*>::iterator iter = ssRecords->begin(); iter != ssRecords->end();
-         ++iter)
+    for (auto iter = ssRecords->begin(); iter != ssRecords->end(); ++iter)
     {
         SSRecord* ssRecord = *iter;
 
@@ -575,7 +571,7 @@
 UplinkSchedulerMBQoS::CountSymbolsQueue(std::list<Ptr<UlJob>> jobs)
 {
     uint32_t symbols = 0;
-    for (std::list<Ptr<UlJob>>::iterator iter = jobs.begin(); iter != jobs.end(); ++iter)
+    for (auto iter = jobs.begin(); iter != jobs.end(); ++iter)
     {
         Ptr<UlJob> job = *iter;
 
@@ -683,7 +679,7 @@
     // for each request in the intermediate queue
     if (!m_uplinkJobs_inter.empty())
     {
-        std::list<Ptr<UlJob>>::iterator iter = m_uplinkJobs_inter.begin();
+        auto iter = m_uplinkJobs_inter.begin();
 
         while (iter != m_uplinkJobs_inter.end() && availableSymbols)
         {
@@ -776,15 +772,12 @@
 
     // For each connection of type rtPS or nrtPS
     std::vector<SSRecord*>* ssRecords = GetBs()->GetSSManager()->GetSSRecords();
-    for (std::vector<SSRecord*>::iterator iter = ssRecords->begin(); iter != ssRecords->end();
-         ++iter)
+    for (auto iter = ssRecords->begin(); iter != ssRecords->end(); ++iter)
     {
         SSRecord* ssRecord = *iter;
         std::vector<ServiceFlow*> serviceFlows =
             ssRecord->GetServiceFlows(ServiceFlow::SF_TYPE_ALL);
-        for (std::vector<ServiceFlow*>::iterator iter2 = serviceFlows.begin();
-             iter2 != serviceFlows.end();
-             ++iter2)
+        for (auto iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
         {
             ServiceFlow* serviceFlow = *iter2;
             if (serviceFlow->GetSchedulingType() == ServiceFlow::SF_TYPE_RTPS ||
@@ -799,9 +792,7 @@
     }
 
     // for each request in the imermediate queue
-    for (std::list<Ptr<UlJob>>::const_iterator iter = m_uplinkJobs_inter.begin();
-         iter != m_uplinkJobs_inter.end();
-         ++iter)
+    for (auto iter = m_uplinkJobs_inter.begin(); iter != m_uplinkJobs_inter.end(); ++iter)
     {
         Ptr<UlJob> job = *iter;
         // SSRecord ssRecord = job->GetSsRecord();
@@ -850,9 +841,7 @@
 
     priorityUlJobs.sort(SortProcessPtr());
 
-    for (std::list<Ptr<PriorityUlJob>>::const_iterator iter = priorityUlJobs.begin();
-         iter != priorityUlJobs.end();
-         ++iter)
+    for (auto iter = priorityUlJobs.begin(); iter != priorityUlJobs.end(); ++iter)
     {
         Ptr<PriorityUlJob> priorityUlJob = *iter;
         Ptr<UlJob> job_priority = priorityUlJob->GetUlJob();
@@ -879,9 +868,7 @@
     uint8_t uiuc = ulMapIe.GetUiuc(); // SS's burst profile
     std::vector<ServiceFlow*> serviceFlows = ssRecord->GetServiceFlows(schedulingType);
 
-    for (std::vector<ServiceFlow*>::iterator iter = serviceFlows.begin();
-         iter != serviceFlows.end();
-         ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         ServiceFlow* serviceFlow = *iter;
 
@@ -945,9 +932,7 @@
 {
     std::vector<ServiceFlow*> serviceFlows = ssRecord->GetServiceFlows(schedulingType);
 
-    for (std::vector<ServiceFlow*>::iterator iter = serviceFlows.begin();
-         iter != serviceFlows.end();
-         ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         if (!ServiceBandwidthRequests(*iter,
                                       schedulingType,
@@ -1127,9 +1112,7 @@
     std::list<Ptr<PriorityUlJob>> priorityUlJobs;
 
     // for each request in the imermediate queue
-    for (std::list<Ptr<UlJob>>::const_iterator iter = m_uplinkJobs_inter.begin();
-         iter != m_uplinkJobs_inter.end();
-         ++iter)
+    for (auto iter = m_uplinkJobs_inter.begin(); iter != m_uplinkJobs_inter.end(); ++iter)
     {
         Ptr<UlJob> job = *iter;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/bs-uplink-scheduler-rtps.cc ns-3.40/src/wimax/model/bs-uplink-scheduler-rtps.cc
--- ns-3.39/src/wimax/model/bs-uplink-scheduler-rtps.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/bs-uplink-scheduler-rtps.cc	2023-09-27 13:30:37.930839800 -0700
@@ -183,8 +183,7 @@
     std::vector<SSRecord*>* ssRecords = GetBs()->GetSSManager()->GetSSRecords();
     NS_LOG_INFO("UL Scheduler start, availableSymbols = " << availableSymbols);
 
-    for (std::vector<SSRecord*>::iterator iter = ssRecords->begin(); iter != ssRecords->end();
-         ++iter)
+    for (auto iter = ssRecords->begin(); iter != ssRecords->end(); ++iter)
     {
         SSRecord* ssRecord = *iter;
         if (ssRecord->GetIsBroadcastSS())
@@ -305,8 +304,7 @@
     // UL Scheduler for nrtPS and BE flows
     if (availableSymbols)
     {
-        for (std::vector<SSRecord*>::iterator iter = ssRecords->begin(); iter != ssRecords->end();
-             ++iter)
+        for (auto iter = ssRecords->begin(); iter != ssRecords->end(); ++iter)
         {
             SSRecord* ssRecord = *iter;
             if (ssRecord->GetIsBroadcastSS())
@@ -371,9 +369,7 @@
     uint8_t uiuc = ulMapIe.GetUiuc(); // SS's burst profile
     std::vector<ServiceFlow*> serviceFlows = ssRecord->GetServiceFlows(schedulingType);
 
-    for (std::vector<ServiceFlow*>::iterator iter = serviceFlows.begin();
-         iter != serviceFlows.end();
-         ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         ServiceFlow* serviceFlow = *iter;
 
@@ -458,9 +454,7 @@
 {
     std::vector<ServiceFlow*> serviceFlows = ssRecord->GetServiceFlows(schedulingType);
 
-    for (std::vector<ServiceFlow*>::iterator iter = serviceFlows.begin();
-         iter != serviceFlows.end();
-         ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         if (!ServiceBandwidthRequests(*iter,
                                       schedulingType,
@@ -550,8 +544,7 @@
     Cid cid;
     std::vector<SSRecord*>* ssRecords = GetBs()->GetSSManager()->GetSSRecords();
 
-    for (std::vector<SSRecord*>::iterator iter = ssRecords->begin(); iter != ssRecords->end();
-         ++iter)
+    for (auto iter = ssRecords->begin(); iter != ssRecords->end(); ++iter)
     {
         SSRecord* ssRecord = *iter;
         if (ssRecord->GetIsBroadcastSS())
@@ -571,9 +564,7 @@
 
             std::vector<ServiceFlow*> serviceFlows =
                 ssRecord->GetServiceFlows(ServiceFlow::SF_TYPE_RTPS);
-            for (std::vector<ServiceFlow*>::iterator iter2 = serviceFlows.begin();
-                 iter2 != serviceFlows.end();
-                 ++iter2)
+            for (auto iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
             {
                 record_[nbAllocation] = (*iter2)->GetRecord();
                 uint32_t requiredBandwidth = record_[nbAllocation]->GetRequestedBandwidth() -
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/bs-uplink-scheduler-simple.cc ns-3.40/src/wimax/model/bs-uplink-scheduler-simple.cc
--- ns-3.39/src/wimax/model/bs-uplink-scheduler-simple.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/bs-uplink-scheduler-simple.cc	2023-09-27 13:30:37.930839800 -0700
@@ -182,8 +182,7 @@
     AllocateInitialRangingInterval(symbolsToAllocation, availableSymbols);
 
     std::vector<SSRecord*>* ssRecords = GetBs()->GetSSManager()->GetSSRecords();
-    for (std::vector<SSRecord*>::iterator iter = ssRecords->begin(); iter != ssRecords->end();
-         ++iter)
+    for (auto iter = ssRecords->begin(); iter != ssRecords->end(); ++iter)
     {
         SSRecord* ssRecord = *iter;
 
@@ -350,9 +349,7 @@
     uint8_t uiuc = ulMapIe.GetUiuc(); // SS's burst profile
     std::vector<ServiceFlow*> serviceFlows = ssRecord->GetServiceFlows(schedulingType);
 
-    for (std::vector<ServiceFlow*>::iterator iter = serviceFlows.begin();
-         iter != serviceFlows.end();
-         ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         ServiceFlow* serviceFlow = *iter;
 
@@ -423,9 +420,7 @@
 {
     std::vector<ServiceFlow*> serviceFlows = ssRecord->GetServiceFlows(schedulingType);
 
-    for (std::vector<ServiceFlow*>::iterator iter = serviceFlows.begin();
-         iter != serviceFlows.end();
-         ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         if (!ServiceBandwidthRequests(*iter,
                                       schedulingType,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/burst-profile-manager.cc ns-3.40/src/wimax/model/burst-profile-manager.cc
--- ns-3.39/src/wimax/model/burst-profile-manager.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/burst-profile-manager.cc	2023-09-27 13:30:37.930839800 -0700
@@ -76,9 +76,7 @@
     {
         std::vector<OfdmDlBurstProfile> dlBurstProfiles =
             m_device->GetCurrentDcd().GetDlBurstProfiles();
-        for (std::vector<OfdmDlBurstProfile>::iterator iter = dlBurstProfiles.begin();
-             iter != dlBurstProfiles.end();
-             ++iter)
+        for (auto iter = dlBurstProfiles.begin(); iter != dlBurstProfiles.end(); ++iter)
         {
             if (iter->GetDiuc() == iuc)
             {
@@ -90,9 +88,7 @@
     {
         std::vector<OfdmUlBurstProfile> ulBurstProfiles =
             m_device->GetCurrentUcd().GetUlBurstProfiles();
-        for (std::vector<OfdmUlBurstProfile>::iterator iter = ulBurstProfiles.begin();
-             iter != ulBurstProfiles.end();
-             ++iter)
+        for (auto iter = ulBurstProfiles.begin(); iter != ulBurstProfiles.end(); ++iter)
         {
             if (iter->GetUiuc() == iuc)
             {
@@ -115,9 +111,7 @@
     {
         std::vector<OfdmDlBurstProfile> dlBurstProfiles =
             m_device->GetCurrentDcd().GetDlBurstProfiles();
-        for (std::vector<OfdmDlBurstProfile>::iterator iter = dlBurstProfiles.begin();
-             iter != dlBurstProfiles.end();
-             ++iter)
+        for (auto iter = dlBurstProfiles.begin(); iter != dlBurstProfiles.end(); ++iter)
         {
             if (iter->GetFecCodeType() == modulationType)
             {
@@ -129,9 +123,7 @@
     {
         std::vector<OfdmUlBurstProfile> ulBurstProfiles =
             m_device->GetCurrentUcd().GetUlBurstProfiles();
-        for (std::vector<OfdmUlBurstProfile>::iterator iter = ulBurstProfiles.begin();
-             iter != ulBurstProfiles.end();
-             ++iter)
+        for (auto iter = ulBurstProfiles.begin(); iter != ulBurstProfiles.end(); ++iter)
         {
             if (iter->GetFecCodeType() == modulationType)
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/connection-manager.cc ns-3.40/src/wimax/model/connection-manager.cc
--- ns-3.39/src/wimax/model/connection-manager.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/connection-manager.cc	2023-09-27 13:30:37.930839800 -0700
@@ -128,9 +128,7 @@
 Ptr<WimaxConnection>
 ConnectionManager::GetConnection(Cid cid)
 {
-    std::vector<Ptr<WimaxConnection>>::const_iterator iter;
-
-    for (iter = m_basicConnections.begin(); iter != m_basicConnections.end(); ++iter)
+    for (auto iter = m_basicConnections.begin(); iter != m_basicConnections.end(); ++iter)
     {
         if ((*iter)->GetCid() == cid)
         {
@@ -138,7 +136,7 @@
         }
     }
 
-    for (iter = m_primaryConnections.begin(); iter != m_primaryConnections.end(); ++iter)
+    for (auto iter = m_primaryConnections.begin(); iter != m_primaryConnections.end(); ++iter)
     {
         if ((*iter)->GetCid() == cid)
         {
@@ -146,7 +144,7 @@
         }
     }
 
-    for (iter = m_transportConnections.begin(); iter != m_transportConnections.end(); ++iter)
+    for (auto iter = m_transportConnections.begin(); iter != m_transportConnections.end(); ++iter)
     {
         if ((*iter)->GetCid() == cid)
         {
@@ -189,27 +187,21 @@
     switch (type)
     {
     case Cid::BASIC: {
-        for (std::vector<Ptr<WimaxConnection>>::const_iterator iter = m_basicConnections.begin();
-             iter != m_basicConnections.end();
-             ++iter)
+        for (auto iter = m_basicConnections.begin(); iter != m_basicConnections.end(); ++iter)
         {
             nrPackets += (*iter)->GetQueue()->GetSize();
         }
         break;
     }
     case Cid::PRIMARY: {
-        for (std::vector<Ptr<WimaxConnection>>::const_iterator iter = m_primaryConnections.begin();
-             iter != m_primaryConnections.end();
-             ++iter)
+        for (auto iter = m_primaryConnections.begin(); iter != m_primaryConnections.end(); ++iter)
         {
             nrPackets += (*iter)->GetQueue()->GetSize();
         }
         break;
     }
     case Cid::TRANSPORT: {
-        for (std::vector<Ptr<WimaxConnection>>::const_iterator iter =
-                 m_transportConnections.begin();
-             iter != m_transportConnections.end();
+        for (auto iter = m_transportConnections.begin(); iter != m_transportConnections.end();
              ++iter)
         {
             if (schedulingType == ServiceFlow::SF_TYPE_ALL ||
@@ -231,8 +223,7 @@
 bool
 ConnectionManager::HasPackets() const
 {
-    std::vector<Ptr<WimaxConnection>>::const_iterator iter;
-    for (iter = m_basicConnections.begin(); iter != m_basicConnections.end(); ++iter)
+    for (auto iter = m_basicConnections.begin(); iter != m_basicConnections.end(); ++iter)
     {
         if ((*iter)->HasPackets())
         {
@@ -240,7 +231,7 @@
         }
     }
 
-    for (iter = m_primaryConnections.begin(); iter != m_primaryConnections.end(); ++iter)
+    for (auto iter = m_primaryConnections.begin(); iter != m_primaryConnections.end(); ++iter)
     {
         if ((*iter)->HasPackets())
         {
@@ -248,7 +239,7 @@
         }
     }
 
-    for (iter = m_transportConnections.begin(); iter != m_transportConnections.end(); ++iter)
+    for (auto iter = m_transportConnections.begin(); iter != m_transportConnections.end(); ++iter)
     {
         if ((*iter)->HasPackets())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/cs-parameters.cc ns-3.40/src/wimax/model/cs-parameters.cc
--- ns-3.39/src/wimax/model/cs-parameters.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/cs-parameters.cc	2023-09-27 13:30:37.930839800 -0700
@@ -37,7 +37,7 @@
     NS_ASSERT_MSG(tlv.GetType() == SfVectorTlvValue::IPV4_CS_Parameters, "Invalid TLV");
     CsParamVectorTlvValue* param = ((CsParamVectorTlvValue*)(tlv.PeekValue()));
 
-    for (std::vector<Tlv*>::const_iterator iter = param->Begin(); iter != param->End(); ++iter)
+    for (auto iter = param->Begin(); iter != param->End(); ++iter)
     {
         switch ((*iter)->GetType())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/ipcs-classifier-record.cc ns-3.40/src/wimax/model/ipcs-classifier-record.cc
--- ns-3.39/src/wimax/model/ipcs-classifier-record.cc	2023-07-05 14:23:48.133428300 -0700
+++ ns-3.40/src/wimax/model/ipcs-classifier-record.cc	2023-09-27 13:30:37.930839800 -0700
@@ -62,7 +62,7 @@
     m_tosHigh = 0;
     m_tosMask = 0;
     m_cid = 0;
-    for (std::vector<Tlv*>::const_iterator iter = rules->Begin(); iter != rules->End(); ++iter)
+    for (auto iter = rules->Begin(); iter != rules->End(); ++iter)
     {
         switch ((*iter)->GetType())
         {
@@ -75,49 +75,40 @@
             break;
         }
         case ClassificationRuleVectorTlvValue::Protocol: {
-            ProtocolTlvValue* list = (ProtocolTlvValue*)(*iter)->PeekValue();
-            for (std::vector<uint8_t>::const_iterator iter2 = list->Begin(); iter2 != list->End();
-                 ++iter2)
+            auto list = (ProtocolTlvValue*)(*iter)->PeekValue();
+            for (auto iter2 = list->Begin(); iter2 != list->End(); ++iter2)
             {
                 AddProtocol(*iter2);
             }
             break;
         }
         case ClassificationRuleVectorTlvValue::IP_src: {
-            Ipv4AddressTlvValue* list = (Ipv4AddressTlvValue*)(*iter)->PeekValue();
-            for (std::vector<Ipv4AddressTlvValue::Ipv4Addr>::const_iterator iter2 = list->Begin();
-                 iter2 != list->End();
-                 ++iter2)
+            auto list = (Ipv4AddressTlvValue*)(*iter)->PeekValue();
+            for (auto iter2 = list->Begin(); iter2 != list->End(); ++iter2)
             {
                 AddSrcAddr((*iter2).Address, (*iter2).Mask);
             }
             break;
         }
         case ClassificationRuleVectorTlvValue::IP_dst: {
-            Ipv4AddressTlvValue* list = (Ipv4AddressTlvValue*)(*iter)->PeekValue();
-            for (std::vector<Ipv4AddressTlvValue::Ipv4Addr>::const_iterator iter2 = list->Begin();
-                 iter2 != list->End();
-                 ++iter2)
+            auto list = (Ipv4AddressTlvValue*)(*iter)->PeekValue();
+            for (auto iter2 = list->Begin(); iter2 != list->End(); ++iter2)
             {
                 AddDstAddr((*iter2).Address, (*iter2).Mask);
             }
             break;
         }
         case ClassificationRuleVectorTlvValue::Port_src: {
-            PortRangeTlvValue* list = (PortRangeTlvValue*)(*iter)->PeekValue();
-            for (std::vector<PortRangeTlvValue::PortRange>::const_iterator iter2 = list->Begin();
-                 iter2 != list->End();
-                 ++iter2)
+            auto list = (PortRangeTlvValue*)(*iter)->PeekValue();
+            for (auto iter2 = list->Begin(); iter2 != list->End(); ++iter2)
             {
                 AddSrcPortRange((*iter2).PortLow, (*iter2).PortHigh);
             }
             break;
         }
         case ClassificationRuleVectorTlvValue::Port_dst: {
-            PortRangeTlvValue* list = (PortRangeTlvValue*)(*iter)->PeekValue();
-            for (std::vector<PortRangeTlvValue::PortRange>::const_iterator iter2 = list->Begin();
-                 iter2 != list->End();
-                 ++iter2)
+            auto list = (PortRangeTlvValue*)(*iter)->PeekValue();
+            for (auto iter2 = list->Begin(); iter2 != list->End(); ++iter2)
             {
                 AddDstPortRange((*iter2).PortLow, (*iter2).PortHigh);
             }
@@ -236,8 +227,7 @@
 bool
 IpcsClassifierRecord::CheckMatchSrcAddr(Ipv4Address srcAddress) const
 {
-    for (std::vector<Ipv4Addr>::const_iterator iter = m_srcAddr.begin(); iter != m_srcAddr.end();
-         ++iter)
+    for (auto iter = m_srcAddr.begin(); iter != m_srcAddr.end(); ++iter)
     {
         NS_LOG_INFO("src addr check match: pkt=" << srcAddress << " cls=" << (*iter).Address << "/"
                                                  << (*iter).Mask);
@@ -253,8 +243,7 @@
 bool
 IpcsClassifierRecord::CheckMatchDstAddr(Ipv4Address dstAddress) const
 {
-    for (std::vector<Ipv4Addr>::const_iterator iter = m_dstAddr.begin(); iter != m_dstAddr.end();
-         ++iter)
+    for (auto iter = m_dstAddr.begin(); iter != m_dstAddr.end(); ++iter)
     {
         NS_LOG_INFO("dst addr check match: pkt=" << dstAddress << " cls=" << (*iter).Address << "/"
                                                  << (*iter).Mask);
@@ -270,9 +259,7 @@
 bool
 IpcsClassifierRecord::CheckMatchSrcPort(uint16_t port) const
 {
-    for (std::vector<PortRange>::const_iterator iter = m_srcPortRange.begin();
-         iter != m_srcPortRange.end();
-         ++iter)
+    for (auto iter = m_srcPortRange.begin(); iter != m_srcPortRange.end(); ++iter)
     {
         NS_LOG_INFO("src port check match: pkt=" << port << " cls= [" << (*iter).PortLow << " TO "
                                                  << (*iter).PortHigh << "]");
@@ -288,9 +275,7 @@
 bool
 IpcsClassifierRecord::CheckMatchDstPort(uint16_t port) const
 {
-    for (std::vector<PortRange>::const_iterator iter = m_dstPortRange.begin();
-         iter != m_dstPortRange.end();
-         ++iter)
+    for (auto iter = m_dstPortRange.begin(); iter != m_dstPortRange.end(); ++iter)
     {
         NS_LOG_INFO("dst port check match: pkt=" << port << " cls= [" << (*iter).PortLow << " TO "
                                                  << (*iter).PortHigh << "]");
@@ -306,8 +291,7 @@
 bool
 IpcsClassifierRecord::CheckMatchProtocol(uint8_t proto) const
 {
-    for (std::vector<uint8_t>::const_iterator iter = m_protocol.begin(); iter != m_protocol.end();
-         ++iter)
+    for (auto iter = m_protocol.begin(); iter != m_protocol.end(); ++iter)
     {
         NS_LOG_INFO("proto check match: pkt=" << (uint16_t)proto << " cls=" << (uint16_t)proto);
         if (proto == (*iter))
@@ -334,38 +318,31 @@
 IpcsClassifierRecord::ToTlv() const
 {
     Ipv4AddressTlvValue ipv4AddrValSrc;
-    for (std::vector<Ipv4Addr>::const_iterator iter = m_srcAddr.begin(); iter != m_srcAddr.end();
-         ++iter)
+    for (auto iter = m_srcAddr.begin(); iter != m_srcAddr.end(); ++iter)
     {
         ipv4AddrValSrc.Add((*iter).Address, (*iter).Mask);
     }
 
     Ipv4AddressTlvValue ipv4AddrValDst;
-    for (std::vector<Ipv4Addr>::const_iterator iter = m_dstAddr.begin(); iter != m_dstAddr.end();
-         ++iter)
+    for (auto iter = m_dstAddr.begin(); iter != m_dstAddr.end(); ++iter)
     {
         ipv4AddrValDst.Add((*iter).Address, (*iter).Mask);
     }
 
     ProtocolTlvValue protoVal;
-    for (std::vector<uint8_t>::const_iterator iter = m_protocol.begin(); iter != m_protocol.end();
-         ++iter)
+    for (auto iter = m_protocol.begin(); iter != m_protocol.end(); ++iter)
     {
         protoVal.Add((*iter));
     }
 
     PortRangeTlvValue portValueSrc;
-    for (std::vector<PortRange>::const_iterator iter = m_srcPortRange.begin();
-         iter != m_srcPortRange.end();
-         ++iter)
+    for (auto iter = m_srcPortRange.begin(); iter != m_srcPortRange.end(); ++iter)
     {
         portValueSrc.Add((*iter).PortLow, (*iter).PortHigh);
     }
 
     PortRangeTlvValue portValueDst;
-    for (std::vector<PortRange>::const_iterator iter = m_dstPortRange.begin();
-         iter != m_dstPortRange.end();
-         ++iter)
+    for (auto iter = m_dstPortRange.begin(); iter != m_dstPortRange.end(); ++iter)
     {
         portValueDst.Add((*iter).PortLow, (*iter).PortHigh);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/service-flow.cc ns-3.40/src/wimax/model/service-flow.cc
--- ns-3.39/src/wimax/model/service-flow.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/service-flow.cc	2023-09-27 13:30:37.930839800 -0700
@@ -73,7 +73,7 @@
 {
     InitValues();
     m_connection = nullptr;
-    m_isEnabled = 0;
+    m_isEnabled = false;
     m_record = new ServiceFlowRecord();
     NS_ASSERT_MSG(tlv.GetType() == Tlv::UPLINK_SERVICE_FLOW ||
                       tlv.GetType() == Tlv::DOWNLINK_SERVICE_FLOW,
@@ -91,7 +91,7 @@
         m_direction = SF_DIRECTION_DOWN;
     }
 
-    for (std::vector<Tlv*>::const_iterator iter = param->Begin(); iter != param->End(); ++iter)
+    for (auto iter = param->Begin(); iter != param->End(); ++iter)
     {
         switch ((*iter)->GetType())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/service-flow-manager.cc ns-3.40/src/wimax/model/service-flow-manager.cc
--- ns-3.39/src/wimax/model/service-flow-manager.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/service-flow-manager.cc	2023-09-27 13:30:37.930839800 -0700
@@ -68,9 +68,7 @@
 void
 ServiceFlowManager::DoDispose()
 {
-    for (std::vector<ServiceFlow*>::iterator iter = m_serviceFlows->begin();
-         iter != m_serviceFlows->end();
-         ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         delete (*iter);
     }
@@ -92,9 +90,7 @@
                                uint8_t proto,
                                ServiceFlow::Direction dir) const
 {
-    for (std::vector<ServiceFlow*>::iterator iter = m_serviceFlows->begin();
-         iter != m_serviceFlows->end();
-         ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         if ((*iter)->GetDirection() == dir)
         {
@@ -110,9 +106,7 @@
 ServiceFlow*
 ServiceFlowManager::GetServiceFlow(uint32_t sfid) const
 {
-    for (std::vector<ServiceFlow*>::iterator iter = m_serviceFlows->begin();
-         iter != m_serviceFlows->end();
-         ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         if ((*iter)->GetSfid() == sfid)
         {
@@ -127,9 +121,7 @@
 ServiceFlow*
 ServiceFlowManager::GetServiceFlow(Cid cid) const
 {
-    for (std::vector<ServiceFlow*>::iterator iter = m_serviceFlows->begin();
-         iter != m_serviceFlows->end();
-         ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         if ((*iter)->GetCid() == cid.GetIdentifier())
         {
@@ -145,9 +137,7 @@
 ServiceFlowManager::GetServiceFlows(ServiceFlow::SchedulingType schedulingType) const
 {
     std::vector<ServiceFlow*> tmpServiceFlows;
-    for (std::vector<ServiceFlow*>::iterator iter = m_serviceFlows->begin();
-         iter != m_serviceFlows->end();
-         ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         if (((*iter)->GetSchedulingType() == schedulingType) ||
             (schedulingType == ServiceFlow::SF_TYPE_ALL))
@@ -173,9 +163,7 @@
 bool
 ServiceFlowManager::AreServiceFlowsAllocated(std::vector<ServiceFlow*> serviceFlowVector)
 {
-    for (std::vector<ServiceFlow*>::const_iterator iter = serviceFlowVector.begin();
-         iter != serviceFlowVector.end();
-         ++iter)
+    for (auto iter = serviceFlowVector.begin(); iter != serviceFlowVector.end(); ++iter)
     {
         if (!(*iter)->GetIsEnabled())
         {
@@ -188,8 +176,7 @@
 ServiceFlow*
 ServiceFlowManager::GetNextServiceFlowToAllocate()
 {
-    std::vector<ServiceFlow*>::iterator iter;
-    for (iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         if (!(*iter)->GetIsEnabled())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/simple-ofdm-send-param.cc ns-3.40/src/wimax/model/simple-ofdm-send-param.cc
--- ns-3.39/src/wimax/model/simple-ofdm-send-param.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/simple-ofdm-send-param.cc	2023-09-27 13:30:37.930839800 -0700
@@ -29,7 +29,7 @@
 {
     // m_fecBlock = 0;
     m_burstSize = 0;
-    m_isFirstBlock = 0;
+    m_isFirstBlock = false;
     m_frequency = 0;
     m_modulationType = WimaxPhy::MODULATION_TYPE_QPSK_12;
     m_direction = 0;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/simple-ofdm-wimax-channel.cc ns-3.40/src/wimax/model/simple-ofdm-wimax-channel.cc
--- ns-3.39/src/wimax/model/simple-ofdm-wimax-channel.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/simple-ofdm-wimax-channel.cc	2023-09-27 13:30:37.930839800 -0700
@@ -128,9 +128,7 @@
 SimpleOfdmWimaxChannel::DoGetDevice(std::size_t index) const
 {
     std::size_t j = 0;
-    for (std::list<Ptr<SimpleOfdmWimaxPhy>>::const_iterator iter = m_phyList.begin();
-         iter != m_phyList.end();
-         ++iter)
+    for (auto iter = m_phyList.begin(); iter != m_phyList.end(); ++iter)
     {
         if (j == index)
         {
@@ -160,9 +158,7 @@
     Ptr<MobilityModel> receiverMobility = nullptr;
     senderMobility = phy->GetDevice()->GetNode()->GetObject<MobilityModel>();
     SimpleOfdmSendParam* param;
-    for (std::list<Ptr<SimpleOfdmWimaxPhy>>::iterator iter = m_phyList.begin();
-         iter != m_phyList.end();
-         ++iter)
+    for (auto iter = m_phyList.begin(); iter != m_phyList.end(); ++iter)
     {
         Time delay = Seconds(0);
         if (phy != *iter)
@@ -220,8 +216,7 @@
 SimpleOfdmWimaxChannel::AssignStreams(int64_t stream)
 {
     int64_t currentStream = stream;
-    typedef std::list<Ptr<SimpleOfdmWimaxPhy>> PhyList;
-    for (PhyList::const_iterator i = m_phyList.begin(); i != m_phyList.end(); i++)
+    for (auto i = m_phyList.begin(); i != m_phyList.end(); i++)
     {
         Ptr<SimpleOfdmWimaxPhy> simpleOfdm = (*i);
         currentStream += simpleOfdm->AssignStreams(currentStream);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/simple-ofdm-wimax-phy.cc ns-3.40/src/wimax/model/simple-ofdm-wimax-phy.cc
--- ns-3.39/src/wimax/model/simple-ofdm-wimax-phy.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/simple-ofdm-wimax-phy.cc	2023-09-27 13:30:37.930839800 -0700
@@ -273,7 +273,7 @@
 void
 SimpleOfdmWimaxPhy::Send(SendParams* params)
 {
-    OfdmSendParams* o_params = dynamic_cast<OfdmSendParams*>(params);
+    auto o_params = dynamic_cast<OfdmSendParams*>(params);
     NS_ASSERT(o_params != nullptr);
     Send(o_params->GetBurst(),
          (WimaxPhy::ModulationType)o_params->GetModulationType(),
@@ -309,7 +309,7 @@
                                            uint8_t direction)
 {
     SetState(PHY_STATE_TX);
-    bool isLastFecBlock = 0;
+    bool isLastFecBlock = false;
     if (isFirstBlock)
     {
         m_blockTime = GetBlockTransmissionTime(modulationType);
@@ -496,20 +496,20 @@
 Bvec
 SimpleOfdmWimaxPhy::ConvertBurstToBits(Ptr<const PacketBurst> burst)
 {
-    Bvec buffer(burst->GetSize() * 8, 0);
+    Bvec buffer(burst->GetSize() * 8, false);
 
     std::list<Ptr<Packet>> packets = burst->GetPackets();
 
     uint32_t j = 0;
-    for (std::list<Ptr<Packet>>::iterator iter = packets.begin(); iter != packets.end(); ++iter)
+    for (auto iter = packets.begin(); iter != packets.end(); ++iter)
     {
         Ptr<Packet> packet = *iter;
-        uint8_t* pstart = (uint8_t*)std::malloc(packet->GetSize());
+        auto pstart = (uint8_t*)std::malloc(packet->GetSize());
         std::memset(pstart, 0, packet->GetSize());
         packet->CopyData(pstart, packet->GetSize());
         Bvec temp(8);
-        temp.resize(0, 0);
-        temp.resize(8, 0);
+        temp.resize(0, false);
+        temp.resize(8, false);
         for (uint32_t i = 0; i < packet->GetSize(); i++)
         {
             for (uint8_t l = 0; l < 8; l++)
@@ -593,7 +593,7 @@
         if (j == 1 && m_paddingBits > 0) // last block can be smaller than block size
         {
             fecBlock = Bvec(buffer.begin() + i, buffer.end());
-            fecBlock.resize(m_blockSize, 0);
+            fecBlock.resize(m_blockSize, false);
         }
         else
         {
@@ -677,7 +677,7 @@
     double fecCode = 0;
     GetModulationFecParams(modulationType, bitsPerSymbol, fecCode);
     double symbolsPerSecond = 1 / GetSymbolDuration().GetSeconds();
-    uint16_t bitsTransmittedPerSymbol = (uint16_t)(bitsPerSymbol * GetNrCarriers() * fecCode);
+    auto bitsTransmittedPerSymbol = (uint16_t)(bitsPerSymbol * GetNrCarriers() * fecCode);
     // 96, 192, 288, 384, 576, 767 and 864 bits per symbol for the seven modulations, respectively
 
     return (uint32_t)symbolsPerSecond * bitsTransmittedPerSymbol;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/simple-ofdm-wimax-phy.h ns-3.40/src/wimax/model/simple-ofdm-wimax-phy.h
--- ns-3.39/src/wimax/model/simple-ofdm-wimax-phy.h	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/simple-ofdm-wimax-phy.h	2023-09-27 13:30:37.930839800 -0700
@@ -22,6 +22,7 @@
 #define SIMPLE_OFDM_WIMAX_PHY_H
 
 #include "bvec.h"
+#include "snr-to-block-error-rate-manager.h"
 #include "wimax-connection.h"
 #include "wimax-phy.h"
 
@@ -29,7 +30,6 @@
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
 #include "ns3/random-variable-stream.h"
-#include "ns3/snr-to-block-error-rate-manager.h"
 
 #include <list>
 #include <stdint.h>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/snr-to-block-error-rate-manager.cc ns-3.40/src/wimax/model/snr-to-block-error-rate-manager.cc
--- ns-3.39/src/wimax/model/snr-to-block-error-rate-manager.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/snr-to-block-error-rate-manager.cc	2023-09-27 13:30:37.930839800 -0700
@@ -18,13 +18,13 @@
  *                              <amine.ismail@udcast.com>
  */
 
-#include "ns3/snr-to-block-error-rate-manager.h"
+#include "snr-to-block-error-rate-manager.h"
 
 #include "default-traces.h"
+#include "snr-to-block-error-rate-record.h"
 
 #include "ns3/assert.h"
 #include "ns3/log.h"
-#include "ns3/snr-to-block-error-rate-record.h"
 
 #include <cstring>
 #include <fstream>
@@ -59,9 +59,7 @@
 {
     for (int i = 0; i < 7; i++)
     {
-        for (std::vector<SNRToBlockErrorRateRecord*>::iterator iter =
-                 m_recordModulation[i]->begin();
-             iter != m_recordModulation[i]->end();
+        for (auto iter = m_recordModulation[i]->begin(); iter != m_recordModulation[i]->end();
              ++iter)
         {
             if (*iter)
@@ -107,12 +105,12 @@
         while (traceFile.good())
         {
             traceFile >> snrValue >> bitErrorRate >> burstErrorRate >> sigma2 >> I1 >> I2;
-            SNRToBlockErrorRateRecord* record = new SNRToBlockErrorRateRecord(snrValue,
-                                                                              bitErrorRate,
-                                                                              burstErrorRate,
-                                                                              sigma2,
-                                                                              I1,
-                                                                              I2);
+            auto record = new SNRToBlockErrorRateRecord(snrValue,
+                                                        bitErrorRate,
+                                                        burstErrorRate,
+                                                        sigma2,
+                                                        I1,
+                                                        I2);
             m_recordModulation[i]->push_back(record);
         }
         traceFile.close();
@@ -138,7 +136,7 @@
         sigma2 = modulation0[3][j];
         I1 = modulation0[4][j];
         I2 = modulation0[5][j];
-        SNRToBlockErrorRateRecord* record =
+        auto record =
             new SNRToBlockErrorRateRecord(snrValue, bitErrorRate, burstErrorRate, sigma2, I1, I2);
         m_recordModulation[0]->push_back(record);
     }
@@ -150,7 +148,7 @@
         sigma2 = modulation1[3][j];
         I1 = modulation1[4][j];
         I2 = modulation1[5][j];
-        SNRToBlockErrorRateRecord* record =
+        auto record =
             new SNRToBlockErrorRateRecord(snrValue, bitErrorRate, burstErrorRate, sigma2, I1, I2);
         m_recordModulation[1]->push_back(record);
     }
@@ -162,7 +160,7 @@
         sigma2 = modulation2[3][j];
         I1 = modulation2[4][j];
         I2 = modulation2[5][j];
-        SNRToBlockErrorRateRecord* record =
+        auto record =
             new SNRToBlockErrorRateRecord(snrValue, bitErrorRate, burstErrorRate, sigma2, I1, I2);
         m_recordModulation[2]->push_back(record);
     }
@@ -174,7 +172,7 @@
         sigma2 = modulation3[3][j];
         I1 = modulation3[4][j];
         I2 = modulation3[5][j];
-        SNRToBlockErrorRateRecord* record =
+        auto record =
             new SNRToBlockErrorRateRecord(snrValue, bitErrorRate, burstErrorRate, sigma2, I1, I2);
         m_recordModulation[3]->push_back(record);
     }
@@ -186,7 +184,7 @@
         sigma2 = modulation4[3][j];
         I1 = modulation4[4][j];
         I2 = modulation4[5][j];
-        SNRToBlockErrorRateRecord* record =
+        auto record =
             new SNRToBlockErrorRateRecord(snrValue, bitErrorRate, burstErrorRate, sigma2, I1, I2);
         m_recordModulation[4]->push_back(record);
     }
@@ -198,7 +196,7 @@
         sigma2 = modulation5[3][j];
         I1 = modulation5[4][j];
         I2 = modulation5[5][j];
-        SNRToBlockErrorRateRecord* record =
+        auto record =
             new SNRToBlockErrorRateRecord(snrValue, bitErrorRate, burstErrorRate, sigma2, I1, I2);
         m_recordModulation[5]->push_back(record);
     }
@@ -210,7 +208,7 @@
         sigma2 = modulation6[3][j];
         I1 = modulation6[4][j];
         I2 = modulation6[5][j];
-        SNRToBlockErrorRateRecord* record =
+        auto record =
             new SNRToBlockErrorRateRecord(snrValue, bitErrorRate, burstErrorRate, sigma2, I1, I2);
         m_recordModulation[6]->push_back(record);
     }
@@ -246,12 +244,12 @@
         while (traceFile.good())
         {
             traceFile >> snrValue >> bitErrorRate >> burstErrorRate >> sigma2 >> I1 >> I2;
-            SNRToBlockErrorRateRecord* record = new SNRToBlockErrorRateRecord(snrValue,
-                                                                              bitErrorRate,
-                                                                              burstErrorRate,
-                                                                              sigma2,
-                                                                              I1,
-                                                                              I2);
+            auto record = new SNRToBlockErrorRateRecord(snrValue,
+                                                        bitErrorRate,
+                                                        burstErrorRate,
+                                                        sigma2,
+                                                        I1,
+                                                        I2);
 
             m_recordModulation[i]->push_back(record);
         }
@@ -349,8 +347,7 @@
     double I1 = coeff2 * (record->at(i - 1)->GetI1()) + coeff1 * (record->at(i)->GetI1());
     double I2 = coeff2 * (record->at(i - 1)->GetI2()) + coeff1 * (record->at(i)->GetI2());
 
-    SNRToBlockErrorRateRecord* SNRToBlockErrorRate =
-        new SNRToBlockErrorRateRecord(SNR, BER, BlcER, sigma2, I1, I2);
+    auto SNRToBlockErrorRate = new SNRToBlockErrorRateRecord(SNR, BER, BlcER, sigma2, I1, I2);
     return SNRToBlockErrorRate;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/snr-to-block-error-rate-manager.h ns-3.40/src/wimax/model/snr-to-block-error-rate-manager.h
--- ns-3.39/src/wimax/model/snr-to-block-error-rate-manager.h	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/snr-to-block-error-rate-manager.h	2023-09-27 13:30:37.930839800 -0700
@@ -21,8 +21,9 @@
 #ifndef SNR_TO_BLOCK_ERROR_RATE_MANAGER_H
 #define SNR_TO_BLOCK_ERROR_RATE_MANAGER_H
 
+#include "snr-to-block-error-rate-record.h"
+
 #include "ns3/ptr.h"
-#include "ns3/snr-to-block-error-rate-record.h"
 
 #include <vector>
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/snr-to-block-error-rate-record.cc ns-3.40/src/wimax/model/snr-to-block-error-rate-record.cc
--- ns-3.39/src/wimax/model/snr-to-block-error-rate-record.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/snr-to-block-error-rate-record.cc	2023-09-27 13:30:37.930839800 -0700
@@ -18,7 +18,7 @@
  *                              <amine.ismail@udcast.com>
  */
 
-#include "ns3/snr-to-block-error-rate-record.h"
+#include "snr-to-block-error-rate-record.h"
 
 #include "ns3/assert.h"
 #include "ns3/simulator.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/ss-manager.cc ns-3.40/src/wimax/model/ss-manager.cc
--- ns-3.39/src/wimax/model/ss-manager.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/ss-manager.cc	2023-09-27 13:30:37.930839800 -0700
@@ -48,8 +48,7 @@
 
 SSManager::~SSManager()
 {
-    for (std::vector<SSRecord*>::iterator iter = m_ssRecords->begin(); iter != m_ssRecords->end();
-         ++iter)
+    for (auto iter = m_ssRecords->begin(); iter != m_ssRecords->end(); ++iter)
     {
         delete *iter;
     }
@@ -60,7 +59,7 @@
 SSRecord*
 SSManager::CreateSSRecord(const Mac48Address& macAddress)
 {
-    SSRecord* ssRecord = new SSRecord(macAddress);
+    auto ssRecord = new SSRecord(macAddress);
     m_ssRecords->push_back(ssRecord);
     return ssRecord;
 }
@@ -68,8 +67,7 @@
 SSRecord*
 SSManager::GetSSRecord(const Mac48Address& macAddress) const
 {
-    for (std::vector<SSRecord*>::iterator iter = m_ssRecords->begin(); iter != m_ssRecords->end();
-         ++iter)
+    for (auto iter = m_ssRecords->begin(); iter != m_ssRecords->end(); ++iter)
     {
         if ((*iter)->GetMacAddress() == macAddress)
         {
@@ -84,8 +82,7 @@
 SSRecord*
 SSManager::GetSSRecord(Cid cid) const
 {
-    for (std::vector<SSRecord*>::iterator iter1 = m_ssRecords->begin(); iter1 != m_ssRecords->end();
-         ++iter1)
+    for (auto iter1 = m_ssRecords->begin(); iter1 != m_ssRecords->end(); ++iter1)
     {
         SSRecord* ssRecord = *iter1;
         if (ssRecord->GetBasicCid() == cid || ssRecord->GetPrimaryCid() == cid)
@@ -95,7 +92,7 @@
         else
         {
             std::vector<ServiceFlow*> sf = ssRecord->GetServiceFlows(ServiceFlow::SF_TYPE_ALL);
-            for (std::vector<ServiceFlow*>::iterator iter2 = sf.begin(); iter2 != sf.end(); ++iter2)
+            for (auto iter2 = sf.begin(); iter2 != sf.end(); ++iter2)
             {
                 if ((*iter2)->GetConnection()->GetCid() == cid)
                 {
@@ -118,8 +115,7 @@
 bool
 SSManager::IsInRecord(const Mac48Address& macAddress) const
 {
-    for (std::vector<SSRecord*>::iterator iter = m_ssRecords->begin(); iter != m_ssRecords->end();
-         ++iter)
+    for (auto iter = m_ssRecords->begin(); iter != m_ssRecords->end(); ++iter)
     {
         if ((*iter)->GetMacAddress() == macAddress)
         {
@@ -140,8 +136,7 @@
 void
 SSManager::DeleteSSRecord(Cid cid)
 {
-    for (std::vector<SSRecord*>::iterator iter1 = m_ssRecords->begin(); iter1 != m_ssRecords->end();
-         ++iter1)
+    for (auto iter1 = m_ssRecords->begin(); iter1 != m_ssRecords->end(); ++iter1)
     {
         SSRecord* ssRecord = *iter1;
         if (ssRecord->GetBasicCid() == cid || ssRecord->GetPrimaryCid() == cid)
@@ -152,8 +147,7 @@
         else
         {
             std::vector<ServiceFlow*> sf = ssRecord->GetServiceFlows(ServiceFlow::SF_TYPE_ALL);
-            for (std::vector<ServiceFlow*>::const_iterator iter2 = sf.begin(); iter2 != sf.end();
-                 ++iter2)
+            for (auto iter2 = sf.begin(); iter2 != sf.end(); ++iter2)
             {
                 if ((*iter2)->GetConnection()->GetCid() == cid)
                 {
@@ -181,8 +175,7 @@
 SSManager::GetNRegisteredSSs() const
 {
     uint32_t nrSS = 0;
-    for (std::vector<SSRecord*>::iterator iter = m_ssRecords->begin(); iter != m_ssRecords->end();
-         ++iter)
+    for (auto iter = m_ssRecords->begin(); iter != m_ssRecords->end(); ++iter)
     {
         if ((*iter)->GetRangingStatus() == WimaxNetDevice::RANGING_STATUS_SUCCESS)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/ss-net-device.cc ns-3.40/src/wimax/model/ss-net-device.cc
--- ns-3.39/src/wimax/model/ss-net-device.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/ss-net-device.cc	2023-09-27 13:30:37.930839800 -0700
@@ -1089,9 +1089,7 @@
 
                     // DEFRAGMENTATION
                     NS_LOG_INFO("\t SS PACKET DEFRAGMENTATION" << std::endl);
-                    for (std::list<Ptr<const Packet>>::const_iterator iter = fragmentsQueue.begin();
-                         iter != fragmentsQueue.end();
-                         ++iter)
+                    for (auto iter = fragmentsQueue.begin(); iter != fragmentsQueue.end(); ++iter)
                     {
                         // Create the whole Packet
                         fullPacket->AddAtEnd(*iter);
@@ -1146,8 +1144,7 @@
     m_baseStationId = dlmap.GetBaseStationId();
     std::list<OfdmDlMapIe> dlMapElements = dlmap.GetDlMapElements();
 
-    for (std::list<OfdmDlMapIe>::iterator iter = dlMapElements.begin(); iter != dlMapElements.end();
-         ++iter)
+    for (auto iter = dlMapElements.begin(); iter != dlMapElements.end(); ++iter)
     {
         if (iter->GetDiuc() == OfdmDlBurstProfile::DIUC_END_OF_MAP)
         {
@@ -1180,8 +1177,7 @@
     std::list<OfdmUlMapIe> ulMapElements = ulmap.GetUlMapElements();
     m_linkManager->SetRangingIntervalFound(false);
 
-    for (std::list<OfdmUlMapIe>::iterator iter = ulMapElements.begin(); iter != ulMapElements.end();
-         ++iter)
+    for (auto iter = ulMapElements.begin(); iter != ulMapElements.end(); ++iter)
     {
         OfdmUlMapIe ulMapIe = *iter;
 
@@ -1282,9 +1278,7 @@
 
     std::vector<OfdmDlBurstProfile> dlBurstProfiles = dcd.GetDlBurstProfiles();
 
-    for (std::vector<OfdmDlBurstProfile>::iterator iter = dlBurstProfiles.begin();
-         iter != dlBurstProfiles.end();
-         ++iter)
+    for (auto iter = dlBurstProfiles.begin(); iter != dlBurstProfiles.end(); ++iter)
     {
         OfdmDlBurstProfile brstProfile = *iter;
 
@@ -1319,9 +1313,7 @@
 
     std::vector<OfdmUlBurstProfile> ulBurstProfiles = ucd.GetUlBurstProfiles();
 
-    for (std::vector<OfdmUlBurstProfile>::iterator iter = ulBurstProfiles.begin();
-         iter != ulBurstProfiles.end();
-         ++iter)
+    for (auto iter = ulBurstProfiles.begin(); iter != ulBurstProfiles.end(); ++iter)
     {
         OfdmUlBurstProfile brstProfile = *iter;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/ss-net-device.h ns-3.40/src/wimax/model/ss-net-device.h
--- ns-3.39/src/wimax/model/ss-net-device.h	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/ss-net-device.h	2023-09-27 13:30:37.930839800 -0700
@@ -23,12 +23,12 @@
 #define WIMAX_SS_NET_DEVICE_H
 
 #include "ipcs-classifier.h"
+#include "ss-service-flow-manager.h"
 #include "wimax-mac-header.h"
 #include "wimax-net-device.h"
 
 #include "ns3/event-id.h"
 #include "ns3/nstime.h"
-#include "ns3/ss-service-flow-manager.h"
 #include "ns3/uinteger.h"
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/ss-record.cc ns-3.40/src/wimax/model/ss-record.cc
--- ns-3.39/src/wimax/model/ss-record.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/ss-record.cc	2023-09-27 13:30:37.930839800 -0700
@@ -64,7 +64,7 @@
 
     m_serviceFlows = new std::vector<ServiceFlow*>();
     m_dsaRsp = DsaRsp();
-    m_broadcast = 0;
+    m_broadcast = false;
 }
 
 SSRecord::~SSRecord()
@@ -233,9 +233,7 @@
 SSRecord::GetServiceFlows(ServiceFlow::SchedulingType schedulingType) const
 {
     std::vector<ServiceFlow*> tmpServiceFlows;
-    for (std::vector<ServiceFlow*>::iterator iter = m_serviceFlows->begin();
-         iter != m_serviceFlows->end();
-         ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         if (((*iter)->GetSchedulingType() == schedulingType) ||
             (schedulingType == ServiceFlow::SF_TYPE_ALL))
@@ -261,9 +259,7 @@
 bool
 SSRecord::GetHasServiceFlowUgs() const
 {
-    for (std::vector<ServiceFlow*>::iterator iter = m_serviceFlows->begin();
-         iter != m_serviceFlows->end();
-         ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         if ((*iter)->GetSchedulingType() == ServiceFlow::SF_TYPE_UGS)
         {
@@ -276,9 +272,7 @@
 bool
 SSRecord::GetHasServiceFlowRtps() const
 {
-    for (std::vector<ServiceFlow*>::iterator iter = m_serviceFlows->begin();
-         iter != m_serviceFlows->end();
-         ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         if ((*iter)->GetSchedulingType() == ServiceFlow::SF_TYPE_RTPS)
         {
@@ -291,9 +285,7 @@
 bool
 SSRecord::GetHasServiceFlowNrtps() const
 {
-    for (std::vector<ServiceFlow*>::iterator iter = m_serviceFlows->begin();
-         iter != m_serviceFlows->end();
-         ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         if ((*iter)->GetSchedulingType() == ServiceFlow::SF_TYPE_NRTPS)
         {
@@ -306,9 +298,7 @@
 bool
 SSRecord::GetHasServiceFlowBe() const
 {
-    for (std::vector<ServiceFlow*>::iterator iter = m_serviceFlows->begin();
-         iter != m_serviceFlows->end();
-         ++iter)
+    for (auto iter = m_serviceFlows->begin(); iter != m_serviceFlows->end(); ++iter)
     {
         if ((*iter)->GetSchedulingType() == ServiceFlow::SF_TYPE_BE)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/ss-scheduler.cc ns-3.40/src/wimax/model/ss-scheduler.cc
--- ns-3.39/src/wimax/model/ss-scheduler.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/ss-scheduler.cc	2023-09-27 13:30:37.930839800 -0700
@@ -167,8 +167,6 @@
 SSScheduler::SelectConnection()
 {
     Time currentTime = Simulator::Now();
-    std::vector<ServiceFlow*>::const_iterator iter;
-    std::vector<ServiceFlow*> serviceFlows;
 
     NS_LOG_INFO("SS Scheduler: Selecting connection...");
     if (m_ss->GetInitialRangingConnection()->HasPackets())
@@ -187,8 +185,8 @@
         return m_ss->GetPrimaryConnection();
     }
 
-    serviceFlows = m_ss->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_UGS);
-    for (iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
+    auto serviceFlows = m_ss->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_UGS);
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         // making sure that this grant was actually intended for this UGS
 
@@ -206,7 +204,7 @@
      hence this function will never be called. */
 
     serviceFlows = m_ss->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_RTPS);
-    for (iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         if ((*iter)->HasPackets(MacHeaderType::HEADER_TYPE_GENERIC) &&
             (currentTime + m_ss->GetPhy()->GetFrameDuration() >
@@ -219,7 +217,7 @@
     }
 
     serviceFlows = m_ss->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_NRTPS);
-    for (iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         if ((*iter)->HasPackets(MacHeaderType::HEADER_TYPE_GENERIC))
         {
@@ -230,7 +228,7 @@
     }
 
     serviceFlows = m_ss->GetServiceFlowManager()->GetServiceFlows(ServiceFlow::SF_TYPE_BE);
-    for (iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
+    for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
     {
         if ((*iter)->HasPackets(MacHeaderType::HEADER_TYPE_GENERIC))
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/ss-service-flow-manager.cc ns-3.40/src/wimax/model/ss-service-flow-manager.cc
--- ns-3.39/src/wimax/model/ss-service-flow-manager.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/ss-service-flow-manager.cc	2023-09-27 13:30:37.930839800 -0700
@@ -105,7 +105,7 @@
 void
 SsServiceFlowManager::AddServiceFlow(ServiceFlow serviceFlow)
 {
-    ServiceFlow* sf = new ServiceFlow();
+    auto sf = new ServiceFlow();
     sf->CopyParametersFrom(serviceFlow);
     ServiceFlowManager::AddServiceFlow(sf);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/wimax-mac-queue.cc ns-3.40/src/wimax/model/wimax-mac-queue.cc
--- ns-3.39/src/wimax/model/wimax-mac-queue.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/wimax-mac-queue.cc	2023-09-27 13:30:37.930839800 -0700
@@ -438,8 +438,7 @@
 {
     QueueElement element;
 
-    for (std::deque<QueueElement>::const_iterator iter = m_queue.begin(); iter != m_queue.end();
-         ++iter)
+    for (auto iter = m_queue.begin(); iter != m_queue.end(); ++iter)
     {
         element = *iter;
         if (element.m_hdrType.GetType() == packetType)
@@ -456,7 +455,7 @@
 {
     QueueElement element;
 
-    for (std::deque<QueueElement>::iterator iter = m_queue.begin(); iter != m_queue.end(); ++iter)
+    for (auto iter = m_queue.begin(); iter != m_queue.end(); ++iter)
     {
         element = *iter;
         if (element.m_hdrType.GetType() == packetType)
@@ -498,8 +497,7 @@
 WimaxMacQueue::CheckForFragmentation(MacHeaderType::HeaderType packetType)
 {
     QueueElement element;
-    for (std::deque<QueueElement>::const_iterator iter = m_queue.begin(); iter != m_queue.end();
-         ++iter)
+    for (auto iter = m_queue.begin(); iter != m_queue.end(); ++iter)
     {
         element = *iter;
         if (element.m_hdrType.GetType() == packetType)
@@ -522,8 +520,7 @@
 WimaxMacQueue::GetFirstPacketHdrSize(MacHeaderType::HeaderType packetType)
 {
     QueueElement element;
-    for (std::deque<QueueElement>::const_iterator iter = m_queue.begin(); iter != m_queue.end();
-         ++iter)
+    for (auto iter = m_queue.begin(); iter != m_queue.end(); ++iter)
     {
         element = *iter;
         if (element.m_hdrType.GetType() == packetType)
@@ -559,8 +556,7 @@
 WimaxMacQueue::GetFirstPacketPayloadSize(MacHeaderType::HeaderType packetType)
 {
     QueueElement element;
-    for (std::deque<QueueElement>::const_iterator iter = m_queue.begin(); iter != m_queue.end();
-         ++iter)
+    for (auto iter = m_queue.begin(); iter != m_queue.end(); ++iter)
     {
         element = *iter;
         if (element.m_hdrType.GetType() == packetType)
@@ -601,7 +597,7 @@
 void
 WimaxMacQueue::SetFragmentation(MacHeaderType::HeaderType packetType)
 {
-    for (std::deque<QueueElement>::iterator iter = m_queue.begin(); iter != m_queue.end(); ++iter)
+    for (auto iter = m_queue.begin(); iter != m_queue.end(); ++iter)
     {
         if (iter->m_hdrType.GetType() == packetType)
         {
@@ -614,7 +610,7 @@
 void
 WimaxMacQueue::SetFragmentNumber(MacHeaderType::HeaderType packetType)
 {
-    for (std::deque<QueueElement>::iterator iter = m_queue.begin(); iter != m_queue.end(); ++iter)
+    for (auto iter = m_queue.begin(); iter != m_queue.end(); ++iter)
     {
         if (iter->m_hdrType.GetType() == packetType)
         {
@@ -627,7 +623,7 @@
 void
 WimaxMacQueue::SetFragmentOffset(MacHeaderType::HeaderType packetType, uint32_t offset)
 {
-    for (std::deque<QueueElement>::iterator iter = m_queue.begin(); iter != m_queue.end(); ++iter)
+    for (auto iter = m_queue.begin(); iter != m_queue.end(); ++iter)
     {
         if (iter->m_hdrType.GetType() == packetType)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/wimax-net-device.cc ns-3.40/src/wimax/model/wimax-net-device.cc
--- ns-3.39/src/wimax/model/wimax-net-device.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/wimax-net-device.cc	2023-09-27 13:30:37.930839800 -0700
@@ -517,7 +517,7 @@
     NS_LOG_DEBUG("WimaxNetDevice::Receive, station = " << GetMacAddress());
 
     Ptr<PacketBurst> b = burst->Copy();
-    for (std::list<Ptr<Packet>>::const_iterator iter = b->Begin(); iter != b->End(); ++iter)
+    for (auto iter = b->Begin(); iter != b->End(); ++iter)
     {
         Ptr<Packet> packet = *iter;
         DoReceive(packet);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/wimax-phy.cc ns-3.40/src/wimax/model/wimax-phy.cc
--- ns-3.39/src/wimax/model/wimax-phy.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/wimax-phy.cc	2023-09-27 13:30:37.930839800 -0700
@@ -90,7 +90,7 @@
       m_psPerFrame(0),
       m_symbolsPerFrame(0)
 {
-    m_duplex = 0;
+    m_duplex = false;
     m_txFrequency = 0;
     m_rxFrequency = 0;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/model/wimax-tlv.cc ns-3.40/src/wimax/model/wimax-tlv.cc
--- ns-3.39/src/wimax/model/wimax-tlv.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/model/wimax-tlv.cc	2023-09-27 13:30:37.930839800 -0700
@@ -239,8 +239,7 @@
 
 VectorTlvValue::~VectorTlvValue()
 {
-    for (std::vector<Tlv*>::const_iterator iter = m_tlvList->begin(); iter != m_tlvList->end();
-         ++iter)
+    for (auto iter = m_tlvList->begin(); iter != m_tlvList->end(); ++iter)
     {
         delete (*iter);
     }
@@ -252,8 +251,7 @@
 VectorTlvValue::GetSerializedSize() const
 {
     uint32_t size = 0;
-    for (std::vector<Tlv*>::const_iterator iter = m_tlvList->begin(); iter != m_tlvList->end();
-         ++iter)
+    for (auto iter = m_tlvList->begin(); iter != m_tlvList->end(); ++iter)
     {
         size += (*iter)->GetSerializedSize();
     }
@@ -263,8 +261,7 @@
 void
 VectorTlvValue::Serialize(Buffer::Iterator i) const
 {
-    for (std::vector<Tlv*>::const_iterator iter = m_tlvList->begin(); iter != m_tlvList->end();
-         ++iter)
+    for (auto iter = m_tlvList->begin(); iter != m_tlvList->end(); ++iter)
     {
         (*iter)->Serialize(i);
         i.Next((*iter)->GetSerializedSize());
@@ -297,8 +294,8 @@
 SfVectorTlvValue*
 SfVectorTlvValue::Copy() const
 {
-    SfVectorTlvValue* tmp = new SfVectorTlvValue();
-    for (std::vector<Tlv*>::const_iterator iter = Begin(); iter != End(); ++iter)
+    auto tmp = new SfVectorTlvValue();
+    for (auto iter = Begin(); iter != End(); ++iter)
     {
         tmp->Add(Tlv((*iter)->GetType(), (*iter)->GetLength(), *(*iter)->PeekValue()));
     }
@@ -528,7 +525,7 @@
 U8TlvValue*
 U8TlvValue::Copy() const
 {
-    U8TlvValue* tmp = new U8TlvValue(m_value);
+    auto tmp = new U8TlvValue(m_value);
     return tmp;
 }
 
@@ -581,7 +578,7 @@
 U16TlvValue*
 U16TlvValue::Copy() const
 {
-    U16TlvValue* tmp = new U16TlvValue(m_value);
+    auto tmp = new U16TlvValue(m_value);
     return tmp;
 }
 
@@ -634,7 +631,7 @@
 U32TlvValue*
 U32TlvValue::Copy() const
 {
-    U32TlvValue* tmp = new U32TlvValue(m_value);
+    auto tmp = new U32TlvValue(m_value);
     return tmp;
 }
 
@@ -693,8 +690,8 @@
 CsParamVectorTlvValue*
 CsParamVectorTlvValue::Copy() const
 {
-    CsParamVectorTlvValue* tmp = new CsParamVectorTlvValue();
-    for (std::vector<Tlv*>::const_iterator iter = Begin(); iter != End(); ++iter)
+    auto tmp = new CsParamVectorTlvValue();
+    for (auto iter = Begin(); iter != End(); ++iter)
     {
         tmp->Add(Tlv((*iter)->GetType(), (*iter)->GetLength(), *(*iter)->PeekValue()));
     }
@@ -710,8 +707,8 @@
 ClassificationRuleVectorTlvValue*
 ClassificationRuleVectorTlvValue::Copy() const
 {
-    ClassificationRuleVectorTlvValue* tmp = new ClassificationRuleVectorTlvValue();
-    for (std::vector<Tlv*>::const_iterator iter = Begin(); iter != End(); ++iter)
+    auto tmp = new ClassificationRuleVectorTlvValue();
+    for (auto iter = Begin(); iter != End(); ++iter)
     {
         tmp->Add(Tlv((*iter)->GetType(), (*iter)->GetLength(), *(*iter)->PeekValue()));
     }
@@ -888,9 +885,7 @@
 void
 PortRangeTlvValue::Serialize(Buffer::Iterator i) const
 {
-    for (std::vector<PortRange>::const_iterator iter = m_portRange->begin();
-         iter != m_portRange->end();
-         ++iter)
+    for (auto iter = m_portRange->begin(); iter != m_portRange->end(); ++iter)
     {
         i.WriteHtonU16((*iter).PortLow);
         i.WriteHtonU16((*iter).PortHigh);
@@ -935,10 +930,8 @@
 PortRangeTlvValue*
 PortRangeTlvValue::Copy() const
 {
-    PortRangeTlvValue* tmp = new PortRangeTlvValue();
-    for (std::vector<PortRange>::const_iterator iter = m_portRange->begin();
-         iter != m_portRange->end();
-         ++iter)
+    auto tmp = new PortRangeTlvValue();
+    for (auto iter = m_portRange->begin(); iter != m_portRange->end(); ++iter)
     {
         tmp->Add((*iter).PortLow, (*iter).PortHigh);
     }
@@ -971,8 +964,7 @@
 void
 ProtocolTlvValue::Serialize(Buffer::Iterator i) const
 {
-    for (std::vector<uint8_t>::const_iterator iter = m_protocol->begin(); iter != m_protocol->end();
-         ++iter)
+    for (auto iter = m_protocol->begin(); iter != m_protocol->end(); ++iter)
     {
         i.WriteU8((*iter));
     }
@@ -1011,9 +1003,8 @@
 ProtocolTlvValue*
 ProtocolTlvValue::Copy() const
 {
-    ProtocolTlvValue* tmp = new ProtocolTlvValue();
-    for (std::vector<uint8_t>::const_iterator iter = m_protocol->begin(); iter != m_protocol->end();
-         ++iter)
+    auto tmp = new ProtocolTlvValue();
+    for (auto iter = m_protocol->begin(); iter != m_protocol->end(); ++iter)
     {
         tmp->Add((*iter));
     }
@@ -1046,9 +1037,7 @@
 void
 Ipv4AddressTlvValue::Serialize(Buffer::Iterator i) const
 {
-    for (std::vector<Ipv4Addr>::const_iterator iter = m_ipv4Addr->begin();
-         iter != m_ipv4Addr->end();
-         ++iter)
+    for (auto iter = m_ipv4Addr->begin(); iter != m_ipv4Addr->end(); ++iter)
     {
         i.WriteHtonU32((*iter).Address.Get());
         i.WriteHtonU32((*iter).Mask.Get());
@@ -1090,10 +1079,8 @@
 Ipv4AddressTlvValue*
 Ipv4AddressTlvValue::Copy() const
 {
-    Ipv4AddressTlvValue* tmp = new Ipv4AddressTlvValue();
-    for (std::vector<Ipv4Addr>::const_iterator iter = m_ipv4Addr->begin();
-         iter != m_ipv4Addr->end();
-         ++iter)
+    auto tmp = new Ipv4AddressTlvValue();
+    for (auto iter = m_ipv4Addr->begin(); iter != m_ipv4Addr->end(); ++iter)
     {
         tmp->Add((*iter).Address, (*iter).Mask);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/test/wimax-fragmentation-test.cc ns-3.40/src/wimax/test/wimax-fragmentation-test.cc
--- ns-3.39/src/wimax/test/wimax-fragmentation-test.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/test/wimax-fragmentation-test.cc	2023-09-27 13:30:37.934840000 -0700
@@ -63,8 +63,8 @@
     GenericMacHeader hdr;
 
     Cid cid;
-    WimaxConnection* connectionTx = new WimaxConnection(cid, Cid::TRANSPORT);
-    WimaxConnection* connectionRx = new WimaxConnection(cid, Cid::TRANSPORT);
+    auto connectionTx = new WimaxConnection(cid, Cid::TRANSPORT);
+    auto connectionRx = new WimaxConnection(cid, Cid::TRANSPORT);
 
     // A Packet of 1000 bytes has been created.
     // It will be fragmentated into 4 fragments and then defragmentated into fullPacket.
@@ -127,9 +127,7 @@
             WimaxConnection::FragmentsQueue fragmentsQueue = connectionRx->GetFragmentsQueue();
 
             // DEFRAGMENTATION
-            for (std::list<Ptr<const Packet>>::const_iterator iter = fragmentsQueue.begin();
-                 iter != fragmentsQueue.end();
-                 ++iter)
+            for (auto iter = fragmentsQueue.begin(); iter != fragmentsQueue.end(); ++iter)
             {
                 // Create the whole Packet
                 fullPacket->AddAtEnd(*iter);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/test/wimax-service-flow-test.cc ns-3.40/src/wimax/test/wimax-service-flow-test.cc
--- ns-3.39/src/wimax/test/wimax-service-flow-test.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/test/wimax-service-flow-test.cc	2023-09-27 13:30:37.934840000 -0700
@@ -98,7 +98,7 @@
     Ipv4InterfaceContainer BSinterface = address.Assign(bsDevs);
 
     // Create one UGS Downlink service flow between the ss and the bs
-    ServiceFlow* DlServiceFlowUgs = new ServiceFlow(ServiceFlow::SF_DIRECTION_DOWN);
+    auto DlServiceFlowUgs = new ServiceFlow(ServiceFlow::SF_DIRECTION_DOWN);
     IpcsClassifierRecord DlClassifierUgs(Ipv4Address("0.0.0.0"),
                                          Ipv4Mask("0.0.0.0"),
                                          Ipv4Address("0.0.0.0"),
@@ -121,7 +121,7 @@
     DlServiceFlowUgs->SetTrafficPriority(1);
 
     // Create one UGS Uplink service flow between the ss and the bs
-    ServiceFlow* UlServiceFlowUgs = new ServiceFlow(ServiceFlow::SF_DIRECTION_UP);
+    auto UlServiceFlowUgs = new ServiceFlow(ServiceFlow::SF_DIRECTION_UP);
     IpcsClassifierRecord UlClassifierUgs(Ipv4Address("0.0.0.0"),
                                          Ipv4Mask("0.0.0.0"),
                                          Ipv4Address("0.0.0.0"),
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/src/wimax/test/wimax-tlv-test.cc ns-3.40/src/wimax/test/wimax-tlv-test.cc
--- ns-3.39/src/wimax/test/wimax-tlv-test.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/src/wimax/test/wimax-tlv-test.cc	2023-09-27 13:30:37.934840000 -0700
@@ -89,10 +89,8 @@
     packet->RemoveHeader(tlvReceived);
     if (tlvReceived.GetType() == Tlv::UPLINK_SERVICE_FLOW)
     {
-        SfVectorTlvValue* sfVecValue = (SfVectorTlvValue*)tlvReceived.PeekValue();
-        for (std::vector<Tlv*>::const_iterator iter = sfVecValue->Begin();
-             iter != sfVecValue->End();
-             ++iter)
+        auto sfVecValue = (SfVectorTlvValue*)tlvReceived.PeekValue();
+        for (auto iter = sfVecValue->Begin(); iter != sfVecValue->End(); ++iter)
         {
             if ((*iter)->GetType() == SfVectorTlvValue::IPV4_CS_Parameters)
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/test.py ns-3.40/test.py
--- ns-3.39/test.py	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/test.py	2023-09-27 13:30:37.934840000 -0700
@@ -15,31 +15,35 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
-import os
-import sys
-import time
 import argparse
+import fnmatch
+import os
+import shutil
+import signal
 import subprocess
+import sys
 import threading
-import signal
-import xml.dom.minidom
-import shutil
-import fnmatch
+import time
+import xml.etree.ElementTree as ET
+
 
 from utils import get_list_from_file
 
+# Global variable
+args = None
+
 # imported from waflib Logs
 colors_lst={'USE':True,'BOLD':'\x1b[01;1m','RED':'\x1b[01;31m','GREEN':'\x1b[32m','YELLOW':'\x1b[33m','PINK':'\x1b[35m','BLUE':'\x1b[01;34m','CYAN':'\x1b[36m','GREY':'\x1b[37m','NORMAL':'\x1b[0m','cursor_on':'\x1b[?25h','cursor_off':'\x1b[?25l',}
 def get_color(cl):
     if colors_lst['USE']:
-        return colors_lst.get(cl,'')
-    return''
+        return colors_lst.get(cl, '')
+    return ''
 class color_dict(object):
-    def __getattr__(self,a):
+    def __getattr__(self, a):
         return get_color(a)
-    def __call__(self,a):
+    def __call__(self, a):
         return get_color(a)
-colors=color_dict()
+colors = color_dict()
 
 try:
     import queue
@@ -272,12 +276,11 @@
         node_to_text(child, f, 'Case')
 
 def translate_to_text(results_file, text_file):
-    text_file += '.txt'
+    text_file += ('.txt' if '.txt' not in text_file else '')
     print('Writing results to text file \"%s\"...' % text_file, end='')
-    import xml.etree.ElementTree as ET
     et = ET.parse(results_file)
 
-    with open(text_file, 'w') as f:
+    with open(text_file, 'w', encoding='utf-8') as f:
         for test in et.findall('Test'):
             node_to_text(test, f)
 
@@ -300,10 +303,10 @@
 # since it will probably grow over time.
 #
 def translate_to_html(results_file, html_file):
-    html_file += '.html'
+    html_file += ('.html' if '.html' not in html_file else '')
     print('Writing results to html file %s...' % html_file, end='')
 
-    with open(html_file, 'w') as f:
+    with open(html_file, 'w', encoding='utf-8') as f:
         f.write("<html>\n")
         f.write("<body>\n")
         f.write("<center><h1>ns-3 Test Results</h1></center>\n")
@@ -311,7 +314,6 @@
         #
         # Read and parse the whole results file.
         #
-        import xml.etree.ElementTree as ET
         et = ET.parse(results_file)
 
         #
@@ -392,7 +394,7 @@
                 f.write("<th>Failure Details</th>\n")
 
             #
-            # Now iterate through all of the test cases.
+            # Now iterate through all the test cases.
             #
             for case in suite.findall('Test'):
 
@@ -503,7 +505,7 @@
         f.write("<th>Details</th>\n")
 
         #
-        # Now iterate through all of the examples
+        # Now iterate through all the examples
         #
         for example in et.findall("Example"):
 
@@ -593,30 +595,28 @@
 #
 def read_ns3_config():
     lock_filename = ".lock-ns3_%s_build" % sys.platform
-    f = None
+
     try:
         # sys.platform reports linux2 for python2 and linux for python3
-        f = open(lock_filename, "rt")
+        with open(lock_filename, "rt", encoding="utf-8") as f:
+            for line in f:
+                if line.startswith("top_dir ="):
+                    key, val = line.split('=')
+                    top_dir = eval(val.strip())
+                if line.startswith("out_dir ="):
+                    key, val = line.split('=')
+                    out_dir = eval(val.strip())
+
     except FileNotFoundError:
         print('The .lock-ns3 file was not found.  You must configure before running test.py.', file=sys.stderr)
         sys.exit(2)
 
-    for line in f:
-        if line.startswith("top_dir ="):
-            key, val = line.split('=')
-            top_dir = eval(val.strip())
-        if line.startswith("out_dir ="):
-            key, val = line.split('=')
-            out_dir = eval(val.strip())
-
-    f.close()
-
     global NS3_BASEDIR
     NS3_BASEDIR = top_dir
     global NS3_BUILDDIR
     NS3_BUILDDIR = out_dir
 
-    with open(lock_filename) as f:
+    with open(lock_filename, encoding='utf-8') as f:
         for line in f.readlines():
             for item in interesting_config_items:
                 if line.startswith(item):
@@ -1026,7 +1026,7 @@
                     # know.  It will be something like "examples/udp/udp-echo" or
                     # "examples/wireless/mixed-wireless.py"
                     #
-                    (job.returncode, standard_out, standard_err, et) = run_job_synchronously(job.shell_command,
+                    (job.returncode, job.standard_out, job.standard_err, et) = run_job_synchronously(job.shell_command,
                         job.cwd, args.valgrind, job.is_pyexample, job.build_path)
                 else:
                     #
@@ -1038,7 +1038,7 @@
                         update_data = '--update-data'
                     else:
                         update_data = ''
-                    (job.returncode, standard_out, standard_err, et) = run_job_synchronously(job.shell_command +
+                    (job.returncode, job.standard_out, job.standard_err, et) = run_job_synchronously(job.shell_command +
                         " --xml --tempdir=%s --out=%s %s" % (job.tempdir, job.tmp_file_name, update_data),
                         job.cwd, args.valgrind, False)
 
@@ -1047,14 +1047,43 @@
                 if args.verbose:
                     print("returncode = %d" % job.returncode)
                     print("---------- begin standard out ----------")
-                    print(standard_out)
+                    print(job.standard_out)
                     print("---------- begin standard err ----------")
-                    print(standard_err)
+                    print(job.standard_err)
                     print("---------- end standard err ----------")
 
                 self.output_queue.put(job)
 
 #
+# This function loads the list of previously successful or skipped examples and test suites.
+#
+def load_previously_successful_tests():
+    import glob
+    previously_run_tests_to_skip = {"test": [], "example": []}
+    previous_results = glob.glob(f"{TMP_OUTPUT_DIR}/*-results.xml")
+    if not previous_results:
+        print("No previous runs to rerun")
+        exit(-1)
+    latest_result_file = list(sorted(previous_results, key=lambda x: os.path.basename(x), reverse=True))[0]
+
+    try:
+        previous_run_results = ET.parse(latest_result_file)
+    except ET.ParseError:
+        print(f"Failed to parse XML {latest_result_file}")
+        exit(-1)
+
+    for test_type in ["Test", "Example"]:
+        if previous_run_results.find(test_type):
+            temp = list(map(lambda x: (x.find('Name').text, x.find('Result').text),
+                            previous_run_results.findall(test_type)
+                            )
+                        )
+            temp = list(filter(lambda x: x[1] in ['PASS', 'SKIP'], temp))
+            temp = [x[0] for x in temp]
+            previously_run_tests_to_skip[test_type.lower()] = temp
+    return previously_run_tests_to_skip
+
+#
 # This is the main function that does the work of interacting with the
 # test-runner itself.
 #
@@ -1248,13 +1277,13 @@
             examples_sorted.sort()
         if ENABLE_PYTHON_BINDINGS:
             python_examples_sorted = []
-            for (x,y) in python_tests:
+            for (x, y) in python_tests:
                 if y == 'True':
                     python_examples_sorted.append(x)
             python_examples_sorted.sort()
             examples_sorted.extend(python_examples_sorted)
         for item in examples_sorted:
-                print("example     ", item)
+            print("example     ", item)
         print()
 
     if args.kinds or args.list:
@@ -1286,17 +1315,26 @@
     if not os.path.exists(TMP_OUTPUT_DIR):
         os.makedirs(TMP_OUTPUT_DIR)
 
-    testpy_output_dir = os.path.join(TMP_OUTPUT_DIR, date_and_time);
+    testpy_output_dir = os.path.join(TMP_OUTPUT_DIR, date_and_time)
 
     if not os.path.exists(testpy_output_dir):
         os.makedirs(testpy_output_dir)
 
     #
+    # Load results from the latest results.xml, then use the list of
+    # failed tests to filter out (SKIP) successful tests
+    #
+    previously_run_tests_to_skip = {"test": [], "example": []}
+    if args.rerun_failed:
+        previously_run_tests_to_skip = load_previously_successful_tests()
+
+    #
     # Create the main output file and start filling it with XML.  We need to
     # do this since the tests will just append individual results to this file.
+    # The file is created outside the directory that gets automatically deleted.
     #
-    xml_results_file = os.path.join(testpy_output_dir, "results.xml")
-    with open(xml_results_file, 'w') as f:
+    xml_results_file = os.path.join(TMP_OUTPUT_DIR, f"{date_and_time}-results.xml")
+    with open(xml_results_file, 'w', encoding='utf-8') as f:
         f.write('<?xml version="1.0"?>\n')
         f.write('<Results>\n')
 
@@ -1333,7 +1371,8 @@
         if isinstance(suites, bytes):
             suites = suites.decode()
 
-        suites_found = fnmatch.filter(suites.split('\n'), args.suite)
+        suites = suites.replace("\r\n", "\n")
+        suites_found = fnmatch.filter(suites.split("\n"), args.suite)
 
         if not suites_found:
             print('The test suite was not run because an unknown test suite name was requested.', file=sys.stderr)
@@ -1392,7 +1431,7 @@
     output_queue = queue.Queue(0)
 
     jobs = 0
-    threads=[]
+    threads = []
 
     #
     # In Python 2.6 you can just use multiprocessing module, but we don't want
@@ -1401,7 +1440,7 @@
     processors = 1
 
     if sys.platform != "win32":
-        if 'SC_NPROCESSORS_ONLN'in os.sysconf_names:
+        if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:
             processors = os.sysconf('SC_NPROCESSORS_ONLN')
         else:
             proc = subprocess.Popen("sysctl -n hw.ncpu", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -1443,7 +1482,7 @@
     # Dispatching will run with unlimited speed and the worker threads will
     # execute as fast as possible from the queue.
     #
-    # Note that we actually dispatch tests to be skipped, so all of the
+    # Note that we actually dispatch tests to be skipped, so all the
     # PASS, FAIL, CRASH and SKIP processing is done in the same place.
     #
     for test in suite_list:
@@ -1475,6 +1514,10 @@
                 job.set_is_skip(True)
                 job.set_skip_reason("crashes valgrind")
 
+            if args.rerun_failed and test in previously_run_tests_to_skip["test"]:
+                job.is_skip = True
+                job.set_skip_reason("didn't fail in the previous run")
+
             if args.verbose:
                 print("Queue %s" % test)
 
@@ -1541,6 +1584,10 @@
                                 job.set_is_skip(True)
                                 job.set_skip_reason("skip in valgrind runs")
 
+                            if args.rerun_failed and name in previously_run_tests_to_skip["example"]:
+                                job.is_skip = True
+                                job.set_skip_reason("didn't fail in the previous run")
+
                             if args.verbose:
                                 print("Queue %s" % test)
 
@@ -1555,7 +1602,7 @@
 
         key_list = []
         for key in ns3_runnable_programs_dictionary:
-            key_list.append (key)
+            key_list.append(key)
         example_name_key_list = fnmatch.filter(key_list, example_name)
 
         if len(example_name_key_list) == 0:
@@ -1716,6 +1763,7 @@
     crashed_testnames = []
     valgrind_errors = 0
     valgrind_testnames = []
+    failed_jobs = []
     for i in range(jobs):
         job = output_queue.get()
         if job.is_break:
@@ -1732,10 +1780,12 @@
             skipped_tests = skipped_tests + 1
             skipped_testnames.append(job.display_name + (" (%s)" % job.skip_reason))
         else:
+            failed_jobs.append(job)
             if job.returncode == 0:
                 status = "PASS"
                 status_print = colors.GREEN + status + colors.NORMAL
                 passed_tests = passed_tests + 1
+                failed_jobs.pop()
             elif job.returncode == 1:
                 failed_tests = failed_tests + 1
                 failed_testnames.append(job.display_name)
@@ -1752,7 +1802,7 @@
                 status = "CRASH"
                 status_print = colors.PINK + status + colors.NORMAL
 
-        print("[%d/%d]" % (passed_tests + failed_tests + skipped_tests + crashed_tests, total_tests), end=' ')
+        print("[%d/%d]" % (i, total_tests), end=' ')
         if args.duration or args.constrain == "performance":
             print("%s (%.3f): %s %s" % (status_print, job.elapsed_time, kind, job.display_name))
         else:
@@ -1768,7 +1818,7 @@
             # XXX We could add some timing information to the examples, i.e. run
             # them through time and print the results here.
             #
-            with open(xml_results_file, 'a') as f:
+            with open(xml_results_file, 'a', encoding='utf-8') as f:
                 f.write('<Example>\n')
                 example_name = "  <Name>%s</Name>\n" % job.display_name
                 f.write(example_name)
@@ -1833,18 +1883,27 @@
             # followed by a VALGR failing test suite of the same name.
             #
             if job.is_skip:
-                with open(xml_results_file, 'a') as f:
+                with open(xml_results_file, 'a', encoding='utf-8') as f:
                     f.write("<Test>\n")
                     f.write("  <Name>%s</Name>\n" % job.display_name)
                     f.write('  <Result>SKIP</Result>\n')
                     f.write("  <Reason>%s</Reason>\n" % job.skip_reason)
                     f.write("</Test>\n")
             else:
+                failed_jobs.append(job)
                 if job.returncode == 0 or job.returncode == 1 or job.returncode == 2:
-                    with open(xml_results_file, 'a') as f_to, open(job.tmp_file_name) as f_from:
-                        f_to.write(f_from.read())
+                    with open(xml_results_file, 'a', encoding='utf-8') as f_to, open(job.tmp_file_name, encoding='utf-8') as f_from:
+                        contents = f_from.read()
+                        if status == "VALGR":
+                            pre = contents.find("<Result>") + len("<Result>")
+                            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()
                 else:
-                    with open(xml_results_file, 'a') as f:
+                    with open(xml_results_file, 'a', encoding='utf-8') as f:
                         f.write("<Test>\n")
                         f.write("  <Name>%s</Name>\n" % job.display_name)
                         f.write('  <Result>CRASH</Result>\n')
@@ -1864,7 +1923,7 @@
     # individual pieces.  So, we need to finish off and close out the XML
     # document
     #
-    with open(xml_results_file, 'a') as f:
+    with open(xml_results_file, 'a', encoding='utf-8') as f:
         f.write('</Results>\n')
 
     #
@@ -1887,8 +1946,18 @@
     if valgrind_testnames:
         valgrind_testnames.sort()
         print('List of VALGR failures:\n    %s' % '\n    '.join(map(str, valgrind_testnames)))
+
+    if failed_jobs and args.verbose_failed:
+        for job in failed_jobs:
+            if job.standard_out or job.standard_err:
+                job_type = 'example' if (job.is_example or job.is_pyexample) else 'test suite'
+                print(f"===================== Begin of {job_type} '{job.display_name}' stdout =====================")
+                print(job.standard_out)
+                print(f"===================== Begin of {job_type} '{job.display_name}' stderr =====================")
+                print(job.standard_err)
+                print(f"===================== End of {job_type} '{job.display_name}' ==============================")
     #
-    # The last things to do are to translate the XML results file to "human
+    # The last things to do are to translate the XML results file to "human-
     # readable form" if the user asked for it (or make an XML file somewhere)
     #
     if len(args.html) + len(args.text) + len(args.xml):
@@ -1901,7 +1970,7 @@
         translate_to_text(xml_results_file, args.text)
 
     if len(args.xml):
-        xml_file = args.xml + '.xml'
+        xml_file = args.xml + ('.xml' if ".xml" not in args.xml else '')
         print('Writing results to xml file %s...' % xml_file, end='')
         shutil.copyfile(xml_results_file, xml_file)
         print('done.')
@@ -1996,6 +2065,9 @@
     parser.add_argument("-v", "--verbose", action="store_true", default=False,
                         help="print progress and informational messages")
 
+    parser.add_argument("--verbose-failed", action="store_true", default=False,
+                        help="print progress and informational messages for failed jobs")
+
     parser.add_argument("-w", "--web", "--html", action="store", type=str, dest="html", default="",
                         metavar="HTML-FILE",
                         help="write detailed test results into HTML-FILE.html")
@@ -2010,12 +2082,15 @@
     parser.add_argument("--jobs", action="store", type=int, dest="process_limit", default=0,
                         help="limit number of worker threads")
 
+    parser.add_argument("--rerun-failed", action="store_true", dest="rerun_failed", default=False,
+                        help="rerun failed tests")
+
     global args
     args = parser.parse_args()
     signal.signal(signal.SIGINT, sigint_hook)
 
     # From waf/waflib/Options.py
-    envcolor=os.environ.get('NOCOLOR','') and 'no' or 'auto' or 'yes'
+    envcolor = os.environ.get('NOCOLOR', '') and 'no' or 'auto' or 'yes'
 
     if args.nocolor or envcolor == 'no':
         colors_lst['USE'] = False
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/bench-scheduler.cc ns-3.40/utils/bench-scheduler.cc
--- ns-3.39/utils/bench-scheduler.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils/bench-scheduler.cc	2023-09-27 13:30:37.934840000 -0700
@@ -432,7 +432,7 @@
         {
             if (*input >> value)
             {
-                uint64_t ns = (uint64_t)(value * 1000000000);
+                auto ns = (uint64_t)(value * 1000000000);
                 nsValues.push_back(ns);
             }
             else
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/check-style-clang-format.py ns-3.40/utils/check-style-clang-format.py
--- ns-3.39/utils/check-style-clang-format.py	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils/check-style-clang-format.py	2023-09-27 13:30:37.934840000 -0700
@@ -22,13 +22,10 @@
 
 The coding style is defined with the clang-format tool, whose definitions are in
 the ".clang-format" file. This script performs the following checks / fixes:
-- Check / apply clang-format.
-- Check / trim trailing whitespace.
-- Check / replace tabs with spaces.
-
-The clang-format and tabs checks respect clang-format guards, which mark code blocks
-that should not be checked. Trailing whitespace is always checked regardless of
-clang-format guards.
+- Check / fix local #include headers with "ns3/" prefix. Respects clang-format guards.
+- Check / apply clang-format. Respects clang-format guards.
+- Check / trim trailing whitespace. Always checked.
+- Check / replace tabs with spaces. Respects clang-format guards.
 
 This script can be applied to all text files in a given path or to individual files.
 
@@ -41,11 +38,12 @@
 import concurrent.futures
 import itertools
 import os
+import re
 import shutil
 import subprocess
 import sys
 
-from typing import Dict, List, Tuple
+from typing import Callable, Dict, List, Tuple
 
 ###########################################################
 # PARAMETERS
@@ -80,6 +78,8 @@
     '.h',
 ]
 
+FILE_EXTENSIONS_TO_CHECK_INCLUDE_PREFIXES = FILE_EXTENSIONS_TO_CHECK_FORMATTING
+
 FILE_EXTENSIONS_TO_CHECK_WHITESPACE = [
     '.c',
     '.cc',
@@ -131,124 +131,95 @@
 ###########################################################
 # AUXILIARY FUNCTIONS
 ###########################################################
-def skip_directory(dirpath: str) -> bool:
+def should_analyze_directory(dirpath: str) -> bool:
     """
-    Check if a directory should be skipped.
+    Check whether a directory should be analyzed.
 
     @param dirpath Directory path.
-    @return Whether the directory should be skipped or not.
+    @return Whether the directory should be analyzed.
     """
 
     _, directory = os.path.split(dirpath)
 
-    return (directory in DIRECTORIES_TO_SKIP or
-            (directory.startswith('.') and directory != '.'))
-
-
-def skip_file_formatting(path: str) -> bool:
-    """
-    Check if a file should be skipped from formatting analysis.
-
-    @param path Path to the file.
-    @return Whether the file should be skipped or not.
-    """
-
-    filename = os.path.split(path)[1]
-
-    if filename in FILES_TO_SKIP:
-        return True
-
-    _, extension = os.path.splitext(filename)
-
-    return extension not in FILE_EXTENSIONS_TO_CHECK_FORMATTING
+    return not (directory in DIRECTORIES_TO_SKIP or
+                (directory.startswith('.') and directory != '.'))
 
 
-def skip_file_whitespace(path: str) -> bool:
+def should_analyze_file(path: str,
+                        files_to_check: List[str],
+                        file_extensions_to_check: List[str],
+                        ) -> bool:
     """
-    Check if a file should be skipped from trailing whitespace analysis.
+    Check whether a file should be analyzed.
 
     @param path Path to the file.
-    @return Whether the file should be skipped or not.
+    @param files_to_check List of files that shall be checked.
+    @param file_extensions_to_check List of file extensions that shall be checked.
+    @return Whether the file should be analyzed.
     """
 
     filename = os.path.split(path)[1]
 
     if filename in FILES_TO_SKIP:
-        return True
+        return False
 
     basename, extension = os.path.splitext(filename)
 
-    return (basename not in FILES_TO_CHECK_WHITESPACE and
-            extension not in FILE_EXTENSIONS_TO_CHECK_WHITESPACE)
-
-
-def skip_file_tabs(path: str) -> bool:
-    """
-    Check if a file should be skipped from tabs analysis.
-
-    @param path Path to the file.
-    @return Whether the file should be skipped or not.
-    """
-
-    filename = os.path.split(path)[1]
-
-    if filename in FILES_TO_SKIP:
-        return True
-
-    _, extension = os.path.splitext(filename)
+    return (basename in files_to_check or
+            extension in file_extensions_to_check)
 
-    return extension not in FILE_EXTENSIONS_TO_CHECK_TABS
 
-
-def find_files_to_check_style(path: str) -> Tuple[List[str], List[str], List[str]]:
+def find_files_to_check_style(path: str) -> Tuple[List[str], List[str], List[str], List[str]]:
     """
     Find all files to be checked in a given path.
 
     @param path Path to check.
-    @return Tuple [List of files to check formatting,
+    @return Tuple [List of files to check include prefixes,
+                   List of files to check formatting,
                    List of files to check trailing whitespace,
                    List of files to check tabs].
     """
 
-    files_to_check_formatting: List[str] = []
-    files_to_check_whitespace: List[str] = []
-    files_to_check_tabs: List[str] = []
-
-    abs_path = os.path.normpath(os.path.abspath(os.path.expanduser(path)))
+    files_to_check: List[str] = []
+    abs_path = os.path.abspath(os.path.expanduser(path))
 
     if os.path.isfile(abs_path):
-        if not skip_file_formatting(path):
-            files_to_check_formatting.append(path)
-
-        if not skip_file_whitespace(path):
-            files_to_check_whitespace.append(path)
-
-        if not skip_file_tabs(path):
-            files_to_check_tabs.append(path)
+        files_to_check = [path]
 
     elif os.path.isdir(abs_path):
         for dirpath, dirnames, filenames in os.walk(path, topdown=True):
-            if skip_directory(dirpath):
+            if not should_analyze_directory(dirpath):
                 # Remove directory and its subdirectories
                 dirnames[:] = []
                 continue
 
-            filenames = [os.path.join(dirpath, f) for f in filenames]
+            files_to_check.extend([os.path.join(dirpath, f) for f in filenames])
+
+    else:
+        raise ValueError(f'Error: {path} is not a file nor a directory')
+
+    files_to_check.sort()
 
-            for f in filenames:
-                if not skip_file_formatting(f):
-                    files_to_check_formatting.append(f)
+    files_to_check_include_prefixes: List[str] = []
+    files_to_check_formatting: List[str] = []
+    files_to_check_whitespace: List[str] = []
+    files_to_check_tabs: List[str] = []
 
-                if not skip_file_whitespace(f):
-                    files_to_check_whitespace.append(f)
+    for f in files_to_check:
+        if should_analyze_file(f, [], FILE_EXTENSIONS_TO_CHECK_INCLUDE_PREFIXES):
+            files_to_check_include_prefixes.append(f)
 
-                if not skip_file_tabs(f):
-                    files_to_check_tabs.append(f)
+        if should_analyze_file(f, [], FILE_EXTENSIONS_TO_CHECK_FORMATTING):
+            files_to_check_formatting.append(f)
 
-    else:
-        raise ValueError(f'Error: {path} is not a file nor a directory')
+        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):
+            files_to_check_tabs.append(f)
 
     return (
+        files_to_check_include_prefixes,
         files_to_check_formatting,
         files_to_check_whitespace,
         files_to_check_tabs,
@@ -295,51 +266,71 @@
 
 
 ###########################################################
-# CHECK STYLE
+# CHECK STYLE MAIN FUNCTIONS
 ###########################################################
-def check_style(path: str,
-                enable_check_formatting: bool,
-                enable_check_whitespace: bool,
-                enable_check_tabs: bool,
-                fix: bool,
-                verbose: bool,
-                n_jobs: int = 1,
-                ) -> None:
+def check_style_clang_format(path: str,
+                             enable_check_include_prefixes: bool,
+                             enable_check_formatting: bool,
+                             enable_check_whitespace: bool,
+                             enable_check_tabs: bool,
+                             fix: bool,
+                             verbose: bool,
+                             n_jobs: int = 1,
+                             ) -> bool:
     """
-    Check / fix the coding style of a list of files, including formatting and
-    trailing whitespace.
+    Check / fix the coding style of a list of files.
 
     @param path Path to the files.
-    @param fix Whether to fix the style of the file (True) or
-               just check if the file is well-formatted (False).
-    @param enable_check_formatting Whether to enable code formatting checking.
-    @param enable_check_whitespace Whether to enable trailing whitespace checking.
-    @param enable_check_tabs Whether to enable tabs checking.
-    @param verbose Show the lines that are not well-formatted.
+    @param enable_check_include_prefixes Whether to enable checking #include headers from the same module with the "ns3/" prefix.
+    @param enable_check_formatting Whether to enable checking code formatting.
+    @param enable_check_whitespace Whether to enable checking trailing whitespace.
+    @param enable_check_tabs Whether to enable checking tabs.
+    @param fix Whether to fix (True) or just check (False) the file.
+    @param verbose Show the lines that are not compliant with the style.
     @param n_jobs Number of parallel jobs.
+    @return Whether all files are compliant with all enabled style checks.
     """
 
-    (files_to_check_formatting,
+    (files_to_check_include_prefixes,
+     files_to_check_formatting,
      files_to_check_whitespace,
      files_to_check_tabs) = find_files_to_check_style(path)
 
+    check_include_prefixes_successful = True
     check_formatting_successful = True
     check_whitespace_successful = True
     check_tabs_successful = True
 
+    if enable_check_include_prefixes:
+        check_include_prefixes_successful = check_style_file(
+            files_to_check_include_prefixes,
+            check_include_prefixes_file,
+            '#include headers from the same module with the "ns3/" prefix',
+            fix,
+            verbose,
+            n_jobs,
+        )
+
+        print('')
+
     if enable_check_formatting:
-        check_formatting_successful = check_formatting(
+        check_formatting_successful = check_style_file(
             files_to_check_formatting,
+            check_formatting_file,
+            'bad code formatting',
             fix,
             verbose,
             n_jobs,
+            clang_format_path=find_clang_format_path(),
         )
 
         print('')
 
     if enable_check_whitespace:
-        check_whitespace_successful = check_trailing_whitespace(
+        check_whitespace_successful = check_style_file(
             files_to_check_whitespace,
+            check_trailing_whitespace_file,
+            'trailing whitespace',
             fix,
             verbose,
             n_jobs,
@@ -348,101 +339,180 @@
         print('')
 
     if enable_check_tabs:
-        check_tabs_successful = check_tabs(
+        check_tabs_successful = check_style_file(
             files_to_check_tabs,
+            check_tabs_file,
+            'tabs',
             fix,
             verbose,
             n_jobs,
         )
 
-    if all([
+    return all([
+        check_include_prefixes_successful,
         check_formatting_successful,
         check_whitespace_successful,
         check_tabs_successful,
-    ]):
-        sys.exit(0)
-    else:
-        sys.exit(1)
+    ])
 
 
-###########################################################
-# CHECK FORMATTING
-###########################################################
-def check_formatting(filenames: List[str],
+def check_style_file(filenames: List[str],
+                     check_style_file_function: Callable,
+                     style_check_str: str,
                      fix: bool,
                      verbose: bool,
                      n_jobs: int,
+                     **kwargs,
                      ) -> bool:
     """
-    Check / fix the coding style of a list of files with clang-format.
+    Check / fix style of a list of files.
 
-    @param filenames List of filenames to be checked.
-    @param fix Whether to fix the formatting of the file (True) or
-               just check if the file is well-formatted (False).
-    @param verbose Show the lines that are not well-formatted.
+    @param filename Name of the file to be checked.
+    @param check_style_file_function Function used to check the file.
+    @param style_check_str Description of the check to be performed.
+    @param fix Whether to fix (True) or just check (False) the file (True).
+    @param verbose Show the lines that are not compliant with the style.
     @param n_jobs Number of parallel jobs.
-    @return True if all files are well formatted after the check process.
-            False if there are non-formatted files after the check process.
+    @param kwargs Additional keyword arguments to the check_style_file_function.
+    @return Whether all files are compliant with the style.
     """
 
     # Check files
-    clang_format_path = find_clang_format_path()
-    files_not_formatted: List[str] = []
+    non_compliant_files: List[str] = []
     files_verbose_infos: Dict[str, List[str]] = {}
 
     with concurrent.futures.ProcessPoolExecutor(n_jobs) as executor:
-        files_not_formatted_results = executor.map(
-            check_formatting_file,
+        non_compliant_files_results = executor.map(
+            check_style_file_function,
             filenames,
-            itertools.repeat(clang_format_path),
             itertools.repeat(fix),
             itertools.repeat(verbose),
+            *[arg if isinstance(arg, list) else itertools.repeat(arg) for arg in kwargs.values()],
         )
 
-        for (filename, formatted, verbose_infos) in files_not_formatted_results:
-            if not formatted:
-                files_not_formatted.append(filename)
+        for (filename, is_file_compliant, verbose_infos) in non_compliant_files_results:
+            if not is_file_compliant:
+                non_compliant_files.append(filename)
 
             if verbose:
                 files_verbose_infos[filename] = verbose_infos
 
     # Output results
-    if not files_not_formatted:
-        print('- All files are well formatted')
+    if not non_compliant_files:
+        print(f'- No files detected with {style_check_str}')
         return True
 
     else:
-        n_non_formatted_files = len(files_not_formatted)
+        n_non_compliant_files = len(non_compliant_files)
 
         if fix:
-            print(f'- Fixed formatting of the files ({n_non_formatted_files}):')
+            print(f'- Fixed {style_check_str} in the files ({n_non_compliant_files}):')
         else:
-            print(f'- Detected bad formatting in the files ({n_non_formatted_files}):')
+            print(f'- Detected {style_check_str} in the files ({n_non_compliant_files}):')
 
-        for f in files_not_formatted:
+        for f in non_compliant_files:
             if verbose:
                 print(*[f'    {l}' for l in files_verbose_infos[f]], sep='\n')
             else:
                 print(f'    - {f}')
 
-        # Return True if all files were fixed
+        # If all files were fixed, there are no more non-compliant files
         return fix
 
 
+###########################################################
+# CHECK STYLE FUNCTIONS
+###########################################################
+def check_include_prefixes_file(filename: str,
+                                fix: bool,
+                                verbose: bool,
+                                ) -> Tuple[str, bool, List[str]]:
+    """
+    Check / fix #include headers from the same module with the "ns3/" prefix in a file.
+
+    @param filename Name of the file to be checked.
+    @param fix Whether to fix (True) or just check (False) the style of the file (True).
+    @param verbose Show the lines that are not compliant with the style.
+    @return Tuple [Filename,
+                   Whether the file is compliant with the style (before the check),
+                   Verbose information].
+    """
+
+    is_file_compliant = True
+    clang_format_enabled = True
+
+    verbose_infos: List[str] = []
+
+    with open(filename, 'r', encoding='utf-8') as f:
+        file_lines = f.readlines()
+
+    for (i, line) in enumerate(file_lines):
+
+        # Check clang-format guards
+        line_stripped = line.strip()
+
+        if line_stripped == CLANG_FORMAT_GUARD_ON:
+            clang_format_enabled = True
+        elif line_stripped == CLANG_FORMAT_GUARD_OFF:
+            clang_format_enabled = False
+
+        if (not clang_format_enabled and
+                line_stripped not in (CLANG_FORMAT_GUARD_ON, CLANG_FORMAT_GUARD_OFF)):
+            continue
+
+        # Check if the line is an #include and extract its header file
+        header_file = re.findall(r'^#include ["<]ns3/(.*\.h)[">]', line_stripped)
+
+        if not header_file:
+            continue
+
+        # Check if the header file belongs to the same module and remove the "ns3/" prefix
+        header_file = header_file[0]
+        parent_path = os.path.split(filename)[0]
+
+        if not os.path.exists(os.path.join(parent_path, header_file)):
+            continue
+
+        is_file_compliant = False
+        file_lines[i] = line_stripped.replace(
+            f'ns3/{header_file}', header_file).replace('<', '"').replace('>', '"') + '\n'
+
+        if verbose:
+            header_index = len('#include "')
+
+            verbose_infos.extend([
+                f'{filename}:{i + 1}:{header_index + 1}: error: #include headers from the same module with the "ns3/" prefix detected',
+                f'    {line_stripped}',
+                f'    {"":{header_index}}^',
+            ])
+
+        # Optimization: If running in non-verbose check mode, only one error is needed to check that the file is not compliant
+        if not fix and not verbose:
+            break
+
+    # Update file with the fixed lines
+    if fix and not is_file_compliant:
+        with open(filename, 'w', encoding='utf-8') as f:
+            f.writelines(file_lines)
+
+    return (filename, is_file_compliant, verbose_infos)
+
+
 def check_formatting_file(filename: str,
-                          clang_format_path: str,
                           fix: bool,
                           verbose: bool,
+                          clang_format_path: str,
                           ) -> Tuple[str, bool, List[str]]:
     """
     Check / fix the coding style of a file with clang-format.
 
     @param filename Name of the file to be checked.
+    @param fix Whether to fix (True) or just check (False) the style of the file (True).
+    @param verbose Show the lines that are not compliant with the style.
     @param clang_format_path Path to clang-format.
-    @param fix Whether to fix the style of the file (True) or
-               just check if the file is well-formatted (False).
-    @param verbose Show the lines that are not well-formatted.
-    @return Tuple [Filename, Whether the file is well-formatted, Verbose information].
+    @return Tuple [Filename,
+                   Whether the file is compliant with the style (before the check),
+                   Verbose information].
     """
 
     verbose_infos: List[str] = []
@@ -455,7 +525,7 @@
             '-style=file',
             '--dry-run',
             '--Werror',
-            # Optimization: In non-verbose mode, only 1 error is needed to check that the file is not formatted
+            # Optimization: In non-verbose mode, only one error is needed to check that the file is not compliant
             f'--ferror-limit={0 if verbose else 1}',
         ],
         check=False,
@@ -463,13 +533,13 @@
         text=True,
     )
 
-    file_formatted = (process.returncode == 0)
+    is_file_compliant = (process.returncode == 0)
 
     if verbose:
         verbose_infos = process.stderr.splitlines()
 
     # Fix file
-    if fix and not file_formatted:
+    if fix and not is_file_compliant:
         process = subprocess.run(
             [
                 clang_format_path,
@@ -482,71 +552,7 @@
             stderr=subprocess.DEVNULL,
         )
 
-    return (filename, file_formatted, verbose_infos)
-
-
-###########################################################
-# CHECK TRAILING WHITESPACE
-###########################################################
-def check_trailing_whitespace(filenames: List[str],
-                              fix: bool,
-                              verbose: bool,
-                              n_jobs: int,
-                              ) -> bool:
-    """
-    Check / fix trailing whitespace in a list of files.
-
-    @param filename Name of the file to be checked.
-    @param fix Whether to fix the file (True) or
-               just check if it has trailing whitespace (False).
-    @param verbose Show the lines that are not well-formatted.
-    @param n_jobs Number of parallel jobs.
-    @return True if no files have trailing whitespace after the check process.
-            False if there are trailing whitespace after the check process.
-    """
-
-    # Check files
-    files_with_whitespace: List[str] = []
-    files_verbose_infos: Dict[str, List[str]] = {}
-
-    with concurrent.futures.ProcessPoolExecutor(n_jobs) as executor:
-        files_with_whitespace_results = executor.map(
-            check_trailing_whitespace_file,
-            filenames,
-            itertools.repeat(fix),
-            itertools.repeat(verbose),
-        )
-
-        for (filename, has_whitespace, verbose_infos) in files_with_whitespace_results:
-            if has_whitespace:
-                files_with_whitespace.append(filename)
-
-            if verbose:
-                files_verbose_infos[filename] = verbose_infos
-
-    # Output results
-    if not files_with_whitespace:
-        print('- No files detected with trailing whitespace')
-        return True
-
-    else:
-        n_files_with_whitespace = len(files_with_whitespace)
-
-        if fix:
-            print(
-                f'- Fixed trailing whitespace in the files ({n_files_with_whitespace}):')
-        else:
-            print(
-                f'- Detected trailing whitespace in the files ({n_files_with_whitespace}):')
-
-        for f in files_with_whitespace:
-            if verbose:
-                print(*[f'    {l}' for l in files_verbose_infos[f]], sep='\n')
-            else:
-                print(f'    - {f}')
-
-        # If all files were fixed, there are no more trailing whitespace
-        return fix
+    return (filename, is_file_compliant, verbose_infos)
 
 
 def check_trailing_whitespace_file(filename: str,
@@ -557,13 +563,14 @@
     Check / fix trailing whitespace in a file.
 
     @param filename Name of the file to be checked.
-    @param fix Whether to fix the file (True) or
-               just check if it has trailing whitespace (False).
-    @param verbose Show the lines that are not well-formatted.
-    @return Tuple [Filename, Whether the file has trailing whitespace, Verbose information].
+    @param fix Whether to fix (True) or just check (False) the style of the file (True).
+    @param verbose Show the lines that are not compliant with the style.
+    @return Tuple [Filename,
+                   Whether the file is compliant with the style (before the check),
+                   Verbose information].
     """
 
-    has_trailing_whitespace = False
+    is_file_compliant = True
     verbose_infos: List[str] = []
 
     with open(filename, 'r', encoding='utf-8') as f:
@@ -573,90 +580,31 @@
     for (i, line) in enumerate(file_lines):
         line_fixed = line.rstrip() + '\n'
 
-        if line_fixed != line:
-            has_trailing_whitespace = True
-            file_lines[i] = line_fixed
+        if line_fixed == line:
+            continue
 
-            if verbose:
-                verbose_infos.extend([
-                    f'{filename}:{i + 1}: error: Trailing whitespace detected',
-                    f'    {line_fixed.rstrip()}',
-                    f'    {"":{len(line_fixed) - 1}}^',
-                ])
-
-            # Optimization: If running in non-verbose check mode, only one error is needed to check that the file is not formatted
-            if not fix and not verbose:
-                break
+        is_file_compliant = False
+        file_lines[i] = line_fixed
+
+        if verbose:
+            line_fixed_stripped_expanded = line_fixed.rstrip().expandtabs(TAB_SIZE)
+
+            verbose_infos.extend([
+                f'{filename}:{i + 1}:{len(line_fixed_stripped_expanded) + 1}: error: Trailing whitespace detected',
+                f'    {line_fixed_stripped_expanded}',
+                f'    {"":{len(line_fixed_stripped_expanded)}}^',
+            ])
+
+        # Optimization: If running in non-verbose check mode, only one error is needed to check that the file is not compliant
+        if not fix and not verbose:
+            break
 
     # Update file with the fixed lines
-    if fix and has_trailing_whitespace:
+    if fix and not is_file_compliant:
         with open(filename, 'w', encoding='utf-8') as f:
             f.writelines(file_lines)
 
-    return (filename, has_trailing_whitespace, verbose_infos)
-
-
-###########################################################
-# CHECK TABS
-###########################################################
-def check_tabs(filenames: List[str],
-               fix: bool,
-               verbose: bool,
-               n_jobs: int,
-               ) -> bool:
-    """
-    Check / fix tabs in a list of files.
-
-    @param filename Name of the file to be checked.
-    @param fix Whether to fix the file (True) or just check if it has tabs (False).
-    @param verbose Show the lines that are not well-formatted.
-    @param n_jobs Number of parallel jobs.
-    @return True if no files have tabs after the check process.
-            False if there are tabs after the check process.
-    """
-
-    # Check files
-    files_with_tabs: List[str] = []
-    files_verbose_infos: Dict[str, List[str]] = {}
-
-    with concurrent.futures.ProcessPoolExecutor(n_jobs) as executor:
-        files_with_tabs_results = executor.map(
-            check_tabs_file,
-            filenames,
-            itertools.repeat(fix),
-            itertools.repeat(verbose),
-        )
-
-        for (filename, has_tabs, verbose_infos) in files_with_tabs_results:
-            if has_tabs:
-                files_with_tabs.append(filename)
-
-            if verbose:
-                files_verbose_infos[filename] = verbose_infos
-
-    # Output results
-    if not files_with_tabs:
-        print('- No files detected with tabs')
-        return True
-
-    else:
-        n_files_with_tabs = len(files_with_tabs)
-
-        if fix:
-            print(
-                f'- Fixed tabs in the files ({n_files_with_tabs}):')
-        else:
-            print(
-                f'- Detected tabs in the files ({n_files_with_tabs}):')
-
-        for f in files_with_tabs:
-            if verbose:
-                print(*[f'    {l}' for l in files_verbose_infos[f]], sep='\n')
-            else:
-                print(f'    - {f}')
-
-        # If all files were fixed, there are no more trailing whitespace
-        return fix
+    return (filename, is_file_compliant, verbose_infos)
 
 
 def check_tabs_file(filename: str,
@@ -667,12 +615,14 @@
     Check / fix tabs in a file.
 
     @param filename Name of the file to be checked.
-    @param fix Whether to fix the file (True) or just check if it has tabs (False).
-    @param verbose Show the lines that are not well-formatted.
-    @return Tuple [Filename, Whether the file has tabs, Verbose information].
+    @param fix Whether to fix (True) or just check (False) the style of the file (True).
+    @param verbose Show the lines that are not compliant with the style.
+    @return Tuple [Filename,
+                   Whether the file is compliant with the style (before the check),
+                   Verbose information].
     """
 
-    has_tabs = False
+    is_file_compliant = True
     clang_format_enabled = True
 
     verbose_infos: List[str] = []
@@ -697,27 +647,29 @@
         # Check if there are tabs and fix them
         tab_index = line.find('\t')
 
-        if tab_index != -1:
-            has_tabs = True
-            file_lines[i] = line.expandtabs(TAB_SIZE)
+        if tab_index == -1:
+            continue
 
-            if verbose:
-                verbose_infos.extend([
-                    f'{filename}:{i + 1}:{tab_index + 1}: error: Tab detected',
-                    f'    {line.rstrip()}',
-                    f'    {"":{tab_index}}^',
-                ])
-
-            # Optimization: If running in non-verbose check mode, only one error is needed to check that the file is not formatted
-            if not fix and not verbose:
-                break
+        is_file_compliant = False
+        file_lines[i] = line.expandtabs(TAB_SIZE)
+
+        if verbose:
+            verbose_infos.extend([
+                f'{filename}:{i + 1}:{tab_index + 1}: error: Tab detected',
+                f'    {line.rstrip()}',
+                f'    {"":{tab_index}}^',
+            ])
+
+        # Optimization: If running in non-verbose check mode, only one error is needed to check that the file is not compliant
+        if not fix and not verbose:
+            break
 
     # Update file with the fixed lines
-    if fix and has_tabs:
+    if fix and not is_file_compliant:
         with open(filename, 'w', encoding='utf-8') as f:
             f.writelines(file_lines)
 
-    return (filename, has_tabs, verbose_infos)
+    return (filename, is_file_compliant, verbose_infos)
 
 
 ###########################################################
@@ -728,8 +680,9 @@
     parser = argparse.ArgumentParser(
         description='Check and apply the ns-3 coding style to all files in a given PATH. '
         'The script checks the formatting of the file with clang-format. '
-        'Additionally, it checks the presence of trailing whitespace and tabs. '
-        'Formatting and tabs checks respect clang-format guards. '
+        'Additionally, it checks #include headers from the same module with the "ns3/" prefix, '
+        'the presence of trailing whitespace and tabs. '
+        'Formatting, local #include "ns3/" prefixes and tabs checks respect clang-format guards. '
         'When used in "check mode" (default), the script checks if all files are well '
         'formatted and do not have trailing whitespace nor tabs. '
         'If it detects non-formatted files, they will be printed and this process exits with a '
@@ -738,6 +691,9 @@
     parser.add_argument('path', action='store', type=str,
                         help='Path to the files to check')
 
+    parser.add_argument('--no-include-prefixes', action='store_true',
+                        help='Do not check / fix #include headers from the same module with the "ns3/" prefix')
+
     parser.add_argument('--no-formatting', action='store_true',
                         help='Do not check / fix code formatting')
 
@@ -759,8 +715,9 @@
     args = parser.parse_args()
 
     try:
-        check_style(
+        all_checks_successful = check_style_clang_format(
             path=args.path,
+            enable_check_include_prefixes=(not args.no_include_prefixes),
             enable_check_formatting=(not args.no_formatting),
             enable_check_whitespace=(not args.no_whitespace),
             enable_check_tabs=(not args.no_tabs),
@@ -772,3 +729,8 @@
     except Exception as e:
         print(e)
         sys.exit(1)
+
+    if all_checks_successful:
+        sys.exit(0)
+    else:
+        sys.exit(1)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/create-module.py ns-3.40/utils/create-module.py
--- ns-3.39/utils/create-module.py	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils/create-module.py	2023-09-27 13:30:37.934840000 -0700
@@ -336,7 +336,7 @@
     artifact_path = Path(path)
 
     #open file for (w)rite and in (t)ext mode
-    with artifact_path.open("wt") as f:
+    with artifact_path.open("wt", encoding="utf-8") as f:
         f.write(template.format(**kwargs))
 
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/grid.py ns-3.40/utils/grid.py
--- ns-3.39/utils/grid.py	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils/grid.py	2023-09-27 13:30:37.934840000 -0700
@@ -14,7 +14,7 @@
     #  end
     ## @var value
     #  value
-    def __init__(self, start = 0, end = 0, value = ''):
+    def __init__(self, start=0, end=0, value=''):
         """! Initializer
         @param self this object
         @param start start
@@ -30,7 +30,7 @@
     #  at
     ## @var value
     #  value
-    def __init__(self, at = 0, value = ''):
+    def __init__(self, at=0, value=''):
         """! Initializer
         @param self this object
         @param at you
@@ -44,7 +44,7 @@
     #  at
     ## @var value
     #  value
-    def __init__(self, at = 0, value = 0.0):
+    def __init__(self, at=0, value=0.0):
         """! Initializer
         @param self this object
         @param at you
@@ -58,7 +58,7 @@
     #  at
     ## @var value
     #  value
-    def __init__(self, at = 0, value = 0.0):
+    def __init__(self, at=0, value=0.0):
         """! Initializer
         @param self this object
         @param at you
@@ -88,7 +88,7 @@
     #  name
     ## @var ranges
     #  ranges
-    def __init__(self, name = ''):
+    def __init__(self, name=''):
         """! Initializer
         @param self this object
         @param name name
@@ -154,13 +154,13 @@
         s = self.__search(start)
         e = self.__search(end)
         if s == -1 and e == -1:
-            return(0, 0)
+            return (0, 0)
         elif s == -1:
-            return(0, e + 1)
+            return (0, e + 1)
         elif e == -1:
-            return(s, len(self.ranges))
+            return (s, len(self.ranges))
         else:
-            return(s, e + 1)
+            return (s, e + 1)
     def sort(self):
         """! Sort ranges
         @param self this object
@@ -175,16 +175,16 @@
         if len(self.ranges) > 0:
             lo = self.ranges[0].start
             hi = self.ranges[len(self.ranges)-1].end
-            return(lo, hi)
+            return (lo, hi)
         else:
-            return(0, 0)
+            return (0, 0)
 ## TimelineEvent class
 class TimelineEvent:
     ## @var name
     #  name
     ## @var events
     #  events
-    def __init__(self, name = ''):
+    def __init__(self, name=''):
         """! Get ranges bounds
         @param self this object
         @param name name
@@ -235,7 +235,7 @@
         """
         s = self.__search(start)
         e = self.__search(end)
-        return(s, e + 1)
+        return (s, e + 1)
     def sort(self):
         """! Sort function
         @param self this object
@@ -250,9 +250,9 @@
         if len(self.events) > 0:
             lo = self.events[0].at
             hi = self.events[-1].at
-            return(lo, hi)
+            return (lo, hi)
         else:
-            return(0, 0)
+            return (0, 0)
 
 ## Timeline class
 class Timeline:
@@ -264,7 +264,7 @@
     #  event string
     ## @var event_int
     #  event int
-    def __init__(self, name = ''):
+    def __init__(self, name=''):
         """! Initializer
         @param self this object
         @param name name
@@ -363,7 +363,7 @@
                 lo = ev_lo
             if ev_hi > hi:
                 hi = ev_hi
-        return(lo, hi)
+        return (lo, hi)
 
 ## Timelines class
 class Timelines:
@@ -412,7 +412,7 @@
                 lo = t_lo
             if t_hi > hi:
                 hi = t_hi
-        return(lo, hi)
+        return (lo, hi)
     def get_all_range_values(self):
         """! Get All Ranges
         @param self this object
@@ -433,7 +433,7 @@
     #  green
     ## @var b
     #  blue
-    def __init__(self, r = 0.0, g = 0.0, b = 0.0):
+    def __init__(self, r=0.0, g=0.0, b=0.0):
         """! Initializer
         @param self: this object
         @param r: red
@@ -587,8 +587,6 @@
             ctx.show_text(legend)
             i += 1
 
-        return
-
 ## TimelinesRenderer class
 class TimelinesRenderer:
     ## @var padding
@@ -797,7 +795,7 @@
         for timeline in self.timelines.get_all():
             (y_bearing, t_width, t_height) = ctx.text_extents(timeline.name)[1:4]
             ctx.move_to(left_x_start, cur_y + self.max_text_height - (t_height + y_bearing))
-            ctx.show_text(timeline.name);
+            ctx.show_text(timeline.name)
             for events_int in timeline.get_events_int():
                 (y_bearing, t_width, t_height) = ctx.text_extents(events_int.name)[1:4]
                 ctx.move_to(right_x_start, cur_y + self.max_text_height - (t_height + y_bearing))
@@ -830,7 +828,6 @@
                        0, bot_y)
         self.draw_line(ctx, right_x_end + self.padding / 2, 0,
                        0, bot_y)
-        return
 
 ## ScaleRenderer class
 class ScaleRenderer:
@@ -869,7 +866,7 @@
         @param x x
         @return real x
         """
-        real_x = (x - self.__lo ) * self.__width / (self.__hi - self.__lo)
+        real_x = (x - self.__lo) * self.__width / (self.__hi - self.__lo)
         return real_x
     def set_top(self):
         """! Set Top
@@ -899,7 +896,7 @@
             closest *= 10
         if (data_delta / closest) == 0:
             delta = closest
-        elif(data_delta / closest) == 1:
+        elif (data_delta / closest) == 1:
             delta = closest / 10
         else:
             delta = closest
@@ -940,7 +937,7 @@
         ctx.set_line_width(1.0)
         ticks = range(int(start), int(end + delta), int(delta))
         for x in ticks:
-            real_x = (x - self.__lo ) * self.__width / (self.__hi - self.__lo)
+            real_x = (x - self.__lo) * self.__width / (self.__hi - self.__lo)
             ctx.move_to(real_x, 0)
             ctx.line_to(real_x, 5*s)
             ctx.close_path()
@@ -958,7 +955,7 @@
             start = self.__lo - (self.__lo % delta) + delta
             end = self.__hi - (self.__hi % delta)
             for x in range(int(start), int(end + delta), int(delta)):
-                real_x = (x - self.__lo ) * self.__width / (self.__hi - self.__lo)
+                real_x = (x - self.__lo) * self.__width / (self.__hi - self.__lo)
                 ctx.move_to(real_x, 0)
                 ctx.line_to(real_x, 3*s)
                 ctx.close_path()
@@ -1024,7 +1021,7 @@
         """
         y_start = self.__top_legend.get_height()
         x_start = self.__data.get_data_x_start()
-        return(x_start, y_start, self.__width - x_start, self.__data.get_height())
+        return (x_start, y_start, self.__width - x_start, self.__data.get_height())
     def scale_data(self, x):
         """! Get Data Rectangle
         @param self this object
@@ -1044,7 +1041,7 @@
         y_height = self.__bot_scale.get_height() + 20
         x_start = self.__bot_scale.get_position(self.__r_start)
         x_end = self.__bot_scale.get_position(self.__r_end)
-        return(x_start, y_start, x_end - x_start, y_height)
+        return (x_start, y_start, x_end - x_start, y_height)
     def scale_selection(self, x):
         """! Scale Selection
         @param self this object
@@ -1074,7 +1071,7 @@
         @param self this object
         @return range
         """
-        return(self.__r_start, self.__r_end)
+        return (self.__r_start, self.__r_end)
     def set_data(self, data):
         """! Set Date
         @param self this object
@@ -1144,14 +1141,14 @@
         # data
         ctx.save()
         ctx.translate(0,
-                       top_legend_height)
+                      top_legend_height)
         self.__data.draw(ctx)
         ctx.restore()
 
         # scale below data
         ctx.save()
         ctx.translate(self.__data.get_data_x_start(),
-                       top_legend_height + self.__data.get_height() + self.__mid_scale.get_height())
+                      top_legend_height + self.__data.get_height() + self.__mid_scale.get_height())
         self.__mid_scale.draw(ctx)
         ctx.restore()
 
@@ -1177,7 +1174,7 @@
         select_end = self.__bot_scale.get_position(self.__r_end)
 
         # left connection between top scale and bottom scale
-        ctx.move_to(0, height_used);
+        ctx.move_to(0, height_used)
         ctx.line_to(self.__data.get_data_x_start(), height_used)
         ctx.line_to(select_start, height_used + 20)
         ctx.line_to(0, height_used + 20)
@@ -1206,12 +1203,12 @@
         unused_end = self.__bot_scale.get_position(self.__r_end)
         unused_height = self.__bot_scale.get_height() + 20
         ctx.rectangle(0, height_used,
-                       unused_start,
-                       unused_height)
+                      unused_start,
+                      unused_height)
         ctx.rectangle(unused_end,
-                       height_used,
-                       self.__width - unused_end,
-                       unused_height)
+                      height_used,
+                      self.__width - unused_end,
+                      unused_height)
         ctx.set_source_rgb(0.9, 0.9, 0.9)
         ctx.fill()
 
@@ -1584,7 +1581,6 @@
         dialog.set_default_response(1)
         dialog.connect("response", self.__dialog_response_cb)
         dialog.show()
-        return
     def __dialog_response_cb(self, widget, response):
         """! Dialog Response Callback
         @param self this object
@@ -1596,7 +1592,6 @@
             filename = self.__dialog.get_filename()
             self.__render.output_png(filename)
             widget.hide()
-        return
 
 
 ## read_data function
@@ -1608,7 +1603,7 @@
     m3 = re.compile('event-int ([^ ]+) ([^ ]+) ([0-9]+) ([0-9]+)')
     m4 = re.compile('color ([^ ]+) #([a-fA-F0-9]{2,2})([a-fA-F0-9]{2,2})([a-fA-F0-9]{2,2})')
 
-    with open(filename) as fh:
+    with open(filename, encoding='utf-8') as fh:
         for line in fh.readlines():
             m = m1.match(line)
             if m:
@@ -1654,7 +1649,6 @@
     return (colors, timelines)
 
 
-
 def main():
     (colors, timelines) = read_data(sys.argv[1])
     (lower_bound, upper_bound) = timelines.get_bounds()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/.ns3rc ns-3.40/utils/.ns3rc
--- ns-3.39/utils/.ns3rc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils/.ns3rc	2023-09-27 13:30:37.934840000 -0700
@@ -2,6 +2,8 @@
 # Modules that depend on the listed modules will be enabled also.
 #
 # All modules can be enabled by emptying the list.
+# To list modules, append the modules separated by space or semicolon; e.g.:
+# set(ns3rc_enabled_modules core propagation)
 set(ns3rc_enabled_modules)
 
 # A list of the modules that will be disabled when ns-3 is run.
@@ -18,4 +20,4 @@
 
 # Override other ns-3 settings by setting their values below
 # Note: command-line settings will also be overridden.
-#set(NS3_LOG ON)
\ No newline at end of file
+#set(NS3_LOG ON)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/print-introspected-doxygen.cc ns-3.40/utils/print-introspected-doxygen.cc
--- ns-3.39/utils/print-introspected-doxygen.cc	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils/print-introspected-doxygen.cc	2023-09-27 13:30:37.934840000 -0700
@@ -456,8 +456,7 @@
     for (uint32_t i = 0; i < tid.GetAttributeN(); ++i)
     {
         struct TypeId::AttributeInformation info = tid.GetAttribute(i);
-        const PointerChecker* ptrChecker =
-            dynamic_cast<const PointerChecker*>(PeekPointer(info.checker));
+        const auto ptrChecker = dynamic_cast<const PointerChecker*>(PeekPointer(info.checker));
         if (ptrChecker != nullptr)
         {
             TypeId pointee = ptrChecker->GetPointeeTypeId();
@@ -482,7 +481,7 @@
             continue;
         }
         // attempt to cast to an object vector.
-        const ObjectPtrContainerChecker* vectorChecker =
+        const auto vectorChecker =
             dynamic_cast<const ObjectPtrContainerChecker*>(PeekPointer(info.checker));
         if (vectorChecker != nullptr)
         {
@@ -723,7 +722,7 @@
                 // Indirect cases to handle
                 if (valType == "ns3::PointerValue")
                 {
-                    const PointerChecker* ptrChecker =
+                    const auto ptrChecker =
                         dynamic_cast<const PointerChecker*>(PeekPointer(info.checker));
                     if (ptrChecker != nullptr)
                     {
@@ -734,7 +733,7 @@
                 }
                 else if (valType == "ns3::ObjectPtrContainerValue")
                 {
-                    const ObjectPtrContainerChecker* ptrChecker =
+                    const auto ptrChecker =
                         dynamic_cast<const ObjectPtrContainerChecker*>(PeekPointer(info.checker));
                     if (ptrChecker != nullptr)
                     {
@@ -1071,7 +1070,7 @@
        << "See ns3::GlobalValue for how to set these." << std::endl;
 
     os << listStart << std::endl;
-    for (GlobalValue::Iterator i = GlobalValue::Begin(); i != GlobalValue::End(); ++i)
+    for (auto i = GlobalValue::Begin(); i != GlobalValue::End(); ++i)
     {
         StringValue val;
         (*i)->GetValue(val);
@@ -1127,7 +1126,6 @@
     os << tLeft << ":" << std::string(widthL - 1, '-') << tMid << ":"
        << std::string(widthR - 1, '-') << tRight << std::endl;
 
-    LogComponent::ComponentList::const_iterator it;
     for (const auto& it : (*logs))
     {
         std::string file = it.second->File();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/gitlab-ci-clang.yml ns-3.40/utils/tests/gitlab-ci-clang.yml
--- ns-3.39/utils/tests/gitlab-ci-clang.yml	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils/tests/gitlab-ci-clang.yml	2023-09-27 13:30:37.934840000 -0700
@@ -4,12 +4,11 @@
 # "RELEASE", that has a value "weekly". Also, a variable "CLANG" should be set
 # to True.
 
-# We support CLANG 6, 8, 9, 10, 11, 12, 13, 14
-# We test only CLANG 6 and 10 on Ubuntu 18.04, and 11 and 14 on Ubuntu 22.04
-# The test is done under Linux.
+# We support CLANG versions 10 through 16
+# We test only CLANG 10 on Ubuntu 20.04 and CLANG 16 on Ubuntu 23.04
 
-.weekly-clang-ubuntu18.04:
-  image: ubuntu:18.04
+.weekly-clang-ubuntu20.04:
+  image: ubuntu:20.04
   extends: .base-build
   rules:
     - if: $RELEASE == "weekly"
@@ -18,7 +17,7 @@
   before_script:
     - apt update
     - apt upgrade -y
-    - apt install -y
+    - DEBIAN_FRONTEND=noninteractive apt install -y
       clang-$CLANG cmake ninja-build ccache build-essential
       libboost-all-dev
       libeigen3-dev
@@ -31,8 +30,8 @@
     COMPILER: clang++-$CLANG
     LIBGSL: libgsl23
 
-.weekly-clang-ubuntu22.04:
-  image: ubuntu:22.04
+.weekly-clang-ubuntu23.04:
+  image: ubuntu:23.04
   extends: .base-build
   rules:
     - if: $RELEASE == "weekly"
@@ -41,7 +40,7 @@
   before_script:
     - apt update
     - apt upgrade -y
-    - apt install -y
+    - DEBIAN_FRONTEND=noninteractive apt install -y
       clang-$CLANG cmake ninja-build ccache build-essential
       libboost-all-dev
       libeigen3-dev
@@ -64,54 +63,9 @@
   script:
     - echo "Starting clang jobs"
 
-# CLANG 6
-weekly-build-clang-6-debug:
-  extends: .weekly-clang-ubuntu18.04
-  needs: ["weekly-clang"]
-  stage: build
-  variables:
-    CLANG: "6.0"
-    MODE: debug
-
-weekly-build-clang-6-default:
-  extends: .weekly-clang-ubuntu18.04
-  needs: ["weekly-clang"]
-  stage: build
-  variables:
-    CLANG: "6.0"
-    MODE: default
-
-weekly-build-clang-6-optimized:
-  extends: .weekly-clang-ubuntu18.04
-  needs: ["weekly-clang"]
-  stage: build
-  variables:
-    CLANG: "6.0"
-    MODE: optimized
-
-weekly-test-clang-6-default:
-  extends: .weekly-clang-ubuntu18.04
-  stage: test
-  needs: ["weekly-build-clang-6-default"]
-  dependencies:
-    - weekly-build-clang-6-default
-  variables:
-    CLANG: "6.0"
-    MODE: default
-
-weekly-test-clang-6-optimized:
-  extends: .weekly-clang-ubuntu18.04
-  stage: test
-  needs: ["weekly-build-clang-6-optimized"]
-  dependencies:
-    - weekly-build-clang-6-optimized
-  variables:
-    CLANG: "6.0"
-    MODE: optimized
-
 # CLANG 10
 weekly-build-clang-10-debug:
-  extends: .weekly-clang-ubuntu18.04
+  extends: .weekly-clang-ubuntu20.04
   needs: ["weekly-clang"]
   stage: build
   variables:
@@ -119,7 +73,7 @@
     MODE: debug
 
 weekly-build-clang-10-default:
-  extends: .weekly-clang-ubuntu18.04
+  extends: .weekly-clang-ubuntu20.04
   needs: ["weekly-clang"]
   stage: build
   variables:
@@ -127,7 +81,7 @@
     MODE: default
 
 weekly-build-clang-10-optimized:
-  extends: .weekly-clang-ubuntu18.04
+  extends: .weekly-clang-ubuntu20.04
   needs: ["weekly-clang"]
   stage: build
   variables:
@@ -135,7 +89,7 @@
     MODE: optimized
 
 weekly-test-clang-10-default:
-  extends: .weekly-clang-ubuntu18.04
+  extends: .weekly-clang-ubuntu20.04
   stage: test
   needs: ["weekly-build-clang-10-default"]
   dependencies:
@@ -145,7 +99,7 @@
     MODE: default
 
 weekly-test-clang-10-optimized:
-  extends: .weekly-clang-ubuntu18.04
+  extends: .weekly-clang-ubuntu20.04
   stage: test
   needs: ["weekly-build-clang-10-optimized"]
   dependencies:
@@ -154,92 +108,47 @@
     CLANG: 10
     MODE: optimized
 
-# CLANG 11
-weekly-build-clang-11-debug:
-  extends: .weekly-clang-ubuntu22.04
-  needs: ["weekly-clang"]
-  stage: build
-  variables:
-    CLANG: 11
-    MODE: debug
-
-weekly-build-clang-11-default:
-  extends: .weekly-clang-ubuntu22.04
-  needs: ["weekly-clang"]
-  stage: build
-  variables:
-    CLANG: 11
-    MODE: default
-
-weekly-build-clang-11-optimized:
-  extends: .weekly-clang-ubuntu22.04
-  needs: ["weekly-clang"]
-  stage: build
-  variables:
-    CLANG: 11
-    MODE: optimized
-
-weekly-test-clang-11-default:
-  extends: .weekly-clang-ubuntu22.04
-  stage: test
-  needs: ["weekly-build-clang-11-default"]
-  dependencies:
-    - weekly-build-clang-11-default
-  variables:
-    CLANG: 11
-    MODE: default
-
-weekly-test-clang-11-optimized:
-  extends: .weekly-clang-ubuntu22.04
-  stage: test
-  needs: ["weekly-build-clang-11-optimized"]
-  dependencies:
-    - weekly-build-clang-11-optimized
-  variables:
-    CLANG: 11
-    MODE: optimized
-
-# CLANG 14
-weekly-build-clang-14-debug:
-  extends: .weekly-clang-ubuntu22.04
+# CLANG 16
+weekly-build-clang-16-debug:
+  extends: .weekly-clang-ubuntu23.04
   needs: ["weekly-clang"]
   stage: build
   variables:
-    CLANG: 14
+    CLANG: 16
     MODE: debug
 
-weekly-build-clang-14-default:
-  extends: .weekly-clang-ubuntu22.04
+weekly-build-clang-16-default:
+  extends: .weekly-clang-ubuntu23.04
   needs: ["weekly-clang"]
   stage: build
   variables:
-    CLANG: 14
+    CLANG: 16
     MODE: default
 
-weekly-build-clang-14-optimized:
-  extends: .weekly-clang-ubuntu22.04
+weekly-build-clang-16-optimized:
+  extends: .weekly-clang-ubuntu23.04
   needs: ["weekly-clang"]
   stage: build
   variables:
-    CLANG: 14
+    CLANG: 16
     MODE: optimized
 
-weekly-test-clang-14-default:
-  extends: .weekly-clang-ubuntu22.04
+weekly-test-clang-16-default:
+  extends: .weekly-clang-ubuntu23.04
   stage: test
-  needs: ["weekly-build-clang-14-default"]
+  needs: ["weekly-build-clang-16-default"]
   dependencies:
-    - weekly-build-clang-14-default
+    - weekly-build-clang-16-default
   variables:
-    CLANG: 14
+    CLANG: 16
     MODE: default
 
-weekly-test-clang-14-optimized:
-  extends: .weekly-clang-ubuntu22.04
+weekly-test-clang-16-optimized:
+  extends: .weekly-clang-ubuntu23.04
   stage: test
-  needs: ["weekly-build-clang-14-optimized"]
+  needs: ["weekly-build-clang-16-optimized"]
   dependencies:
-    - weekly-build-clang-14-optimized
+    - weekly-build-clang-16-optimized
   variables:
-    CLANG: 14
+    CLANG: 16
     MODE: optimized
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/gitlab-ci-code-linting.yml ns-3.40/utils/tests/gitlab-ci-code-linting.yml
--- ns-3.39/utils/tests/gitlab-ci-code-linting.yml	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils/tests/gitlab-ci-code-linting.yml	2023-09-27 13:30:37.934840000 -0700
@@ -15,20 +15,20 @@
     - python3 utils/check-style-clang-format.py --verbose .
   timeout: 1h
 
-check-style-clang-format-14:
+check-style-clang-format-16:
   extends: .check-style-clang-format
   variables:
-    CLANG_FORMAT_VERSION: 14
+    CLANG_FORMAT_VERSION: 16
 
 check-style-clang-format-15:
   extends: .check-style-clang-format
   variables:
     CLANG_FORMAT_VERSION: 15
 
-check-style-clang-format-16:
+check-style-clang-format-14:
   extends: .check-style-clang-format
   variables:
-    CLANG_FORMAT_VERSION: 16
+    CLANG_FORMAT_VERSION: 14
 
 # Clang-tidy
 clang-tidy-16:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/gitlab-ci-cppyy.yml ns-3.40/utils/tests/gitlab-ci-cppyy.yml
--- ns-3.39/utils/tests/gitlab-ci-cppyy.yml	2023-07-05 14:23:48.141428500 -0700
+++ ns-3.40/utils/tests/gitlab-ci-cppyy.yml	2023-09-27 13:30:37.934840000 -0700
@@ -3,12 +3,10 @@
   image: ubuntu:22.04 # python 3.10
   rules:
     - if: $RELEASE == "weekly"
+    - if: $RELEASE == "daily"
+    - if: $RELEASE == "manual"
     - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-  needs: ["weekly-slow-jobs"]
   dependencies: []
-  tags:
-    - nsnam
-    - linux
   before_script:
     - apt update
     - DEBIAN_FRONTEND=noninteractive apt install -y
@@ -40,9 +38,6 @@
   image: ubuntu:20.04 # python 3.8
   rules:
     - if: $RELEASE == "manual"
-  tags:
-    - nsnam
-    - linux
   before_script:
     - apt update
     - DEBIAN_FRONTEND=noninteractive apt install -y
@@ -60,35 +55,6 @@
     - ./ns3 run ./utils/python-unit-tests.py
   timeout: 9h
 
-cppyy-18.04:
-  stage: test
-  image: ubuntu:18.04 # python 3.6
-  rules:
-    - if: $RELEASE == "manual"
-  tags:
-    - nsnam
-    - linux
-  before_script:
-    - apt update
-    - apt install -y software-properties-common
-    - add-apt-repository ppa:ubuntu-toolchain-r/test -y
-    - apt update
-    - DEBIAN_FRONTEND=noninteractive apt install -y
-      g++-9 gcc-9 cmake ninja-build ccache libclang-dev llvm-dev
-      python3 python3-pip
-      libboost-dev libgsl-dev libgtk-3-dev
-      git wget
-    - update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 800 --slave /usr/bin/g++ g++ /usr/bin/g++-9
-    - pip3 install cppyy-cling cppyy-backend CPyCppyy cppyy # older python version may install dependencies in the wrong order
-  script:
-    - CXX=g++-9 ./ns3 configure -G Ninja --enable-python-bindings
-    - ./ns3 build
-    - ./ns3 run first.py
-    - ./ns3 run second.py
-    - ./ns3 run third.py
-    - ./ns3 run ./utils/python-unit-tests.py
-  timeout: 9h
-
 .manylinux-pip-wheel:
   stage: test
   image: quay.io/pypa/manylinux_2_28_x86_64
@@ -104,16 +70,16 @@
     - $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 wheel --upgrade
-    - $PYTHON -m pip install wheel auditwheel cmake-build-extension cppyy==2.4.2
+    - 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
     # Configure and build wheel
-    - $PYTHON setup.py bdist_wheel build_ext
-    - export EXCLUDE_INTERNAL_LIBRARIES=`$PYTHON ./build-support/pip-wheel/auditwheel-exclude-list.py`
+    - python setup.py bdist_wheel build_ext
+    - 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
+    - python -m auditwheel repair ./dist/*whl -L /lib64 $EXCLUDE_INTERNAL_LIBRARIES
     # Clean the build directory
-    - $PYTHON ./ns3 clean
+    - python ./ns3 clean
     # Clean up the environment
     - deactivate
     - rm -R ./venv
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/gitlab-ci-daily.yml ns-3.40/utils/tests/gitlab-ci-daily.yml
--- ns-3.39/utils/tests/gitlab-ci-daily.yml	2023-07-05 14:23:48.141428500 -0700
+++ ns-3.40/utils/tests/gitlab-ci-daily.yml	1969-12-31 16:00:00.000000000 -0800
@@ -1,218 +0,0 @@
-# NS3 CI script for testing
-
-# Defines the steps to run the tests
-# Inherit with "extends: .base-test" and remember to set
-# the following variables: COMPILER (g++, clang++, ...) and
-# MODE (debug, default, optimized)
-
-.base-test:
-  image: archlinux
-  before_script:
-    # add the core-debug repo to pacman.conf
-    - printf "\n%s\n%s\n" "[core-debug]" "Include = /etc/pacman.d/mirrorlist" >> /etc/pacman.conf
-    - pacman-key --init
-    - pacman -Syu --noconfirm
-      base-devel cmake ninja ccache valgrind
-      python
-      boost gsl gtk3
-      glibc-debug
-  script:
-    - mkdir -p $CCACHE_BASEDIR_VALUE
-    - export CCACHE_BASEDIR=${PWD}
-    - export CCACHE_DIR=${PWD}/$CCACHE_BASEDIR_VALUE
-    # missing the flag --disable-python
-    - ./ns3 configure -d $MODE -GNinja --enable-examples --enable-tests --disable-gtk
-    - if [[ "$CI_JOB_STAGE" == "build" ]];
-      then ./ns3 build;
-      fi
-    - if [[ "$CI_JOB_STAGE" == "test" ]] || [[ "$FORCE_TESTS" == "Force" ]];
-      then ./test.py -n $VALGRIND_FLAG $FULLNESS;
-      fi
-  cache:
-    key: "ccache-$CI_JOB_NAME"
-    paths:
-      - $CCACHE_BASEDIR_VALUE/
-  variables:
-    COMPILER: g++
-    CCACHE_BASEDIR_VALUE: ns-3-ccache-storage
-    VALGRIND_FLAG: ""
-    FULLNESS: ""
-    # workaround for Valgrind on Archlinux https://bbs.archlinux.org/viewtopic.php?pid=2036171#p2036171
-    DEBUGINFOD_URLS: "https://debuginfod.archlinux.org"
-
-daily-jobs:
-  rules:
-    - if: $RELEASE == "daily"
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-      when: manual
-      allow_failure: true
-  stage: pre-build
-  script:
-    - echo "Starting daily jobs"
-
-weekly-slow-jobs:
-  rules:
-    - if: $RELEASE == "weekly"
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-      when: manual
-      allow_failure: true
-  stage: pre-build
-  script:
-    - echo "Starting weekly jobs"
-
-# Run the test.py script with files compiled in debug mode
-daily-build-test-debug:
-  extends: .base-test
-  rules:
-    - if: $RELEASE == "daily"
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-      allow_failure: true
-  needs: ["daily-jobs"]
-  dependencies: []
-  stage: build
-  variables:
-    MODE: debug
-  tags:
-    - nsnam
-    - linux
-
-# Run the test.py script with files compiled in default mode
-daily-build-default:
-  extends: .base-test
-  rules:
-    - if: $RELEASE == "daily"
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-      allow_failure: true
-  stage: build
-  needs: ["daily-jobs"]
-  variables:
-    MODE: default
-
-daily-test-default:
-  extends: .base-test
-  rules:
-    - if: $RELEASE == "daily"
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-      allow_failure: true
-  stage: test
-  needs: ["daily-build-default"]
-  dependencies:
-    - daily-build-default
-  variables:
-    MODE: default
-
-# Run the test.py script with files compiled in optimized mode
-daily-build-optimized:
-  extends: .base-test
-  rules:
-    - if: $RELEASE == "daily"
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-      allow_failure: true
-  stage: build
-  needs: ["daily-jobs"]
-  variables:
-    MODE: optimized
-
-daily-test-optimized:
-  extends: .base-test
-  rules:
-    - if: $RELEASE == "daily"
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-      allow_failure: true
-  stage: test
-  needs: ["daily-build-optimized"]
-  dependencies:
-    - daily-build-optimized
-  variables:
-    MODE: optimized
-
-### Valgrind tests
-# Run the test.py script with files compiled in optimized mode + valgrind (daily)
-daily-build-test-optimized-valgrind:
-  extends: .base-test
-  rules:
-    - if: $RELEASE == "daily"
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-      allow_failure: true
-  stage: build
-  needs: ["daily-jobs"]
-  dependencies: []
-  variables:
-    MODE: optimized
-    VALGRIND_FLAG: -g
-    FORCE_TESTS: Force
-  tags:
-    - nsnam
-    - linux
-
-# Run the test.py script with files compiled in debug mode
-weekly-build-test-debug-valgrind:
-  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: debug
-    VALGRIND_FLAG: -g
-    FORCE_TESTS: Force
-  tags:
-    - nsnam
-    - linux
-
-# Run the test.py script with files compiled in default mode
-weekly-build-test-default-valgrind:
-  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: default
-    VALGRIND_FLAG: -g
-    FORCE_TESTS: Force
-  tags:
-    - nsnam
-    - linux
-
-# Run the test.py script with files compiled in optimized mode
-weekly-build-test-optimized-valgrind:
-  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
-    VALGRIND_FLAG: -g
-    FORCE_TESTS: Force
-  tags:
-    - nsnam
-    - linux
-
-# Do a check for the TAKES_FOREVER jobs, only in optimized mode
-weekly-build-test-takes-forever-optimized:
-  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
-    FULLNESS: "-f TAKES_FOREVER"
-    FORCE_TESTS: Force
-  tags:
-    - nsnam
-    - linux
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/gitlab-ci-gcc.yml ns-3.40/utils/tests/gitlab-ci-gcc.yml
--- ns-3.39/utils/tests/gitlab-ci-gcc.yml	2023-07-05 14:23:48.141428500 -0700
+++ ns-3.40/utils/tests/gitlab-ci-gcc.yml	2023-09-27 13:30:37.934840000 -0700
@@ -4,8 +4,16 @@
 # "RELEASE", that has a value "weekly". Also, a variable "GCC" should be set
 # to True.
 
-# We support from 8 to the latest version. Check if everything builds fine
+# We support from 9 to the latest version. Check if everything builds fine
 # under debug, default, and optimized, on Linux.
+# The distro used is Ubuntu - the logic is:
+# - Test minimum and maximum GCC version
+# - Do not test if it's the default version installed (already tested as Ubuntu test)
+# Note: the following is the list of default gcc versions on Ubuntu:
+# - focal (20.04LTS) 9
+# - jammy (22.04LTS) 11
+# - kinetic (22.10) 12
+# - lunar (23.04) 12
 
 .weekly-gcc-base:
   extends: .base-build
@@ -42,277 +50,116 @@
   script:
     - echo "Starting GCC jobs"
 
-# GCC 8
-weekly-build-gcc-8-debug:
-  extends: .weekly-gcc-base
-  needs: ["weekly-gcc"]
-  image: ubuntu:20.04
-  stage: build
-  variables:
-    MODE: debug
-    COMPILER: g++-8
-    LIBGSL: libgsl23
-
-weekly-build-gcc-8-default:
-  extends: .weekly-gcc-base
-  needs: ["weekly-gcc"]
-  image: ubuntu:20.04
-  stage: build
-  variables:
-    MODE: default
-    COMPILER: g++-8
-    LIBGSL: libgsl23
-
-weekly-build-gcc-8-optimized:
-  extends: .weekly-gcc-base
-  needs: ["weekly-gcc"]
-  image: ubuntu:20.04
-  stage: build
-  variables:
-    MODE: optimized
-    COMPILER: g++-8
-    LIBGSL: libgsl23
-
-weekly-test-gcc-8-default:
-  extends: .weekly-gcc-base
-  image: ubuntu:20.04
-  stage: test
-  needs: ["weekly-build-gcc-8-default"]
-  dependencies:
-    - weekly-build-gcc-8-default
-  variables:
-    MODE: default
-    COMPILER: g++-8
-    LIBGSL: libgsl23
-
-weekly-test-gcc-8-optimized:
-  extends: .weekly-gcc-base
-  image: ubuntu:20.04
-  stage: test
-  needs: ["weekly-build-gcc-8-optimized"]
-  dependencies:
-    - weekly-build-gcc-8-optimized
-  variables:
-    MODE: optimized
-    COMPILER: g++-8
-    LIBGSL: libgsl23
-
-# GCC 9
-weekly-build-gcc-9-debug:
-  extends: .weekly-gcc-base
-  needs: ["weekly-gcc"]
-  image: ubuntu:20.04
-  stage: build
-  variables:
-    MODE: debug
-    COMPILER: g++-9
-    LIBGSL: libgsl23
-
-weekly-build-gcc-9-default:
-  extends: .weekly-gcc-base
-  needs: ["weekly-gcc"]
-  image: ubuntu:20.04
-  stage: build
-  variables:
-    MODE: default
-    COMPILER: g++-9
-    LIBGSL: libgsl23
-
-weekly-build-gcc-9-optimized:
-  extends: .weekly-gcc-base
-  needs: ["weekly-gcc"]
-  image: ubuntu:20.04
-  stage: build
-  variables:
-    MODE: optimized
-    COMPILER: g++-9
-    LIBGSL: libgsl23
-
-weekly-test-gcc-9-default:
-  extends: .weekly-gcc-base
-  image: ubuntu:20.04
-  stage: test
-  needs: ["weekly-build-gcc-9-default"]
-  dependencies:
-    - weekly-build-gcc-9-default
-  variables:
-    MODE: default
-    COMPILER: g++-9
-    LIBGSL: libgsl23
-
-weekly-test-gcc-9-optimized:
-  extends: .weekly-gcc-base
-  image: ubuntu:20.04
-  stage: test
-  needs: ["weekly-build-gcc-9-optimized"]
-  dependencies:
-    - weekly-build-gcc-9-optimized
-  variables:
-    MODE: optimized
-    COMPILER: g++-9
-    LIBGSL: libgsl23
-
-# GCC 10
-# weekly-build-gcc-10-debug:
+# GCC 9 (not tested as it's the default for Ubuntu 20.04)
+# weekly-build-gcc-9-debug:
 #   extends: .weekly-gcc-base
 #   needs: ["weekly-gcc"]
 #   image: ubuntu:20.04
 #   stage: build
 #   variables:
 #     MODE: debug
-#     COMPILER: g++-10
+#     COMPILER: g++-9
 #     LIBGSL: libgsl23
 
-# weekly-build-gcc-10-default:
+# weekly-build-gcc-9-default:
 #   extends: .weekly-gcc-base
 #   needs: ["weekly-gcc"]
 #   image: ubuntu:20.04
 #   stage: build
 #   variables:
 #     MODE: default
-#     COMPILER: g++-10
+#     COMPILER: g++-9
 #     LIBGSL: libgsl23
 
-# weekly-build-gcc-10-optimized:
+# weekly-build-gcc-9-optimized:
 #   extends: .weekly-gcc-base
 #   needs: ["weekly-gcc"]
 #   image: ubuntu:20.04
 #   stage: build
 #   variables:
 #     MODE: optimized
-#     COMPILER: g++-10
+#     COMPILER: g++-9
 #     LIBGSL: libgsl23
 
-# weekly-test-gcc-10-default:
+# weekly-test-gcc-9-default:
 #   extends: .weekly-gcc-base
 #   image: ubuntu:20.04
 #   stage: test
-#   needs: ["weekly-build-gcc-10-default"]
+#   needs: ["weekly-build-gcc-9-default"]
 #   dependencies:
-#     - weekly-build-gcc-10-default
+#     - weekly-build-gcc-9-default
 #   variables:
 #     MODE: default
-#     COMPILER: g++-10
+#     COMPILER: g++-9
 #     LIBGSL: libgsl23
 
-# weekly-test-gcc-10-optimized:
+# weekly-test-gcc-9-optimized:
 #   extends: .weekly-gcc-base
 #   image: ubuntu:20.04
 #   stage: test
-#   needs: ["weekly-build-gcc-10-optimized"]
+#   needs: ["weekly-build-gcc-9-optimized"]
 #   dependencies:
-#     - weekly-build-gcc-10-optimized
+#     - weekly-build-gcc-9-optimized
 #   variables:
 #     MODE: optimized
-#     COMPILER: g++-10
+#     COMPILER: g++-9
 #     LIBGSL: libgsl23
 
-# GCC 11
-# weekly-build-gcc-11-debug:
-#   extends: .weekly-gcc-base
-#   needs: ["weekly-gcc"]
-#   image: ubuntu:22.04
-#   stage: build
-#   variables:
-#     MODE: debug
-#     COMPILER: g++-11
-#     LIBGSL: libgsl27
-
-# weekly-build-gcc-11-default:
-#   extends: .weekly-gcc-base
-#   needs: ["weekly-gcc"]
-#   image: ubuntu:22.04
-#   stage: build
-#   variables:
-#     MODE: default
-#     COMPILER: g++-11
-#     LIBGSL: libgsl27
-
-# weekly-build-gcc-11-optimized:
-#   extends: .weekly-gcc-base
-#   needs: ["weekly-gcc"]
-#   image: ubuntu:22.04
-#   stage: build
-#   variables:
-#     MODE: optimized
-#     COMPILER: g++-11
-#     LIBGSL: libgsl27
-
-# weekly-test-gcc-11-default:
-#   extends: .weekly-gcc-base
-#   image: ubuntu:22.04
-#   stage: test
-#   needs: ["weekly-build-gcc-11-default"]
-#   dependencies:
-#     - weekly-build-gcc-11-default
-#   variables:
-#     MODE: default
-#     COMPILER: g++-11
-#     LIBGSL: libgsl27
-
-# weekly-test-gcc-11-optimized:
-#   extends: .weekly-gcc-base
-#   image: ubuntu:22.04
-#   stage: test
-#   needs: ["weekly-build-gcc-11-optimized"]
-#   dependencies:
-#     - weekly-build-gcc-11-optimized
-#   variables:
-#     MODE: optimized
-#     COMPILER: g++-11
-#     LIBGSL: libgsl27
-
-# GCC 12
-weekly-build-gcc-12-debug:
+# GCC 13
+weekly-build-gcc-13-debug:
   extends: .weekly-gcc-base
   needs: ["weekly-gcc"]
-  image: ubuntu:22.04
+  image: ubuntu:23.04
   stage: build
   variables:
     MODE: debug
-    COMPILER: g++-12
+    COMPILER: g++-13
     LIBGSL: libgsl27
 
-weekly-build-gcc-12-default:
+weekly-build-gcc-13-default:
   extends: .weekly-gcc-base
   needs: ["weekly-gcc"]
-  image: ubuntu:22.04
+  image: ubuntu:23.04
   stage: build
   variables:
     MODE: default
-    COMPILER: g++-12
+    COMPILER: g++-13
     LIBGSL: libgsl27
 
-weekly-build-gcc-12-optimized:
+# Aug. 26, 2023: --disable-eigen is needed to prevent a -Werror=unused-variable
+weekly-build-gcc-13-optimized:
   extends: .weekly-gcc-base
   needs: ["weekly-gcc"]
-  image: ubuntu:22.04
+  image: ubuntu:23.04
   stage: build
   variables:
     MODE: optimized
-    COMPILER: g++-12
+    COMPILER: g++-13
     LIBGSL: libgsl27
+    EXTRA_OPTIONS: --disable-eigen
 
-weekly-test-gcc-12-default:
+weekly-test-gcc-13-default:
   extends: .weekly-gcc-base
-  image: ubuntu:22.04
+  image: ubuntu:23.04
   stage: test
-  needs: ["weekly-build-gcc-12-default"]
+  needs: ["weekly-build-gcc-13-default"]
   dependencies:
-    - weekly-build-gcc-12-default
+    - weekly-build-gcc-13-default
   variables:
     MODE: default
-    COMPILER: g++-12
+    COMPILER: g++-13
     LIBGSL: libgsl27
 
-weekly-test-gcc-12-optimized:
+# Aug. 26, 2023: --disable-eigen is needed to prevent a -Werror=unused-variable
+weekly-test-gcc-13-optimized:
   extends: .weekly-gcc-base
-  image: ubuntu:22.04
+  image: ubuntu:23.04
   stage: test
-  needs: ["weekly-build-gcc-12-optimized"]
+  needs: ["weekly-build-gcc-13-optimized"]
   dependencies:
-    - weekly-build-gcc-12-optimized
+    - weekly-build-gcc-13-optimized
   variables:
     MODE: optimized
-    COMPILER: g++-12
+    COMPILER: g++-13
     LIBGSL: libgsl27
+    EXTRA_OPTIONS: --disable-eigen
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/gitlab-ci-per-commit.yml ns-3.40/utils/tests/gitlab-ci-per-commit.yml
--- ns-3.39/utils/tests/gitlab-ci-per-commit.yml	2023-07-05 14:23:48.141428500 -0700
+++ ns-3.40/utils/tests/gitlab-ci-per-commit.yml	2023-09-27 13:30:37.934840000 -0700
@@ -20,6 +20,7 @@
   variables:
     ENABLE_MPI: --enable-mpi
 
+# Build stage
 per-commit-clang-debug:
   extends: .base-per-commit-compile
   stage: build
@@ -48,6 +49,23 @@
     MODE: optimized
     COMPILER: g++
 
+per-commit-disabled-precompiled-headers:
+  extends: .base-per-commit-compile
+  stage: build
+  variables:
+    MODE: debug
+    COMPILER: g++
+    EXTRA_OPTIONS: --disable-precompiled-headers
+
+per-commit-disabled-asserts:
+  extends: .base-per-commit-compile
+  stage: build
+  variables:
+    MODE: debug
+    COMPILER: g++
+    EXTRA_OPTIONS: --disable-asserts
+
+# Test stage
 per-commit-gcc-default-test:
   extends: .base-per-commit-compile
   stage: test
@@ -67,11 +85,3 @@
   variables:
     MODE: optimized
     COMPILER: g++
-
-per-commit-disabled-precompiled-headers:
-  extends: .base-per-commit-compile
-  stage: build
-  variables:
-    MODE: debug
-    COMPILER: g++
-    EXTRA_OPTIONS: --disable-precompiled-headers
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/gitlab-ci-scheduled.yml ns-3.40/utils/tests/gitlab-ci-scheduled.yml
--- ns-3.39/utils/tests/gitlab-ci-scheduled.yml	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.40/utils/tests/gitlab-ci-scheduled.yml	2023-09-27 13:30:37.934840000 -0700
@@ -0,0 +1,218 @@
+# NS3 CI script for testing
+
+# Defines the steps to run the tests
+# Inherit with "extends: .base-test" and remember to set
+# the following variables: COMPILER (g++, clang++, ...) and
+# MODE (debug, default, optimized)
+
+.base-test:
+  image: archlinux
+  before_script:
+    # add the core-debug repo to pacman.conf
+    - printf "\n%s\n%s\n" "[core-debug]" "Include = /etc/pacman.d/mirrorlist" >> /etc/pacman.conf
+    - pacman-key --init
+    - pacman -Syu --noconfirm
+      base-devel cmake ninja ccache valgrind
+      python
+      boost gsl gtk3
+      glibc-debug
+  script:
+    - mkdir -p $CCACHE_BASEDIR_VALUE
+    - export CCACHE_BASEDIR=${PWD}
+    - export CCACHE_DIR=${PWD}/$CCACHE_BASEDIR_VALUE
+    # missing the flag --disable-python
+    - ./ns3 configure -d $MODE -GNinja --enable-examples --enable-tests --disable-gtk
+    - if [[ "$CI_JOB_STAGE" == "build" ]];
+      then ./ns3 build;
+      fi
+    - if [[ "$CI_JOB_STAGE" == "test" ]] || [[ "$FORCE_TESTS" == "Force" ]];
+      then ./test.py -n $VALGRIND_FLAG $FULLNESS;
+      fi
+  cache:
+    key: "ccache-$CI_JOB_NAME"
+    paths:
+      - $CCACHE_BASEDIR_VALUE/
+  variables:
+    COMPILER: g++
+    CCACHE_BASEDIR_VALUE: ns-3-ccache-storage
+    VALGRIND_FLAG: ""
+    FULLNESS: ""
+    # workaround for Valgrind on Archlinux https://bbs.archlinux.org/viewtopic.php?pid=2036171#p2036171
+    DEBUGINFOD_URLS: "https://debuginfod.archlinux.org"
+
+daily-jobs:
+  rules:
+    - if: $RELEASE == "daily"
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+      when: manual
+      allow_failure: true
+  stage: pre-build
+  script:
+    - echo "Starting daily jobs"
+
+weekly-slow-jobs:
+  rules:
+    - if: $RELEASE == "weekly"
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+      when: manual
+      allow_failure: true
+  stage: pre-build
+  script:
+    - echo "Starting weekly jobs"
+
+# Run the test.py script with files compiled in debug mode
+daily-build-test-debug:
+  extends: .base-test
+  rules:
+    - if: $RELEASE == "daily"
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+      allow_failure: true
+  needs: ["daily-jobs"]
+  dependencies: []
+  stage: build
+  variables:
+    MODE: debug
+  tags:
+    - nsnam
+    - linux
+
+# Run the test.py script with files compiled in default mode
+daily-build-default:
+  extends: .base-test
+  rules:
+    - if: $RELEASE == "daily"
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+      allow_failure: true
+  stage: build
+  needs: ["daily-jobs"]
+  variables:
+    MODE: default
+
+daily-test-default:
+  extends: .base-test
+  rules:
+    - if: $RELEASE == "daily"
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+      allow_failure: true
+  stage: test
+  needs: ["daily-build-default"]
+  dependencies:
+    - daily-build-default
+  variables:
+    MODE: default
+
+# Run the test.py script with files compiled in optimized mode
+daily-build-optimized:
+  extends: .base-test
+  rules:
+    - if: $RELEASE == "daily"
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+      allow_failure: true
+  stage: build
+  needs: ["daily-jobs"]
+  variables:
+    MODE: optimized
+
+daily-test-optimized:
+  extends: .base-test
+  rules:
+    - if: $RELEASE == "daily"
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+      allow_failure: true
+  stage: test
+  needs: ["daily-build-optimized"]
+  dependencies:
+    - daily-build-optimized
+  variables:
+    MODE: optimized
+
+### Valgrind tests
+# Run the test.py script with files compiled in optimized mode + valgrind (daily)
+daily-build-test-optimized-valgrind:
+  extends: .base-test
+  rules:
+    - if: $RELEASE == "daily"
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+      allow_failure: true
+  stage: build
+  needs: ["daily-jobs"]
+  dependencies: []
+  variables:
+    MODE: optimized
+    VALGRIND_FLAG: -g --verbose-failed
+    FORCE_TESTS: Force
+  tags:
+    - nsnam
+    - linux
+
+# Run the test.py script with files compiled in debug mode
+weekly-build-test-debug-valgrind:
+  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: debug
+    VALGRIND_FLAG: -g --verbose-failed
+    FORCE_TESTS: Force
+  tags:
+    - nsnam
+    - linux
+
+# Run the test.py script with files compiled in default mode
+weekly-build-test-default-valgrind:
+  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: default
+    VALGRIND_FLAG: -g --verbose-failed
+    FORCE_TESTS: Force
+  tags:
+    - nsnam
+    - linux
+
+# Run the test.py script with files compiled in optimized mode
+weekly-build-test-optimized-valgrind:
+  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
+    VALGRIND_FLAG: -g --verbose-failed
+    FORCE_TESTS: Force
+  tags:
+    - nsnam
+    - linux
+
+# Do a check for the TAKES_FOREVER jobs, only in optimized mode
+weekly-build-test-takes-forever-optimized:
+  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
+    FULLNESS: "-f TAKES_FOREVER"
+    FORCE_TESTS: Force
+  tags:
+    - nsnam
+    - linux
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/gitlab-ci-ubuntu.yml ns-3.40/utils/tests/gitlab-ci-ubuntu.yml
--- ns-3.39/utils/tests/gitlab-ci-ubuntu.yml	2023-07-05 14:23:48.141428500 -0700
+++ ns-3.40/utils/tests/gitlab-ci-ubuntu.yml	2023-09-27 13:30:37.934840000 -0700
@@ -14,10 +14,6 @@
     - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
       allow_failure: true
   before_script:
-    # The following ppa is needed only for Ubuntu 18.04 to install g++9
-    - apt update
-    - DEBIAN_FRONTEND=noninteractive apt install -y software-properties-common
-    - add-apt-repository ppa:ubuntu-toolchain-r/test -y
     - apt update
     - apt upgrade -y
     - DEBIAN_FRONTEND=noninteractive apt install -y
@@ -44,211 +40,171 @@
   script:
     - echo "Starting Ubuntu jobs"
 
-# Ubuntu 18.04 (Until April 2023)
-weekly-build-ubuntu-18.04-debug:
+# Ubuntu 20.04 (Until April 2025)
+weekly-build-ubuntu-20.04-debug:
   extends: .weekly-base-ubuntu
   needs: ["weekly-ubuntu"]
-  image: ubuntu:18.04
+  image: ubuntu:20.04
   stage: build
   variables:
     MODE: debug
     LIBGSL: libgsl23
-    COMPILER: g++-9
+    COMPILER: g++
 
-weekly-build-ubuntu-18.04-default:
+weekly-build-ubuntu-20.04-default:
   extends: .weekly-base-ubuntu
   needs: ["weekly-ubuntu"]
-  image: ubuntu:18.04
+  image: ubuntu:20.04
   stage: build
   variables:
     MODE: default
     LIBGSL: libgsl23
-    COMPILER: g++-9
+    COMPILER: g++
 
-weekly-build-ubuntu-18.04-optimized:
+weekly-build-ubuntu-20.04-optimized:
   extends: .weekly-base-ubuntu
   needs: ["weekly-ubuntu"]
-  image: ubuntu:18.04
+  image: ubuntu:20.04
   stage: build
   variables:
     MODE: optimized
     LIBGSL: libgsl23
-    COMPILER: g++-9
+    COMPILER: g++
 
-weekly-test-ubuntu-18.04-default:
+weekly-test-ubuntu-20.04-default:
   extends: .weekly-base-ubuntu
-  image: ubuntu:18.04
+  image: ubuntu:20.04
   stage: test
-  needs: ["weekly-build-ubuntu-18.04-default"]
+  needs: ["weekly-build-ubuntu-20.04-default"]
   dependencies:
-    - weekly-build-ubuntu-18.04-default
+    - weekly-build-ubuntu-20.04-default
   variables:
     MODE: default
     LIBGSL: libgsl23
-    COMPILER: g++-9
+    COMPILER: g++
 
-weekly-test-ubuntu-18.04-optimized:
+weekly-test-ubuntu-20.04-optimized:
   extends: .weekly-base-ubuntu
-  image: ubuntu:18.04
+  image: ubuntu:20.04
   stage: test
-  needs: ["weekly-build-ubuntu-18.04-optimized"]
+  needs: ["weekly-build-ubuntu-20.04-optimized"]
   dependencies:
-    - weekly-build-ubuntu-18.04-optimized
+    - weekly-build-ubuntu-20.04-optimized
   variables:
     MODE: optimized
     LIBGSL: libgsl23
-    COMPILER: g++-9
-
-# # Ubuntu 20.04 (Until April 2025)
-# weekly-build-ubuntu-20.04-debug:
-#   extends: .weekly-base-ubuntu
-#   image: ubuntu:20.04
-#   variables:
-#     MODE: debug
-#     LIBGSL: libgsl23
-
-# weekly-build-ubuntu-20.04-default:
-#   extends: .weekly-base-ubuntu
-#   image: ubuntu:20.04
-#   variables:
-#     MODE: default
-#     LIBGSL: libgsl23
-
-# weekly-build-ubuntu-20.04-optimized:
-#   extends: .weekly-base-ubuntu
-#   image: ubuntu:20.04
-#   variables:
-#     MODE: optimized
-#     LIBGSL: libgsl23
-
-# Ubuntu 22.04 (Until January 2032) -- commented out because we are using Ubuntu 22.04 for gcc jobs
-# weekly-build-ubuntu-22.04-debug:
-#   extends: .weekly-base-ubuntu
-#   needs: ["weekly-ubuntu"]
-#   image: ubuntu:22.04
-#   stage: build
-#   variables:
-#     MODE: debug
-#     LIBGSL: libgsl27
-#     COMPILER: g++
-
-# weekly-build-ubuntu-22.04-default:
-#   extends: .weekly-base-ubuntu
-#   needs: ["weekly-ubuntu"]
-#   image: ubuntu:22.04
-#   stage: build
-#   variables:
-#     MODE: default
-#     LIBGSL: libgsl27
-#     COMPILER: g++
-
-# weekly-build-ubuntu-22.04-optimized:
-#   extends: .weekly-base-ubuntu
-#   needs: ["weekly-ubuntu"]
-#   image: ubuntu:22.04
-#   stage: build
-#   variables:
-#     MODE: optimized
-#     LIBGSL: libgsl27
-#     COMPILER: g++
-
-# weekly-test-ubuntu-22.04-default:
-#   extends: .weekly-base-ubuntu
-#   image: ubuntu:22.04
-#   stage: test
-#   needs: ["weekly-build-ubuntu-22.04-default"]
-#   dependencies:
-#     - weekly-build-ubuntu-22.04-default
-#   variables:
-#     MODE: default
-#     LIBGSL: libgsl27
-#     COMPILER: g++
-
-# weekly-test-ubuntu-22.04-optimized:
-#   extends: .weekly-base-ubuntu
-#   image: ubuntu:22.04
-#   stage: test
-#   needs: ["weekly-build-ubuntu-22.04-optimized"]
-#   dependencies:
-#     - weekly-build-ubuntu-22.04-optimized
-#   variables:
-#     MODE: optimized
-#     LIBGSL: libgsl27
-#     COMPILER: g++
+    COMPILER: g++
 
-# Ubuntu Latest
-weekly-build-ubuntu-latest-debug:
+# Ubuntu 22.04 (Until January 2032)
+weekly-build-ubuntu-22.04-debug:
   extends: .weekly-base-ubuntu
   needs: ["weekly-ubuntu"]
-  image: ubuntu:latest
+  image: ubuntu:22.04
   stage: build
   variables:
     MODE: debug
     LIBGSL: libgsl27
     COMPILER: g++
 
-weekly-build-ubuntu-latest-default:
+weekly-build-ubuntu-22.04-default:
   extends: .weekly-base-ubuntu
   needs: ["weekly-ubuntu"]
-  image: ubuntu:latest
+  image: ubuntu:22.04
   stage: build
   variables:
     MODE: default
     LIBGSL: libgsl27
     COMPILER: g++
 
-weekly-build-ubuntu-latest-optimized:
+weekly-build-ubuntu-22.04-optimized:
   extends: .weekly-base-ubuntu
   needs: ["weekly-ubuntu"]
-  image: ubuntu:latest
+  image: ubuntu:22.04
   stage: build
   variables:
     MODE: optimized
     LIBGSL: libgsl27
     COMPILER: g++
 
-weekly-test-ubuntu-latest-default:
+weekly-test-ubuntu-22.04-default:
   extends: .weekly-base-ubuntu
-  image: ubuntu:latest
+  image: ubuntu:22.04
   stage: test
-  needs: ["weekly-build-ubuntu-latest-default"]
+  needs: ["weekly-build-ubuntu-22.04-default"]
   dependencies:
-    - weekly-build-ubuntu-latest-default
+    - weekly-build-ubuntu-22.04-default
   variables:
     MODE: default
     LIBGSL: libgsl27
     COMPILER: g++
 
-weekly-test-ubuntu-latest-optimized:
+weekly-test-ubuntu-22.04-optimized:
   extends: .weekly-base-ubuntu
-  image: ubuntu:latest
+  image: ubuntu:22.04
   stage: test
-  needs: ["weekly-build-ubuntu-latest-optimized"]
+  needs: ["weekly-build-ubuntu-22.04-optimized"]
   dependencies:
-    - weekly-build-ubuntu-latest-optimized
+    - weekly-build-ubuntu-22.04-optimized
   variables:
     MODE: optimized
     LIBGSL: libgsl27
     COMPILER: g++
 
-# Ubuntu Rolling
-# weekly-build-ubuntu-rolling-debug:
-#   extends: .weekly-base-ubuntu
-#   image: ubuntu:rolling
-#   variables:
-#     MODE: debug
-#     LIBGSL: libgsl27
+# Ubuntu Rolling (latest released, might be non-LTS)
+weekly-build-ubuntu-rolling-debug:
+  extends: .weekly-base-ubuntu
+  needs: ["weekly-ubuntu"]
+  image: ubuntu:rolling
+  stage: build
+  variables:
+    MODE: debug
+    LIBGSL: libgsl27
+    COMPILER: g++
+
+weekly-build-ubuntu-rolling-default:
+  extends: .weekly-base-ubuntu
+  needs: ["weekly-ubuntu"]
+  image: ubuntu:rolling
+  stage: build
+  variables:
+    MODE: default
+    LIBGSL: libgsl27
+    COMPILER: g++
+
+# Aug. 26, 2023: --disable-eigen is needed to prevent a -Werror=unused-variable
+weekly-build-ubuntu-rolling-optimized:
+  extends: .weekly-base-ubuntu
+  needs: ["weekly-ubuntu"]
+  image: ubuntu:rolling
+  stage: build
+  variables:
+    MODE: optimized
+    LIBGSL: libgsl27
+    COMPILER: g++
+    EXTRA_OPTIONS: --disable-eigen
 
-# weekly-build-ubuntu-rolling-default:
-#   extends: .weekly-base-ubuntu
-#   image: ubuntu:rolling
-#   variables:
-#     MODE: default
-#     LIBGSL: libgsl27
+weekly-test-ubuntu-rolling-default:
+  extends: .weekly-base-ubuntu
+  image: ubuntu:rolling
+  stage: test
+  needs: ["weekly-build-ubuntu-rolling-default"]
+  dependencies:
+    - weekly-build-ubuntu-rolling-default
+  variables:
+    MODE: default
+    LIBGSL: libgsl27
+    COMPILER: g++
 
-# weekly-build-ubuntu-rolling-optimized:
-#   extends: .weekly-base-ubuntu
-#   image: ubuntu:rolling
-#   variables:
-#     MODE: optimized
-#     LIBGSL: libgsl27
+# Aug. 26, 2023: --disable-eigen is needed to prevent a -Werror=unused-variable
+weekly-test-ubuntu-rolling-optimized:
+  extends: .weekly-base-ubuntu
+  image: ubuntu:rolling
+  stage: test
+  needs: ["weekly-build-ubuntu-rolling-optimized"]
+  dependencies:
+    - weekly-build-ubuntu-rolling-optimized
+  variables:
+    MODE: optimized
+    LIBGSL: libgsl27
+    COMPILER: g++
+    EXTRA_OPTIONS: --disable-eigen
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/gitlab-ci.yml ns-3.40/utils/tests/gitlab-ci.yml
--- ns-3.39/utils/tests/gitlab-ci.yml	2023-07-05 14:23:48.141428500 -0700
+++ ns-3.40/utils/tests/gitlab-ci.yml	2023-09-27 13:30:37.934840000 -0700
@@ -43,7 +43,7 @@
     - export CCACHE_BASEDIR=${PWD}
     - export CCACHE_DIR=${PWD}/$CCACHE_BASEDIR_VALUE
     - export MPI_CI=1
-    - CXX=$COMPILER ./ns3 configure -d $MODE -GNinja --enable-examples --enable-tests --enable-asserts $ENABLE_MPI
+    - CXX=$COMPILER ./ns3 configure -d $MODE -GNinja --enable-examples --enable-tests --enable-asserts --enable-werror $ENABLE_MPI
       $EXTRA_OPTIONS
     - ccache -z
     - if [[ "$CI_JOB_STAGE" == "build" ]];
@@ -89,7 +89,7 @@
   - "utils/tests/gitlab-ci-fedora.yml"
   - "utils/tests/gitlab-ci-gcc.yml"
   - "utils/tests/gitlab-ci-clang.yml"
-  - "utils/tests/gitlab-ci-daily.yml"
+  - "utils/tests/gitlab-ci-scheduled.yml"
   - "utils/tests/gitlab-ci-code-linting.yml"
   - "utils/tests/gitlab-ci-doc.yml"
   - "utils/tests/gitlab-ci-cppyy.yml"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/README.md ns-3.40/utils/tests/README.md
--- ns-3.39/utils/tests/README.md	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils/tests/README.md	2023-09-27 13:30:37.934840000 -0700
@@ -4,32 +4,59 @@
 ## Table of Contents:
 
 1) [What is](#what-is)
-2) [Testing script](#testing-script)
-3) [Gitlab CI infrastructure](#gitlab-ci-infrastructure)
-4) [Test your changes](#test-your-changes)
+2) [Gitlab CI infrastructure](#gitlab-ci-infrastructure)
+3) [Test your changes](#test-your-changes)
 
 ## What is
 
 In this directory, we store documents related to our testing infrastructure.
 
-## Testing script
-To fill.
-
 ## Gitlab CI infrastructure
 
 To know more about the Gitlab CI feature, please refer to https://about.gitlab.com/product/continuous-integration/. We use the services offered by Gitlab to test our software in multiple ways. If you are interested how to run these tests on your fork, please read below.
 
+Note: each user does have a limited amount of "minutes" (time used to run CI jobs). Minutes are limited, and if you run out of minutes you will not be able to run jobs until the next month - or until you pay for more minutes.
+
 ### ns-3 CI configuration
 
 We store our YML files under the directory ./utils/tests. The main file is named `gitlab-ci.yml`, and from there we include multiple files to expand the number (and the quality) of tests we perform. We use inheritance of jobs to avoid to write many lines of code.
 
+The configuration is split in different files, each one containing a group of jobs that have some common rules. E.g.:
+
+- `gitlab-ci-per-commit.yml`: jobs executed at each commit.
+- `gitlab-ci-scheduled.yml`: daily and weekly ordinary and slow jobs.
+- `gitlab-ci-gcc.yml`: jobs to test various GCC versions.
+
+If you did fork ns-3, the CI should already point to the right configureation file. Otherwise, you will have to select the `gitlab-ci.yml` in your fork configuration. Note that Gitlab requires a user verification (usually it requires a valid credit card) to run CI jobs. If you did skip the verification process the CI will always fail.
+
+### CI pipelines
+
+If configured properly, the CI will start a pipeline (a set of jobs) each time new commits are pushed to the repository. To avoid to trigger a pipeline, it is possible to issue the command `git push -o ci.skip`.
+
+Each pipeline is made of several stages, and there are different pipelines depending if there is an active merge request or not.
+
+#### CI pipeline stages
+
+The stages are:
+
+- pre (fast jobs that are easy to fail, like coding style checks and spell checks).
+- pre-build (dummy jobs used to trigger following jobs according to specific rules).
+- build (build jobs)
+- test (test jobs, run the script `test.py` and other checks that require a previous build job)
+- code-linting (code quality checks, e.g., clang-tidy)
+- documentation (build the docs and check for errors)
+
+Normally, stages are executed sequentially (a stage is stared when the previous is finished), but jobs dependencies might override this.
+
 ### Per commit jobs description
 
-After each commit, the infrastructure will test the grammar correctness by doing a build, with tests and examples enabled, in three modes: debug, release, optimized. The build is done with the default GCC of the Arch Linux distribution: more deep check are done daily and weekly. You can see the job script in `gitlab-ci.yml`. If the build stage is passed, the commits done on the master branch will also trigger a documentation update. Currently, we do not use the generated documentation as Gitlab pages, but we use a separate service to display the documentation through the web.
+After each commit, the infrastructure will test the grammar correctness by doing a build, with tests and examples enabled, in three modes: debug, default, optimized. The build is done with the default GCC of the Arch Linux distribution: more deep check are done daily and weekly. You can see the job script in `gitlab-ci.yml`. If the build stage is passed, the commits done on the master branch will also trigger a documentation update. Currently, we do not use the generated documentation as Gitlab pages, but we use a separate service to display the documentation through the web.
+
+Note that if a commit is pushed to a branch associated to an active merge request, the jobs will be run in a different way, and it will be possible to manually trigger additional jobs. Use this opportunity with caution, as it does consume nsnam minutes (not user minutes).
 
 ### Daily jobs description
 
-Thanks to the "Schedule" feature of Gitlab, we setup pipelines that have to be run once per day. The scheduled pipeline has to define a variable, named `RELEASE`, that should be set to `daily`. In the scripts then, we check for the value of that variable and run the jobs accordingly. As daily jobs, we perform a test run in all the modes (debug, release, optimized) under Arch Linux, and they are defined in the file `gitlab-ci-test.yml`.
+Thanks to the "Schedule" feature of Gitlab, we setup pipelines that have to be run once per day. The scheduled pipeline has to define a variable, named `RELEASE`, that should be set to `daily`. In the scripts then, we check for the value of that variable and run the jobs accordingly. As daily jobs, we perform a test run in all the modes (debug, default, optimized) under Arch Linux.
 
 ### Weekly jobs description
 
@@ -37,7 +64,7 @@
 
 ## Test your changes
 
-When you fork ns-3-dev on Gitlab, you get access to 2000 free hours of execution time on the Gitlab CI infrastructure. You automatically inherit all the scripts as well, so you can test your changes before requesting a merge. As mentioned previously, we store our YML files under the directory ./utils/tests, therefore, to execute per-commit script automatically, Gitlab CI/CD requires a custom path to the YML file.
+When you fork ns-3-dev on Gitlab, you get access to some free hours of execution time on the Gitlab CI infrastructure. You automatically inherit all the scripts as well, so you can test your changes before requesting a merge. As mentioned previously, we store our YML files under the directory ./utils/tests, therefore, to execute per-commit script automatically, Gitlab CI/CD requires a custom path to the YML file.
 
 To customize the path:
 
@@ -48,7 +75,7 @@
 
 To perform a deeper test, you can manually run the daily or the weekly test. Go to the Gitlab interface, then enter in the CI/CD menu and select Pipelines. On the top, you can manually run a pipeline: select the branch, and add a variable `RELEASE` set to `daily` or `weekly` following your need, and then run it.
 
-Related to the timeout, our `gitlab-ci.yml` script also configures the job-level timeout. Currently, this timeout is set to 9h considering the extensive and time-consuming testing done in weekly jobs.
+Related to the timeout, our `gitlab-ci.yml` script also configures the job-level timeout. Currently, this timeout is set to 24h considering the extensive and time-consuming testing done in weekly jobs.
 
 **Note**: The job-level timeout can exceed the [project-level](https://docs.gitlab.com/ee/ci/pipelines/settings.html#set-a-limit-for-how-long-jobs-can-run) timeout (default: 60 min), but can not exceed the Runner-specific timeout.
 
@@ -61,21 +88,7 @@
 list below:
 
 ```shell
-RELEASE, that can take the value "weekly" or "daily" or "monthly"
-(if you want to perform all the build/test that are done daily, once a week,
-or once a month, respectively)
-
-FEDORA = True
-(to test all the fedora builds)
-
-UBUNTU = True
-(to test all the Ubuntu builds)
-
-GCC_BUILD_ENABLE = True
-(to test all the GCC builds)
-
-CLANG_BUILD_ENABLE = True
-(to test all the clang builds)
+RELEASE, that can take the value "daily" or "weekly" (if you want to perform all the build/test that are done daily or once a week, respectively)
 ```
 
 ... and then click Save, and run it manually from the "Schedules" page.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/TestBase.py ns-3.40/utils/tests/TestBase.py
--- ns-3.39/utils/tests/TestBase.py	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils/tests/TestBase.py	2023-09-27 13:30:37.934840000 -0700
@@ -24,9 +24,9 @@
 
 def print_case_in_file(case_string, out):
     for i in range(100):
-        print("-", end = '', file = out)
+        print("-", end='', file=out)
     print(file=out)
-    print("running test case " + case_string, end='\n\n', file = out)
+    print("running test case " + case_string, end='\n\n', file=out)
     out.flush()
 
 def print_failed_cases(failed_cases):
@@ -40,10 +40,10 @@
         print(cmd.replace(sys.executable, ''))
 
 def set_workdir():
-    dir_files = [ f for f in os.listdir('.') if os.path.exists(f) ]
+    dir_files = [f for f in os.listdir('.') if os.path.exists(f)]
     if not 'VERSION' in dir_files and not 'ns3' in dir_files:
         if os.path.split(os.path.abspath('.'))[1] == 'tests' and os.path.split(os.path.abspath(os.pardir))[1] == 'utils':
-                os.chdir('../../')
+            os.chdir('../../')
         else:
             print('Error: Invalid working directory')
             sys.exit(1)
@@ -75,7 +75,7 @@
         self.my_env['LD_LIBRARY_PATH'] = os.getcwd() + "/build"
         self.mode = mode
         self.outfile = 'test-port-'+self.mode+'.out'
-        self.options = self.parseargs(argv , desc)
+        self.options = self.parseargs(argv, desc)
 
     def parseargs(self, argv, desc):
         """!
@@ -85,15 +85,15 @@
         @param desc description
         @return command line arguments
         """
-        parser = argparse.ArgumentParser(description = desc)
-        parser.add_argument('-f', '--file', action='store', dest='out_file', default = self.outfile,
+        parser = argparse.ArgumentParser(description=desc)
+        parser.add_argument('-f', '--file', action='store', dest='out_file', default=self.outfile,
                             metavar="FILE",
                             help='File to be used for storing the command specific output (Default: '+self.outfile+')')
         parser.add_argument('-c', action='store_true', dest='cmds', default=False,
                             help='List out all the commands being tested')
         parser.add_argument('-m', action='store_true', dest='mute', default=False,
                             help='Sends only stderr output to FILE')
-        parser.add_argument('-x', '--customcmd', action='store', dest='custcmd', default = None,
+        parser.add_argument('-x', '--customcmd', action='store', dest='custcmd', default=None,
                             help='Enter a comma-separated list of commands to override the existing ones. NOT APPLICABLE FOR TEST-PY SUITE.')
         return parser.parse_args(argv)
 
@@ -115,15 +115,15 @@
         if self.options.cmds:
             print_cmds(cmds)
             return
-
+        base_dir = os.sep.join(os.path.abspath(__file__).replace(os.path.pathsep, '/').split('/')[:-3])
         final_return = 0
         total_tests = len(cmds)
         passed = 0
         progress = 0.0
         failed_cases = []
-        with open(self.options.out_file, 'w') as out:
+        with open(self.options.out_file, 'w', encoding='utf-8') as out:
             outstream = out
-            with open(os.devnull, 'w') as sink:
+            with open(os.devnull, 'w', encoding='utf-8') as sink:
                 if self.options.mute:
                     outstream = sink
                 for cmd in cmds:
@@ -131,7 +131,13 @@
                     print("running test case: " + case_string)
                     print_case_in_file(case_string, out)
                     progress += 1
-                    ret = subprocess.call(cmd, shell=True, env=self.my_env, stdout=outstream, stderr=out)
+                    ret = subprocess.call(cmd,
+                                          shell=True,
+                                          env=self.my_env,
+                                          stdout=outstream,
+                                          stderr=out,
+                                          cwd=base_dir
+                                          )
                     if not ret:
                         passed += 1
                     else:
@@ -142,5 +148,5 @@
             print_failed_cases(failed_cases)
         else:
             print("\nAll cases passed")
-        print ("Detailed output available in " + self.options.out_file, end='\n\n')
+        print("Detailed output available in " + self.options.out_file, end='\n\n')
         return final_return
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/test-ns3.py ns-3.40/utils/tests/test-ns3.py
--- ns-3.39/utils/tests/test-ns3.py	2023-07-05 14:23:48.141428500 -0700
+++ ns-3.40/utils/tests/test-ns3.py	2023-09-27 13:30:37.934840000 -0700
@@ -1,6 +1,6 @@
 #! /usr/bin/env python3
 #
-# Copyright (c) 2021 Universidade de Brasília
+# Copyright (c) 2021-2023 Universidade de Brasília
 #
 # 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
@@ -126,7 +126,7 @@
     @return list of programs.
     """
     values = {}
-    with open(ns3_lock_filename) as f:
+    with open(ns3_lock_filename, encoding="utf-8") as f:
         exec(f.read(), globals(), values)
 
     programs_list = values["ns3_runnable_programs"]
@@ -163,7 +163,7 @@
     @return value of the requested entry.
     """
     values = {}
-    with open(ns3_lock_filename) as f:
+    with open(ns3_lock_filename, encoding="utf-8") as f:
         exec(f.read(), globals(), values)
     return values.get(entry, None)
 
@@ -206,7 +206,7 @@
             currentTestCase.skipTest("python-on-whales was not found")
 
         # Import rootless docker settings from .bashrc
-        with open(os.path.expanduser("~/.bashrc"), "r") as f:
+        with open(os.path.expanduser("~/.bashrc"), "r", encoding="utf-8") as f:
             docker_settings = re.findall("(DOCKER_.*=.*)", f.read())
             for setting in docker_settings:
                 key, value = setting.split("=")
@@ -285,7 +285,7 @@
                 continue
 
             # Open the examples CMakeLists.txt and read it
-            with open(os.path.join(example_directory, "CMakeLists.txt"), "r") as f:
+            with open(os.path.join(example_directory, "CMakeLists.txt"), "r", encoding="utf-8") as f:
                 cmake_contents = f.read()
 
             # For each file, check if it is in the CMake contents
@@ -319,7 +319,7 @@
                 cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
 
             # Open the module CMakeLists.txt and read it
-            with open(cmake_path, "r") as f:
+            with open(cmake_path, "r", encoding="utf-8") as f:
                 cmake_contents = f.read()
 
             # For each file, check if it is in the CMake contents
@@ -358,7 +358,7 @@
                 cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
 
             # Open the module CMakeLists.txt and read it
-            with open(cmake_path, "r") as f:
+            with open(cmake_path, "r", encoding="utf-8") as f:
                 cmake_contents = f.read()
 
             # For each file, check if it is in the CMake contents
@@ -389,7 +389,7 @@
         for path in module_paths:
             # Open the module CMakeLists.txt and read it
             cmake_path = os.path.join(path, "CMakeLists.txt")
-            with open(cmake_path, "r") as f:
+            with open(cmake_path, "r", encoding="utf-8") as f:
                 cmake_contents = f.readlines()
 
             module_name = os.path.relpath(path, ns3_path)
@@ -957,7 +957,7 @@
             ns3rc_template = ns3rc_str(ns3rc_type)
 
             # Now we repeat the command line tests but with the ns3rc file.
-            with open(ns3rc_script, "w") as f:
+            with open(ns3rc_script, "w", encoding="utf-8") as f:
                 f.write(ns3rc_template.format(modules="'lte'", examples="False", tests="True"))
 
             # Reconfigure.
@@ -972,7 +972,7 @@
             self.assertLessEqual(len(get_programs_list()), len(self.ns3_executables))
 
             # Replace the ns3rc file with the wifi module, enabling examples and disabling tests
-            with open(ns3rc_script, "w") as f:
+            with open(ns3rc_script, "w", encoding="utf-8") as f:
                 f.write(ns3rc_template.format(modules="'wifi'", examples="True", tests="False"))
 
             # Reconfigure
@@ -987,7 +987,7 @@
             self.assertGreater(len(get_programs_list()), len(self.ns3_executables))
 
             # Replace the ns3rc file with multiple modules
-            with open(ns3rc_script, "w") as f:
+            with open(ns3rc_script, "w", encoding="utf-8") as f:
                 f.write(ns3rc_template.format(modules="'core','network'", examples="True", tests="False"))
 
             # Reconfigure
@@ -1004,7 +1004,7 @@
 
             # Replace the ns3rc file with multiple modules,
             # in various different ways and with comments
-            with open(ns3rc_script, "w") as f:
+            with open(ns3rc_script, "w", encoding="utf-8") as f:
                 if ns3rc_type == "python":
                     f.write(ns3rc_template.format(modules="""'core', #comment
                     'lte',
@@ -1126,7 +1126,7 @@
 
         # Cause a sigsegv
         sigsegv_example = os.path.join(ns3_path, "scratch", "sigsegv.cc")
-        with open(sigsegv_example, "w") as f:
+        with open(sigsegv_example, "w", encoding="utf-8") as f:
             f.write("""
                     int main (int argc, char *argv[])
                     {
@@ -1144,7 +1144,7 @@
 
         # Cause an abort
         abort_example = os.path.join(ns3_path, "scratch", "abort.cc")
-        with open(abort_example, "w") as f:
+        with open(abort_example, "w", encoding="utf-8") as f:
             f.write("""
                     #include "ns3/core-module.h"
 
@@ -1217,7 +1217,7 @@
         for path in test_files + backup_files:
             filepath = os.path.join(ns3_path, path)
             os.makedirs(os.path.dirname(filepath), exist_ok=True)
-            with open(filepath, "w") as f:
+            with open(filepath, "w", encoding="utf-8") as f:
                 if "main" in path:
                     f.write("int main (int argc, char *argv[]){}")
                 else:
@@ -1358,10 +1358,10 @@
         os.makedirs("contrib/borked/examples", exist_ok=True)
 
         # Test if configuration succeeds and building the module library fails
-        with open("contrib/borked/examples/CMakeLists.txt", "w") as f:
+        with open("contrib/borked/examples/CMakeLists.txt", "w", encoding="utf-8") as f:
             f.write("")
         for invalid_or_nonexistent_library in ["", "gsd", "lib", "libfi", "calibre"]:
-            with open("contrib/borked/CMakeLists.txt", "w") as f:
+            with open("contrib/borked/CMakeLists.txt", "w", encoding="utf-8") as f:
                 f.write("""
                         build_lib(
                             LIBNAME borked
@@ -1400,7 +1400,7 @@
         # - no additional library (should work)
         # - invalid library names (should fail to configure)
         # - valid library names but nonexistent libraries (should not create a target)
-        with open("contrib/borked/CMakeLists.txt", "w") as f:
+        with open("contrib/borked/CMakeLists.txt", "w", encoding="utf-8") as f:
             f.write("""
                     build_lib(
                         LIBNAME borked
@@ -1409,7 +1409,7 @@
                     )
                     """)
         for invalid_or_nonexistent_library in ["", "gsd", "lib", "libfi", "calibre"]:
-            with open("contrib/borked/examples/CMakeLists.txt", "w") as f:
+            with open("contrib/borked/examples/CMakeLists.txt", "w", encoding="utf-8") as f:
                 f.write("""
                         build_lib_example(
                             NAME borked-example
@@ -1452,9 +1452,9 @@
         os.makedirs("contrib/calibre/examples", exist_ok=True)
 
         # Now test if we can have a library with "lib" in it
-        with open("contrib/calibre/examples/CMakeLists.txt", "w") as f:
+        with open("contrib/calibre/examples/CMakeLists.txt", "w", encoding="utf-8") as f:
             f.write("")
-        with open("contrib/calibre/CMakeLists.txt", "w") as f:
+        with open("contrib/calibre/CMakeLists.txt", "w", encoding="utf-8") as f:
             f.write("""
                 build_lib(
                     LIBNAME calibre
@@ -1539,7 +1539,7 @@
                                       "VERSION_TAG_DISTANCE = '0'\n"
                                       "VERSION_BUILD_PROFILE = 'debug'\n"
                                       )
-            with open(version_cache_file, "w") as version:
+            with open(version_cache_file, "w", encoding="utf-8") as version:
                 version.write(version_cache_contents)
 
             # Configuration should now succeed
@@ -1549,7 +1549,7 @@
             self.assertTrue(os.path.exists(os.path.join(ns3_path, "cmake-cache", "build.ninja")))
 
             # And contents of version cache should be unchanged
-            with open(version_cache_file, "r") as version:
+            with open(version_cache_file, "r", encoding="utf-8") as version:
                 self.assertEqual(version.read(), version_cache_contents)
 
             # Third case: we rename the .git directory temporarily and reconfigure
@@ -1571,7 +1571,7 @@
             container.execute("./ns3 configure -G Ninja --enable-build-version")
             container.execute("./ns3 build core")
             self.assertTrue(os.path.exists(os.path.join(ns3_path, "cmake-cache", "build.ninja")))
-            with open(version_cache_file, "r") as version:
+            with open(version_cache_file, "r", encoding="utf-8") as version:
                 self.assertNotEqual(version.read(), version_cache_contents)
 
             # Remove version cache file if it exists
@@ -1638,7 +1638,7 @@
 
             # Check if configuration properly detected lld
             self.assertTrue(os.path.exists(os.path.join(ns3_path, "cmake-cache", "build.ninja")))
-            with open(os.path.join(ns3_path, "cmake-cache", "build.ninja"), "r") as f:
+            with open(os.path.join(ns3_path, "cmake-cache", "build.ninja"), "r", encoding="utf-8") as f:
                 self.assertIn("-fuse-ld=lld", f.read())
 
             # Try to build using the lld linker
@@ -1659,7 +1659,7 @@
 
             # Check if configuration properly detected mold
             self.assertTrue(os.path.exists(os.path.join(ns3_path, "cmake-cache", "build.ninja")))
-            with open(os.path.join(ns3_path, "cmake-cache", "build.ninja"), "r") as f:
+            with open(os.path.join(ns3_path, "cmake-cache", "build.ninja"), "r", encoding="utf-8") as f:
                 self.assertIn("-fuse-ld=mold", f.read())
 
             # Try to build using the lld linker
@@ -1676,7 +1676,7 @@
 
             # Check if configuration properly disabled lld/mold usage
             self.assertTrue(os.path.exists(os.path.join(ns3_path, "cmake-cache", "build.ninja")))
-            with open(os.path.join(ns3_path, "cmake-cache", "build.ninja"), "r") as f:
+            with open(os.path.join(ns3_path, "cmake-cache", "build.ninja"), "r", encoding="utf-8") as f:
                 self.assertNotIn("-fuse-ld=mold", f.read())
 
     def test_21_ClangTimeTrace(self):
@@ -1958,7 +1958,7 @@
         self.ns3_libraries = get_libraries_list()
 
         version_file = os.sep.join([ns3_path, "VERSION"])
-        with open(version_file, "w") as f:
+        with open(version_file, "w", encoding="utf-8") as f:
             f.write("3-00\n")
 
         # Reconfigure.
@@ -1990,7 +1990,7 @@
             self.assertTrue(os.path.exists(library))
 
         # Restore version file.
-        with open(version_file, "w") as f:
+        with open(version_file, "w", encoding="utf-8") as f:
             f.write("3-dev\n")
 
     def test_07_OutputDirectory(self):
@@ -2077,7 +2077,7 @@
 
         # 3-dev version format is not supported by CMake, so we use 3.01.
         version_file = os.sep.join([ns3_path, "VERSION"])
-        with open(version_file, "w") as f:
+        with open(version_file, "w", encoding="utf-8") as f:
             f.write("3-01\n")
 
         # Reconfigure setting the installation folder to ns-3-dev/build/install.
@@ -2113,7 +2113,7 @@
 
         # Now create a test CMake project and try to find_package ns-3.
         test_main_file = os.sep.join([install_prefix, "main.cpp"])
-        with open(test_main_file, "w") as f:
+        with open(test_main_file, "w", encoding="utf-8") as f:
             f.write("""
             #include <ns3/core-module.h>
             using namespace ns3;
@@ -2163,7 +2163,7 @@
                                      """ + import_method
 
                 test_cmake_project_file = os.sep.join([install_prefix, "CMakeLists.txt"])
-                with open(test_cmake_project_file, "w") as f:
+                with open(test_cmake_project_file, "w", encoding="utf-8") as f:
                     f.write(test_cmake_project)
 
                 # Configure the test project
@@ -2215,7 +2215,7 @@
 
         # Restore 3-dev version file
         os.remove(version_file)
-        with open(version_file, "w") as f:
+        with open(version_file, "w", encoding="utf-8") as f:
             f.write("3-dev\n")
 
     def test_09_Scratches(self):
@@ -2834,6 +2834,98 @@
         self.assertIn("scratch-simulator", stdout)
         self.assertIn("(lldb) target create", stdout)
 
+    def test_18_CpmAndVcpkgManagers(self):
+        """!
+        Test if CPM and Vcpkg package managers are working properly
+        @return None
+        """
+        # Clean the ns-3 configuration
+        return_code, stdout, stderr = run_ns3("clean")
+        self.assertEqual(return_code, 0)
+
+        # Cleanup VcPkg leftovers
+        if os.path.exists("vcpkg"):
+            shutil.rmtree("vcpkg")
+
+        # Copy a test module that consumes armadillo
+        destination_src = os.path.join(ns3_path, "src/test-package-managers")
+        # Remove pre-existing directories
+        if os.path.exists(destination_src):
+            shutil.rmtree(destination_src)
+
+        # Always use a fresh copy
+        shutil.copytree(os.path.join(ns3_path, "build-support/test-files/test-package-managers"),
+                        destination_src)
+
+        with DockerContainerManager(self, "ubuntu:22.04") as container:
+            # Install toolchain
+            container.execute("apt-get update")
+            container.execute("apt-get install -y python3 cmake g++ ninja-build")
+
+            # Verify that Armadillo is not available and that we did not
+            # add any new unnecessary dependency when features are not used
+            try:
+                container.execute(
+                    "./ns3 configure -- -DTEST_PACKAGE_MANAGER:STRING=ON")
+                self.skipTest("Armadillo is already installed")
+            except DockerException as e:
+                pass
+
+            # Clean cache to prevent dumb errors
+            return_code, stdout, stderr = run_ns3("clean")
+            self.assertEqual(return_code, 0)
+
+            # Install CPM and VcPkg shared dependency
+            container.execute("apt-get install -y git")
+
+            # Install Armadillo with CPM
+            try:
+                container.execute(
+                    "./ns3 configure -- -DNS3_CPM=ON -DTEST_PACKAGE_MANAGER:STRING=CPM")
+            except DockerException as e:
+                self.fail()
+
+            # Try to build module using CPM's Armadillo
+            try:
+                container.execute(
+                    "./ns3 build test-package-managers")
+            except DockerException as e:
+                self.fail()
+
+            # Clean cache to prevent dumb errors
+            return_code, stdout, stderr = run_ns3("clean")
+            self.assertEqual(return_code, 0)
+
+            # Install VcPkg dependencies
+            container.execute("apt-get install -y zip unzip tar curl")
+
+            # Install Armadillo dependencies
+            container.execute("apt-get install -y pkg-config gfortran")
+
+            # Install VcPkg
+            try:
+                container.execute(
+                    "./ns3 configure -- -DNS3_VCPKG=ON")
+            except DockerException as e:
+                self.fail()
+
+            # Install Armadillo with VcPkg
+            try:
+                container.execute("./ns3 configure -- -DTEST_PACKAGE_MANAGER:STRING=VCPKG")
+            except DockerException as e:
+                self.fail()
+
+            # Try to build module using VcPkg's Armadillo
+            try:
+                container.execute(
+                    "./ns3 build test-package-managers")
+            except DockerException as e:
+                self.fail()
+
+        # Remove test module
+        if os.path.exists(destination_src):
+            shutil.rmtree(destination_src)
+
 
 class NS3QualityControlTestCase(unittest.TestCase):
     """!
@@ -2907,7 +2999,7 @@
                         continue
 
                     try:
-                        with open(filepath, "r") as f:
+                        with open(filepath, "r", encoding="utf-8") as f:
                             matches = regex.findall(f.read())
 
                             # Get first group for each match (containing the URL)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils/tests/test-test.py ns-3.40/utils/tests/test-test.py
--- ns-3.39/utils/tests/test-test.py	2023-07-05 14:23:48.141428500 -0700
+++ ns-3.40/utils/tests/test-test.py	2023-09-27 13:30:37.934840000 -0700
@@ -19,7 +19,7 @@
 # NOTE: Run this script with the Python3 interpreter if the python3 compatibility
 #       of the ns-3 unit test runner needs to be tested.
 
-#   The following options of test.py are being tested for poratability by this script.
+#   The following options of test.py are being tested for portability by this script.
 #   To see the options supported by this script, run with the -h option on the command line
 #
 #   -h, --help            show this help message and exit
@@ -71,49 +71,50 @@
         Prepares test cases and executes
     """
     test_cases = [
-      '',
-      '-h',
-      '--help',
-      '-b build/',
-      '--buildpath=build/',
-      '-c performance',
-      '--constrain=performance',
-      '-d',
-      '--duration',
-      '-e socket-options-ipv6',
-      '--example=socket-options-ipv6',
-      '-u',
-      '--update-data',
-      '-f EXTENSIVE --fullness=EXTENSIVE'
-      '-g',
-      '--grind',
-      '-l',
-      '--list',
-      '-m',
-      '--multiple',
-      '-n',
-      '--no-build',
-      '-p first',
-      '--pyexample=first',
-      '-r',
-      '--retain',
-      '-s ns3-tcp-interoperability',
-      '--suite=ns3-tcp-interoperability',
-      '-t t_opt.txt',
-      '--text=t_opt.txt && rm -rf t_opt.txt',
-      '-v',
-      '--verbose',
-      '-w t_opt.html && rm -rf t_opt.html',
-      '--web=t_opt.html && rm -rf t_opt.html',
-      '--html=t_opt.html && rm -rf t_opt.html',
-      '-x t_opt.xml && rm -rf t_opt.xml',
-      '--xml=t_opt.xml && rm -rf t_opt.xml',
+        '',
+        '-h',
+        '--help',
+        '-b build/',
+        '--buildpath=build/',
+        '-c performance',
+        '--constrain=performance',
+        '-d',
+        '--duration',
+        '-e socket-options-ipv6',
+        '--example=socket-options-ipv6',
+        '-u',
+        '--update-data',
+        '-f EXTENSIVE',
+        '--fullness=EXTENSIVE',
+        '-g',
+        '--grind',
+        '-l',
+        '--list',
+        '-m',
+        '--multiple',
+        '-n',
+        '--no-build',
+        '-p first',
+        '--pyexample=first',
+        '-r',
+        '--retain',
+        '-s ns3-tcp-state',
+        '--suite=ns3-tcp-state',
+        '-t t_opt.txt',
+        '--text=t_opt.txt && rm t_opt.txt',
+        '-v',
+        '--verbose',
+        '-w t_opt.html && rm t_opt.html',
+        '--web=t_opt.html && rm t_opt.html',
+        '--html=t_opt.html && rm t_opt.html',
+        '-x t_opt.xml && rm t_opt.xml',
+        '--xml=t_opt.xml && rm t_opt.xml',
     ]
 
     configure_string = sys.executable + ' ns3 configure --enable-tests --enable-examples'
     clean_string = sys.executable + ' ns3 clean'
-    cmd_execute_list = [ '%s && %s test.py %s && %s' % (configure_string, sys.executable, option, clean_string) for option in test_cases]
-    runner = TestBaseClass(argv[1:], "Test suite for the ns-3 unit test runner" , 'test-py')
+    cmd_execute_list = ['%s && %s test.py %s && %s' % (configure_string, sys.executable, option, clean_string) for option in test_cases]
+    runner = TestBaseClass(argv[1:], "Test suite for the ns-3 unit test runner", 'test-py')
     return runner.runtests(cmd_execute_list)
 
 if __name__ == '__main__':
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/utils.py ns-3.40/utils.py
--- ns-3.39/utils.py	2023-07-05 14:23:48.137428500 -0700
+++ ns-3.40/utils.py	2023-09-27 13:30:37.934840000 -0700
@@ -5,7 +5,7 @@
 # should be enabled
 
 import os
-import sys
+
 
 def get_list_from_file(file_path, list_name):
     '''Looks for a Python list called list_name in the file specified
@@ -20,7 +20,7 @@
 
     # Read in the file if it exists.
     if os.path.exists(file_path):
-        with open(file_path, "r") as file_in:
+        with open(file_path, "r", encoding="utf-8") as file_in:
 
             # Look for the list.
             list_string = ""
@@ -58,7 +58,7 @@
 
     # Read in the file if it exists.
     if os.path.exists(file_path):
-        with open(file_path, "r") as file_in:
+        with open(file_path, "r", encoding="utf-8") as file_in:
 
             # Look for the boolean variable.
             bool_found = False
@@ -121,4 +121,3 @@
     tests_enabled = get_bool_from_file(dot_ns3rc_path, 'tests_enabled', value_if_missing)
 
     return (config_file_exists, modules_enabled, examples_enabled, tests_enabled)
-
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.39/VERSION ns-3.40/VERSION
--- ns-3.39/VERSION	2023-07-05 14:24:01.481474000 -0700
+++ ns-3.40/VERSION	2023-09-27 13:30:55.802883400 -0700
@@ -1 +1 @@
-3.39
+3.40
