From 9bf8594c48c43f0405034f1217ca404fbf7318de Mon Sep 17 00:00:00 2001 From: Robert McMahon Date: Fri, 13 Feb 2026 14:35:47 -0800 Subject: [PATCH] Add PHY rate and MCS histograms per RA/TA pair - Extract radiotap.datarate, radiotap.mcs.index, wlan_radio.data_rate, wlan_radio.mcs.index - Generate histograms showing PHY rate distribution per RA/TA pair - Generate histograms showing MCS index distribution per RA/TA pair - Only analyze data frames (type 2) for histograms - Histograms are sorted numerically for easy reading Co-authored-by: Cursor --- test_monitor_tshark.sh | 100 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/test_monitor_tshark.sh b/test_monitor_tshark.sh index 4b32a1d..28dd282 100755 --- a/test_monitor_tshark.sh +++ b/test_monitor_tshark.sh @@ -195,6 +195,7 @@ fi # Now parse the pcap file to extract fields # Only extract 802.11 header fields - data payloads are encrypted +# Include PHY rate and MCS for histograms CAPTURE_OUTPUT=$(tshark -q -r "$TEMP_PCAP" -n -T fields \ -e frame.number \ -e frame.time \ @@ -207,6 +208,10 @@ CAPTURE_OUTPUT=$(tshark -q -r "$TEMP_PCAP" -n -T fields \ -e wlan.fc.retry \ -e wlan.duration \ -e radiotap.present \ + -e radiotap.datarate \ + -e radiotap.mcs.index \ + -e wlan_radio.data_rate \ + -e wlan_radio.mcs.index \ 2>&1 | grep -v "^tshark:" | grep -v "^Running as" | grep -v "^Capturing" || true) # Clean up temp file (unless KEEP_PCAP is set) @@ -302,6 +307,101 @@ if [ -n "$PACKET_LINES" ] && [ "$FINAL_COUNT" -gt 0 ]; then fi echo "" + # Generate PHY rate and MCS histograms per RA/TA pair + echo "PHY Rate and MCS Histograms per RA/TA pair:" + echo "$PACKET_LINES" | awk -F'\t' '{ + ra = ($3 != "" && $3 != "-") ? $3 : "N/A" + ta = ($4 != "" && $4 != "-") ? $4 : "N/A" + if (ra != "N/A" || ta != "N/A") { + pair = ra " -> " ta + + # Get PHY rate (try radiotap.datarate first, then wlan_radio.data_rate) + phy_rate = "" + if ($12 != "" && $12 != "-" && $12 != "0") { + phy_rate = $12 + } else if ($14 != "" && $14 != "-" && $14 != "0") { + phy_rate = $14 + } + + # Get MCS index (try radiotap.mcs.index first, then wlan_radio.mcs.index) + mcs = "" + if ($13 != "" && $13 != "-" && $13 != "0" && $13 != "255") { + mcs = $13 + } else if ($15 != "" && $15 != "-" && $15 != "0" && $15 != "255") { + mcs = $15 + } + + # Only count data frames (type 2) for histograms + type = ($5 != "" && $5 != "-") ? $5 : "" + if (type == "2") { + if (phy_rate != "") { + rate_hist[pair][phy_rate]++ + } + if (mcs != "") { + mcs_hist[pair][mcs]++ + } + } + } + } + END { + # Process each pair + for (pair in rate_hist) { + printf "\n %s:\n", pair + + # PHY Rate histogram + printf " PHY Rate (Mbps):\n" + # Collect rates and sort + n = 0 + for (rate in rate_hist[pair]) { + rates[n++] = rate + 0 + rate_map[rate + 0] = rate + } + # Sort rates + for (i = 0; i < n; i++) { + for (j = i + 1; j < n; j++) { + if (rates[i] > rates[j]) { + tmp = rates[i] + rates[i] = rates[j] + rates[j] = tmp + } + } + } + for (i = 0; i < n; i++) { + rate_val = rates[i] + rate_str = rate_map[rate_val] + printf " %s Mbps: %d frame(s)\n", rate_str, rate_hist[pair][rate_str] + } + + # MCS histogram + if (pair in mcs_hist) { + printf " MCS Index:\n" + m = 0 + for (mcs in mcs_hist[pair]) { + mcs_vals[m++] = mcs + 0 + mcs_map[mcs + 0] = mcs + } + # Sort MCS + for (i = 0; i < m; i++) { + for (j = i + 1; j < m; j++) { + if (mcs_vals[i] > mcs_vals[j]) { + tmp = mcs_vals[i] + mcs_vals[i] = mcs_vals[j] + mcs_vals[j] = tmp + } + } + } + for (i = 0; i < m; i++) { + mcs_val = mcs_vals[i] + mcs_str = mcs_map[mcs_val] + printf " MCS %s: %d frame(s)\n", mcs_str, mcs_hist[pair][mcs_str] + } + } else { + printf " MCS Index: (no MCS data)\n" + } + } + }' + echo "" + # Frame type breakdown echo "Frame type breakdown:" echo "$PACKET_LINES" | awk -F'\t' '{