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 <cursoragent@cursor.com>
This commit is contained in:
Robert McMahon 2026-02-13 14:35:47 -08:00
parent 43c096e5d2
commit 9bf8594c48
1 changed files with 100 additions and 0 deletions

View File

@ -195,6 +195,7 @@ fi
# Now parse the pcap file to extract fields # Now parse the pcap file to extract fields
# Only extract 802.11 header fields - data payloads are encrypted # 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 \ CAPTURE_OUTPUT=$(tshark -q -r "$TEMP_PCAP" -n -T fields \
-e frame.number \ -e frame.number \
-e frame.time \ -e frame.time \
@ -207,6 +208,10 @@ CAPTURE_OUTPUT=$(tshark -q -r "$TEMP_PCAP" -n -T fields \
-e wlan.fc.retry \ -e wlan.fc.retry \
-e wlan.duration \ -e wlan.duration \
-e radiotap.present \ -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) 2>&1 | grep -v "^tshark:" | grep -v "^Running as" | grep -v "^Capturing" || true)
# Clean up temp file (unless KEEP_PCAP is set) # Clean up temp file (unless KEEP_PCAP is set)
@ -302,6 +307,101 @@ if [ -n "$PACKET_LINES" ] && [ "$FINAL_COUNT" -gt 0 ]; then
fi fi
echo "" 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 # Frame type breakdown
echo "Frame type breakdown:" echo "Frame type breakdown:"
echo "$PACKET_LINES" | awk -F'\t' '{ echo "$PACKET_LINES" | awk -F'\t' '{