525 lines
19 KiB
Bash
Executable File
525 lines
19 KiB
Bash
Executable File
#!/bin/bash
|
|
# Test script to verify monitor mode works with tshark
|
|
# Usage: ./test_monitor_tshark.sh [interface] [channel] [duration_seconds] [--keep-pcap]
|
|
# Or: KEEP_PCAP=1 sudo -E ./test_monitor_tshark.sh [interface] [channel] [duration_seconds]
|
|
|
|
set -e
|
|
|
|
# Parse arguments
|
|
KEEP_PCAP_FLAG=""
|
|
ARGS=()
|
|
for arg in "$@"; do
|
|
if [ "$arg" = "--keep-pcap" ] || [ "$arg" = "-k" ]; then
|
|
KEEP_PCAP_FLAG="1"
|
|
else
|
|
ARGS+=("$arg")
|
|
fi
|
|
done
|
|
|
|
INTERFACE="${ARGS[0]:-wlan0}"
|
|
CHANNEL="${ARGS[1]:-36}"
|
|
DURATION="${ARGS[2]:-10}" # Default 10 seconds, minimum 1 second
|
|
|
|
# Check for KEEP_PCAP environment variable or flag
|
|
if [ -n "$KEEP_PCAP_FLAG" ]; then
|
|
KEEP_PCAP="1"
|
|
elif [ -z "${KEEP_PCAP:-}" ]; then
|
|
KEEP_PCAP=""
|
|
fi
|
|
|
|
# Ensure minimum 1 second
|
|
if [ "$DURATION" -lt 1 ]; then
|
|
DURATION=1
|
|
fi
|
|
|
|
echo "=== Testing Monitor Mode with tshark ==="
|
|
echo "Interface: $INTERFACE"
|
|
echo "Channel: $CHANNEL"
|
|
echo "Duration: $DURATION seconds"
|
|
echo ""
|
|
|
|
# Check if running as root
|
|
if [ "$EUID" -ne 0 ]; then
|
|
echo "Please run as root (use sudo)"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if tshark is installed
|
|
if ! command -v tshark &> /dev/null; then
|
|
echo "tshark is not installed. Installing..."
|
|
if command -v apt-get &> /dev/null; then
|
|
sudo apt-get update
|
|
sudo apt-get install -y tshark
|
|
elif command -v dnf &> /dev/null; then
|
|
sudo dnf install -y wireshark-cli
|
|
else
|
|
echo "Please install tshark manually"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Unmanage from NetworkManager
|
|
if command -v nmcli &> /dev/null; then
|
|
echo "Unmanaging interface from NetworkManager..."
|
|
nmcli device set "$INTERFACE" managed no 2>/dev/null || true
|
|
fi
|
|
|
|
# Unblock WiFi
|
|
rfkill unblock wifi 2>/dev/null || true
|
|
|
|
# Bring down interface
|
|
echo "Bringing down interface..."
|
|
ip link set "$INTERFACE" down 2>/dev/null || true
|
|
sleep 0.5
|
|
|
|
# Set monitor mode
|
|
echo "Setting monitor mode..."
|
|
if ! iw dev "$INTERFACE" set type monitor; then
|
|
echo "Error: Failed to set monitor mode"
|
|
exit 1
|
|
fi
|
|
|
|
sleep 0.5
|
|
|
|
# Bring up interface
|
|
echo "Bringing up interface..."
|
|
ip link set "$INTERFACE" up || echo "Warning: Failed to bring interface up"
|
|
|
|
sleep 0.5
|
|
|
|
# Set channel
|
|
echo "Setting channel to $CHANNEL..."
|
|
iw dev "$INTERFACE" set channel "$CHANNEL" || echo "Warning: Failed to set channel"
|
|
|
|
# Verify monitor mode
|
|
echo ""
|
|
echo "Verifying monitor mode..."
|
|
iw dev "$INTERFACE" info | grep -E "(type|channel)" || echo "Could not verify"
|
|
|
|
# Check DLT with tshark (capture for 1 second)
|
|
echo ""
|
|
echo "Checking Data Link Type (1 second test capture)..."
|
|
echo "(This may take up to 2 seconds if no packets are present)"
|
|
|
|
# Use timeout with -c to limit packets and avoid hanging
|
|
# Capture both stdout and stderr
|
|
# Fields: frame.number, wlan.ra (Receiver Address), wlan.ta (Transmitter Address), radiotap.present
|
|
# Note: wlan.ra and wlan.ta may not be available for all frame types, but are correct for monitor mode
|
|
TEST_OUTPUT=$(timeout 2 tshark -i "$INTERFACE" -c 100 -T fields \
|
|
-e frame.number \
|
|
-e wlan.ra \
|
|
-e wlan.ta \
|
|
-e radiotap.present \
|
|
2>&1 || true)
|
|
TEST_EXIT_CODE=${PIPESTATUS[0]}
|
|
|
|
# Show any warnings/errors from tshark (but not packet data)
|
|
echo "$TEST_OUTPUT" | grep -E "(Running as|tshark:|Warning|Error|Capturing)" || true
|
|
|
|
# Count packets (lines starting with a number, excluding error messages)
|
|
PACKET_LINES=$(echo "$TEST_OUTPUT" | grep -E '^[0-9]+' || true)
|
|
PACKET_COUNT=$(echo "$PACKET_LINES" | wc -l || echo "0")
|
|
|
|
# Count lines with radiotap.present (4th field) set to 1
|
|
PLCP_COUNT=$(echo "$PACKET_LINES" | awk -F'\t' 'NF >= 4 && $1 != "" && $4 != "" && $4 != "0" && $4 != "-" {count++} END {print count+0}' || echo "0")
|
|
|
|
# Show sample output with better formatting
|
|
if [ "$PACKET_COUNT" -gt 0 ]; then
|
|
echo "Sample packets:"
|
|
echo "$PACKET_LINES" | head -5 | awk -F'\t' '{
|
|
ra = ($2 != "" && $2 != "-") ? $2 : "N/A"
|
|
ta = ($3 != "" && $3 != "-") ? $3 : "N/A"
|
|
radiotap = ($4 == "1" || $4 == "1.0") ? "yes" : "no"
|
|
printf " Frame %s: RA=%s, TA=%s, PLCP=%s\n", $1, ra, ta, radiotap
|
|
}'
|
|
fi
|
|
|
|
echo ""
|
|
echo "Test capture results:"
|
|
echo " Packets captured: $PACKET_COUNT"
|
|
echo " PLCP headers: $PLCP_COUNT"
|
|
if [ "$PLCP_COUNT" -eq 0 ] && [ "$PACKET_COUNT" -gt 0 ]; then
|
|
echo " Note: Packets captured but no radiotap headers (may be using DLT_IEEE802_11 instead of DLT_IEEE802_11_RADIO)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Starting tshark capture ($DURATION seconds) ==="
|
|
echo "Press Ctrl+C to stop early"
|
|
echo ""
|
|
|
|
# Capture for specified duration and count packets
|
|
echo "Capturing packets for $DURATION seconds..."
|
|
|
|
# Use a temporary pcap file to avoid field extraction errors during capture
|
|
# Capture to file first, then parse it - this prevents tshark from exiting early
|
|
TEMP_PCAP=$(mktemp /tmp/tshark_capture_XXXXXX.pcap)
|
|
echo "Capturing to temporary file: $TEMP_PCAP"
|
|
|
|
set +e # Temporarily disable exit on error
|
|
# Capture to pcap file - this won't error on missing fields
|
|
# Use -b filesize:100000 to rotate files if needed, but we'll only use the first
|
|
timeout "$DURATION" tshark -q -i "$INTERFACE" -n -w "$TEMP_PCAP" 2>/dev/null
|
|
CAPTURE_EXIT_CODE=$?
|
|
set -e # Re-enable exit on error
|
|
|
|
# Force sync to ensure file is written
|
|
sync
|
|
|
|
# Exit code 124 means timeout occurred (expected), 0 means command completed normally
|
|
if [ "$CAPTURE_EXIT_CODE" -ne 0 ] && [ "$CAPTURE_EXIT_CODE" -ne 124 ]; then
|
|
echo "Warning: tshark capture exited with code $CAPTURE_EXIT_CODE"
|
|
fi
|
|
|
|
# Check if pcap file exists and get its size
|
|
if [ -f "$TEMP_PCAP" ]; then
|
|
PCAP_SIZE=$(stat -c%s "$TEMP_PCAP" 2>/dev/null || stat -f%z "$TEMP_PCAP" 2>/dev/null || echo "0")
|
|
echo "Pcap file size: $PCAP_SIZE bytes"
|
|
|
|
# Count packets in raw pcap file using capinfos or tshark
|
|
if command -v capinfos &> /dev/null; then
|
|
RAW_PACKET_COUNT=$(capinfos -c "$TEMP_PCAP" 2>/dev/null | grep "^Number of packets:" | awk '{print $4}' || echo "0")
|
|
echo "Raw packets in pcap file: $RAW_PACKET_COUNT"
|
|
else
|
|
# Fallback: use tshark to count packets
|
|
RAW_PACKET_COUNT=$(tshark -q -r "$TEMP_PCAP" -n -T fields -e frame.number 2>/dev/null | tail -1 || echo "0")
|
|
if [ "$RAW_PACKET_COUNT" != "0" ] && [ -n "$RAW_PACKET_COUNT" ]; then
|
|
echo "Raw packets in pcap file: $RAW_PACKET_COUNT"
|
|
else
|
|
echo "Raw packets in pcap file: (could not determine)"
|
|
fi
|
|
fi
|
|
else
|
|
echo "ERROR: Pcap file was not created: $TEMP_PCAP"
|
|
exit 1
|
|
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
|
|
# Extract to temp file first to avoid pipe issues, then filter
|
|
TEMP_TSHARK_OUTPUT=$(mktemp /tmp/tshark_output_XXXXXX.txt)
|
|
tshark -q -r "$TEMP_PCAP" -n -T fields \
|
|
-e frame.number \
|
|
-e frame.time \
|
|
-e wlan.ra \
|
|
-e wlan.ta \
|
|
-e wlan.fc.type \
|
|
-e wlan.fc.subtype \
|
|
-e wlan.fc.type_subtype \
|
|
-e wlan.fc.protected \
|
|
-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>/dev/null > "$TEMP_TSHARK_OUTPUT" || true
|
|
|
|
# Filter out non-packet lines (keep only lines starting with frame numbers)
|
|
CAPTURE_OUTPUT=$(grep -E '^[0-9]+\t' "$TEMP_TSHARK_OUTPUT" || true)
|
|
rm -f "$TEMP_TSHARK_OUTPUT"
|
|
|
|
# Clean up temp file (unless KEEP_PCAP is set)
|
|
if [ -z "$KEEP_PCAP" ]; then
|
|
echo "Cleaning up temporary pcap file: $TEMP_PCAP"
|
|
rm -f "$TEMP_PCAP"
|
|
else
|
|
echo "Keeping temporary pcap file: $TEMP_PCAP"
|
|
echo " (Use: tshark -r $TEMP_PCAP to analyze)"
|
|
fi
|
|
|
|
# Force output flush
|
|
sync
|
|
|
|
# Show stats immediately after capture completes
|
|
echo ""
|
|
echo "=== Capture Statistics ==="
|
|
|
|
# Show any warnings/errors (but not the "Running as root" or "Capturing" messages)
|
|
WARNINGS=$(echo "$CAPTURE_OUTPUT" | grep -E "(tshark:|Warning|Error)" | grep -v -E "(Running as|Capturing)" | head -5 || true)
|
|
if [ -n "$WARNINGS" ]; then
|
|
echo "$WARNINGS"
|
|
echo ""
|
|
fi
|
|
|
|
# Count total packets captured (lines starting with a number followed by tab)
|
|
# Filter out tshark status messages like "100 packets captured" or "Capturing on..."
|
|
# Only count lines that look like actual packet data: number, tab, then more fields
|
|
# Also handle lines that start with just a number (frame.number field)
|
|
PACKET_LINES=$(echo "$CAPTURE_OUTPUT" | grep -E '^[0-9]+' | grep -v -E '(packets captured|Capturing on|Running as|tshark:)' || true)
|
|
FINAL_COUNT=$(echo "$PACKET_LINES" | wc -l || echo "0")
|
|
|
|
# If we got very few packets but raw count shows many, there might be a parsing issue
|
|
if [ "$FINAL_COUNT" -lt "$RAW_PACKET_COUNT" ] && [ "$RAW_PACKET_COUNT" -gt 10 ]; then
|
|
echo "Warning: Parsed $FINAL_COUNT packets but pcap file contains $RAW_PACKET_COUNT packets"
|
|
echo " This may indicate field extraction issues. Check tshark output above."
|
|
fi
|
|
|
|
# Count packets with PLCP headers (radiotap present)
|
|
# radiotap.present is field 11 (after frame.number, frame.time, wlan.ra, wlan.ta, wlan.fc.type, wlan.fc.subtype, wlan.fc.type_subtype, wlan.fc.protected, wlan.fc.retry, wlan.duration)
|
|
PLCP_COUNT=$(echo "$PACKET_LINES" | awk -F'\t' 'NF >= 11 && $1 != "" && $11 != "" && $11 != "0" && $11 != "-" {count++} END {print count+0}' || echo "0")
|
|
|
|
# Display stats immediately - always show these
|
|
echo "Total packets captured: $FINAL_COUNT"
|
|
echo "PLCP headers: $PLCP_COUNT"
|
|
if [ "$FINAL_COUNT" -gt 0 ]; then
|
|
# Calculate rate
|
|
RATE=$(awk "BEGIN {printf \"%.1f\", $FINAL_COUNT / $DURATION}")
|
|
echo "Packet rate: $RATE packets/second"
|
|
fi
|
|
echo ""
|
|
|
|
# Display sample packets with readable format
|
|
if [ -n "$PACKET_LINES" ] && [ "$FINAL_COUNT" -gt 0 ]; then
|
|
echo "Sample packets (first 10):"
|
|
echo "$PACKET_LINES" | head -10 | awk -F'\t' '{
|
|
ra = ($3 != "" && $3 != "-") ? $3 : "N/A"
|
|
ta = ($4 != "" && $4 != "-") ? $4 : "N/A"
|
|
type = ($5 != "" && $5 != "-") ? $5 : "N/A"
|
|
subtype = ($6 != "" && $6 != "-") ? $6 : "N/A"
|
|
protected = ($8 == "1" || $8 == "1.0") ? "encrypted" : "unencrypted"
|
|
retry = ($9 == "1" || $9 == "1.0") ? "retry" : ""
|
|
duration = ($10 != "" && $10 != "-") ? $10 : "N/A"
|
|
radiotap = ($11 == "1" || $11 == "1.0") ? "yes" : (($11 != "" && $11 != "-") ? "no" : "N/A")
|
|
retry_str = (retry != "") ? sprintf(" [%s]", retry) : ""
|
|
printf " Frame %s: RA=%s, TA=%s, type=%s/%s, %s, dur=%s, PLCP=%s%s\n",
|
|
$1, ra, ta, type, subtype, protected, duration, radiotap, retry_str
|
|
}'
|
|
echo ""
|
|
|
|
# Count unique RA/TA pairs
|
|
echo "Unique RA/TA pairs (with counts):"
|
|
UNIQUE_PAIRS=$(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
|
|
count[pair]++
|
|
}
|
|
}
|
|
END {
|
|
for (pair in count) {
|
|
printf "%d\t%s\n", count[pair], pair
|
|
}
|
|
}' | sort -rn)
|
|
|
|
if [ -n "$UNIQUE_PAIRS" ]; then
|
|
echo "$UNIQUE_PAIRS" | awk -F'\t' '{
|
|
printf " %s: %d frame(s)\n", $2, $1
|
|
}'
|
|
else
|
|
echo " (no valid RA/TA pairs found)"
|
|
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' '{
|
|
type = ($5 != "" && $5 != "-") ? $5 : "unknown"
|
|
subtype = ($6 != "" && $6 != "-") ? $6 : "unknown"
|
|
type_name = "Unknown"
|
|
if (type == "0") type_name = "Management"
|
|
else if (type == "1") type_name = "Control"
|
|
else if (type == "2") type_name = "Data"
|
|
count[type_name]++
|
|
}
|
|
END {
|
|
for (t in count) {
|
|
printf " %s: %d frame(s)\n", t, count[t]
|
|
}
|
|
}' | sort -rn
|
|
echo ""
|
|
|
|
# Analyze data frames (iperf uses QoS Data frames, subtype 8)
|
|
echo "Data frame analysis (iperf typically uses QoS Data frames, subtype 8):"
|
|
DATA_FRAMES=$(echo "$PACKET_LINES" | awk -F'\t' '{
|
|
type = ($5 != "" && $5 != "-") ? $5 : ""
|
|
subtype = ($6 != "" && $6 != "-") ? $6 : ""
|
|
if (type == "2" && subtype == "8") { # QoS Data frames
|
|
print $0
|
|
}
|
|
}')
|
|
DATA_COUNT=$(echo "$DATA_FRAMES" | wc -l || echo "0")
|
|
echo " QoS Data frames (type 2, subtype 8): $DATA_COUNT"
|
|
|
|
# Count encrypted vs unencrypted data frames
|
|
ENCRYPTED_DATA=$(echo "$DATA_FRAMES" | awk -F'\t' '$8 == "1" || $8 == "1.0" {count++} END {print count+0}')
|
|
UNENCRYPTED_DATA=$(echo "$DATA_FRAMES" | awk -F'\t' '$8 != "1" && $8 != "1.0" && $8 != "" && $8 != "-" {count++} END {print count+0}')
|
|
echo " Encrypted: $ENCRYPTED_DATA"
|
|
echo " Unencrypted: $UNENCRYPTED_DATA"
|
|
|
|
if [ "$DATA_COUNT" -gt 0 ]; then
|
|
echo " Sample QoS Data frames (likely iperf traffic):"
|
|
echo "$DATA_FRAMES" | head -5 | awk -F'\t' '{
|
|
ra = ($3 != "" && $3 != "-") ? $3 : "N/A"
|
|
ta = ($4 != "" && $4 != "-") ? $4 : "N/A"
|
|
protected = ($8 == "1" || $8 == "1.0") ? "encrypted" : "unencrypted"
|
|
retry = ($9 == "1" || $9 == "1.0") ? "retry" : ""
|
|
duration = ($10 != "" && $10 != "-") ? $10 : "N/A"
|
|
retry_str = (retry != "") ? sprintf(" [%s]", retry) : ""
|
|
printf " Frame %s: RA=%s, TA=%s, %s, dur=%s%s\n",
|
|
$1, ra, ta, protected, duration, retry_str
|
|
}'
|
|
fi
|
|
echo ""
|
|
|
|
# Frames involving server MAC (80:84:89:93:c4:b6)
|
|
echo "Frames involving server MAC (80:84:89:93:c4:b6):"
|
|
SERVER_MAC="80:84:89:93:c4:b6"
|
|
SERVER_FRAMES=$(echo "$PACKET_LINES" | awk -F'\t' -v mac="$SERVER_MAC" '{
|
|
ra = ($3 != "" && $3 != "-") ? $3 : ""
|
|
ta = ($4 != "" && $4 != "-") ? $4 : ""
|
|
if (ra == mac || ta == mac) {
|
|
print $0
|
|
}
|
|
}')
|
|
SERVER_COUNT=$(echo "$SERVER_FRAMES" | wc -l || echo "0")
|
|
echo " Total frames with server MAC: $SERVER_COUNT"
|
|
if [ "$SERVER_COUNT" -gt 0 ]; then
|
|
echo " Frame type breakdown:"
|
|
echo "$SERVER_FRAMES" | awk -F'\t' '{
|
|
type = ($5 != "" && $5 != "-") ? $5 : "unknown"
|
|
subtype = ($6 != "" && $6 != "-") ? $6 : "unknown"
|
|
type_name = "Unknown"
|
|
if (type == "0") type_name = "Management"
|
|
else if (type == "1") type_name = "Control"
|
|
else if (type == "2") type_name = "Data"
|
|
count[type_name]++
|
|
}
|
|
END {
|
|
for (t in count) {
|
|
printf " %s: %d frame(s)\n", t, count[t]
|
|
}
|
|
}' | sort -rn
|
|
echo " Sample frames:"
|
|
echo "$SERVER_FRAMES" | head -5 | awk -F'\t' '{
|
|
ra = ($3 != "" && $3 != "-") ? $3 : "N/A"
|
|
ta = ($4 != "" && $4 != "-") ? $4 : "N/A"
|
|
type = ($5 != "" && $5 != "-") ? $5 : "N/A"
|
|
subtype = ($6 != "" && $6 != "-") ? $6 : "N/A"
|
|
protected = ($8 == "1" || $8 == "1.0") ? "encrypted" : "unencrypted"
|
|
retry = ($9 == "1" || $9 == "1.0") ? "retry" : ""
|
|
duration = ($10 != "" && $10 != "-") ? $10 : "N/A"
|
|
retry_str = (retry != "") ? sprintf(" [%s]", retry) : ""
|
|
printf " Frame %s: RA=%s, TA=%s, type=%s/%s, %s, dur=%s%s\n",
|
|
$1, ra, ta, type, subtype, protected, duration, retry_str
|
|
}'
|
|
fi
|
|
echo ""
|
|
else
|
|
echo "(No packets captured)"
|
|
echo ""
|
|
fi
|
|
|
|
echo "=== Summary ==="
|
|
if [ "$FINAL_COUNT" -gt 0 ]; then
|
|
echo "✓ Monitor mode is working! Captured $FINAL_COUNT packet(s)"
|
|
if [ "$PLCP_COUNT" -gt 0 ]; then
|
|
echo "✓ PLCP headers detected: $PLCP_COUNT packet(s) with radiotap information"
|
|
else
|
|
echo "⚠ No PLCP headers detected (may be using DLT_IEEE802_11 instead of DLT_IEEE802_11_RADIO)"
|
|
fi
|
|
else
|
|
echo "✗ No packets captured. Check:"
|
|
echo " 1. Is there WiFi traffic on channel $CHANNEL?"
|
|
echo " 2. Is the interface actually in monitor mode? (iw dev $INTERFACE info)"
|
|
echo " 3. Try a different channel (e.g., 1, 6, 11 for 2.4GHz)"
|
|
echo " 4. Try a longer duration: sudo ./test_monitor_tshark.sh $INTERFACE $CHANNEL 30"
|
|
fi
|