The sample supports the offline net capture feature in Zephyr, see `Zephyr net capture`_ for details.
See the `Zephyr net capture Linux setup`_ section for instructions on how to set up the Linux host for offline net capture.
Ensure the requirements from `Zephyr net capture`_ are met before proceeding.
To enable this feature in this sample, use the :file:`overlay-net-capture.conf` and :file:`overlay-netusb.conf` configuration overlay files.

When the offline net capture feature is enabled, incoming IEEE 802.11 packets are routed to the offline storage over the net capture tunnel.
These packets can then be analyzed using `Wireshark`_.

Wireshark decode as IEEE 802.11
===============================

The packets from the device are sent to the host over the net capture tunnel using IP in IP tunneling.
The nRF70 Series device sends the IEEE 802.11 packets prepended with a custom metadata over the net capture tunnel to the host.
To analyze the packets in Wireshark, the payload of the UDP packets must be dissected as IEEE 802.11 packets.

This support is only available in Wireshark 4.3 (under development - master branch).
A custom build of Wireshark from the latest sources is required, see `Wireshark Unix Build setup`_ for details.
Once the custom build is installed, complete the following steps to dissect the payload of the UDP packets as IEEE 802.11 packets:

1. Ensure Wireshark is compiled with Lua support, see `Wireshark with Lua`_ for details.
#. Open Wireshark and go to :guilabel:`Analyze` > :guilabel:`Decode As` > :guilabel:`+`, then select :guilabel:`UDP`.
#. In the **Current** column, ensure `IEEE 802.11` is available.

   If not, then the Wireshark version does not have the support to decode the UDP payload as IEEE 802.11 packets, and you need to build Wireshark from the latest sources.

#. Copy the following Lua script to a file, for example, :file:`nordic_decode_raw_80211.lua` file.

   .. code-block:: lua

         -- Create a new dissector
         local nordic_raw_80211 = Proto("nordic_raw_80211", "Nordic Raw 802.11 dissector")

         -- No built-in helper to convert a number to a signed char in Lua
         function toSignedChar(value)
            if value > 127 then
               return value - 256
            else
               return value
            end
         end

         local nordic_rate_flags = {
            NORD_RATE_FLAG_LEGACY = 0,
            NORD_RATE_FLAG_HT = 1,
            NORD_RATE_FLAG_VHT = 2,
            NORD_RATE_FLAG_HE_SU = 3,
            NORD_RATE_FLAG_HE_ER_SU = 4,
            NORD_RATE_FLAG_MAX = 5
         }

         function getRateFlags(rate_flags)
            local rate_flags_str = ""
            if rate_flags == nordic_rate_flags.NORD_RATE_FLAG_LEGACY then
               rate_flags_str = "Legacy"
            elseif rate_flags == nordic_rate_flags.NORD_RATE_FLAG_HT then
               rate_flags_str = "HT"
            elseif rate_flags == nordic_rate_flags.NORD_RATE_FLAG_VHT then
               rate_flags_str = "VHT"
            elseif rate_flags == nordic_rate_flags.NORD_RATE_FLAG_HE_SU then
               rate_flags_str = "HE-SU"
            elseif rate_flags == nordic_rate_flags.NORD_RATE_FLAG_HE_ER_SU then
               rate_flags_str = "HE-ER-SU"
            else
               rate_flags_str = "Unknown"
            end
            return rate_flags_str
         end

         function getRate(rate_flags, rate)
            local rate_str = ""
            -- Lgeacy rates
            if rate_flags == 0x00 then
               if rate == 55 then
                     rate_str = "Data rate: 5.5 Mbps"
               else
                     rate_str = "Data rate: " .. rate .. " Mbps"
               end
            else
               rate_str = "MCS Index" .. rate
            end
            return rate_str
         end

         -- This function will dissect the packet
         function nordic_raw_80211.dissector(buffer, pinfo, tree)
            -- Dissect the first 6 bytes (Raw RX custom header)
            local payload = buffer(6):tvb()
            local subtree = tree:add(nordic_raw_80211, buffer(), "Nordic Raw 802.11 Dissector")
            subtree:add(buffer(0, 2), "Frequency: " .. buffer(0, 2):le_uint())
            -- Convert mBm to dBm and display as signed char
            local mBm = buffer(2, 2):le_int()
            local dBm = toSignedChar(mBm / 100)
            subtree:add(buffer(2, 2), "Signal (dBm): " .. dBm)
            subtree:add(buffer(4, 1), "Rate Flags: " .. getRateFlags(buffer(4, 1):uint()))
            subtree:add(buffer(5, 1), getRate(buffer(4, 1):uint(), buffer(5, 1):uint()))

            local wlan_dissector_name = "wlan"
            local wlan_dissector = Dissector.get(wlan_dissector_name)
            if wlan_dissector == nil then
               print("Error: No dissector found for " .. wlan_dissector_name)
               return
            end
            -- Call IEEE 802.11 dissector
            wlan_dissector:call(payload, pinfo, tree)
         end

         -- Register the dissector
         local netcapture_udp_port = 4242
         local udp_port = DissectorTable.get("udp.port")
         udp_port:add(netcapture_udp_port, nordic_raw_80211)
#. Copy the Lua script to the Wireshark plugin directory.

   The plugin directory can be found in the Wireshark preferences.
#. Open Wireshark and either start capturing packets or open a capture file.
#. The UDP payload for port ``4242`` is now dissected as follows:

   * Nordic Raw 802.11 header
   * IEEE 802.11 packet

   See the reference image below:

   .. figure:: /images/wireshark_decode_as_nordic_80211.png
      :alt: Wireshark decode Nordic Raw 802.11
      :align: center

      UDP payload
