Commit Graph

46 Commits

Author SHA1 Message Date
Robert McMahon 77fb5c69d4 Only show tcpdump message when tcpdump is available
- Check for tcpdump availability before printing startup message
- Show 'Note: tcpdump not found, skipping concurrent count' when unavailable
- Prevents confusing message when tcpdump is not installed

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:51:57 -08:00
Robert McMahon 1ef363f644 Improve tcpdump counter error handling and debugging
- Add detailed error messages when tcpdump fails or produces no output
- Show tcpdump stderr output for debugging filter issues
- Return 0 instead of None when tcpdump finds 0 packets (so it's displayed)
- Handle SIGTERM return code properly (expected when terminating)
- Display tcpdump count even when 0 to help diagnose issues
- Add note when tcpdump counter is unavailable

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:50:21 -08:00
Robert McMahon fc9b8c7f00 Add concurrent tcpdump counter for data frame comparison
- Run tcpdump concurrently with scapy to count data frames
- Use BPF filter (wlan[0] & 0x0C == 0x08) to filter data frames only
- Display comparison between scapy and tcpdump data frame counts
- Show capture ratio to identify if scapy is missing packets
- Add re import for regex parsing of tcpdump output

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:47:50 -08:00
Robert McMahon e52cd355e7 Change duration argument to time and add timestamps to sample packets
- Change CLI argument from -d/--duration to -t/--time
- Add timestamps with milliseconds to sample packets output
- Update all documentation examples to use --time/-t
- Format timestamps as HH:MM:SS.mmm for better readability

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:44:16 -08:00
Robert McMahon 12c57df2a2 Refactor CLI to use argparse key-value pairs and improve data frame analysis
- Replace custom argument parsing with argparse for better CLI design
- Use key-value pairs: --interface/-i, --channel/-c, --duration/-d, --pcap
- Remove iperf-specific references (server MAC analysis, iperf mentions)
- Improve data frame subtype detection for encrypted frames
- Add _get_subtype_from_fc() to parse Frame Control field directly
- Show data frame subtype breakdown in analysis output
- Add better debugging when QoS Data frames aren't found
- Maintain backward compatibility for positional pcap file argument

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:40:08 -08:00
Robert McMahon 9ff3cb9793 Fix async subprocess communication and remove unsupported snaplen parameter
- Fix async subprocess.communicate() usage: await before unpacking tuple
  Changed from: stderr = await proc.communicate()[1]
  To: _, stderr = await proc.communicate()
- Remove snaplen parameter from sniff() calls (not supported for live interface capture)
- Update messages to reflect that full packets are captured for live capture
- Remove redundant proc.wait() calls after communicate()

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:36:19 -08:00
Robert McMahon 96aab517af fix communicate and await 2026-02-13 15:34:47 -08:00
Robert McMahon e09456aab9 Refactor MonitorModeSetup to WiFiMonitor with async start/stop methods
- Rename MonitorModeSetup class to WiFiMonitor (better naming)
- Add async start() method for setting up monitor mode
- Add async stop() method for restoring interface to managed mode
- Convert all subprocess calls to async (asyncio.create_subprocess_exec)
- Add is_started property to track monitor mode state
- Update capture methods to use async implementation
- Use try/finally to ensure proper cleanup
- Run blocking scapy sniff() calls in executor for async compatibility
- Improve error handling with proper stderr communication

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:30:13 -08:00
Robert McMahon b67107e53e Refactor WiFi monitor script: improve code quality and rename
- Rename test_monitor.py to wifi_monitor.py (better naming)
- Delete parse_tshark_pcap.py (deprecated, replaced by wifi_monitor.py)
- Refactor to class-based architecture for better modularity:
  * Config: Configuration management
  * MonitorModeSetup: Monitor mode setup operations
  * PacketParser: Packet parsing utilities
  * PacketAnalyzer: Packet analysis and statistics
  * PacketCapture: Capture operations (PCAP and live)
  * ArgumentParser: Command line argument parsing
- Add properties where appropriate (snaplen, is_successful, error_message)
- Remove 'get_' prefix from utility methods (Python convention)
- Fix Python convention violations:
  * Replace wildcard imports with explicit imports
  * Use specific exception types instead of bare Exception
  * Organize imports (stdlib, third-party)
  * Remove unused imports
- Single exit point pattern throughout code
- Remove trailing whitespace

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:19:18 -08:00
Robert McMahon d3a4937d0a Add PCAP file reading support and packet size limiting option
- Support reading from PCAP files: python3 test_monitor.py file.pcap
- Add --full-packet flag to capture entire packets (default: header-only, 256 bytes)
- Default snaplen=256 bytes captures 802.11 header + some payload
- Mutually exclusive modes: PCAP file reading vs live interface capture
- Improves memory efficiency by default (header-only capture)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:09:23 -08:00
Robert McMahon 04e05c409a Replace bash script with pure Python scapy-based monitor script
- Created test_monitor.py: single Python script using scapy for packet capture
- Removed test_monitor_tshark.sh: replaced by Python solution
- Avoids tshark parsing issues by using scapy directly
- Provides same functionality: RA/TA extraction, histograms, statistics
- Supports --keep-pcap flag for saving pcap files

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:04:57 -08:00
Robert McMahon 5132a667e9 Fix Python parser: improve field parsing robustness and add debug output
- Use int() parsing instead of isdigit() for more robust frame number validation
- Preserve leading tabs with rstrip() instead of strip()
- Add debug output when parsing fails to help diagnose issues
- Handle empty fields and whitespace more gracefully

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 15:01:32 -08:00
Robert McMahon 3cb36bff4b Replace bash/awk parsing with Python script for robust tshark output parsing
- Created parse_tshark_pcap.py to handle tshark field extraction
- Python script gracefully handles missing fields and filters error messages
- Replaced complex bash/awk parsing logic in test_monitor_tshark.sh
- Fixes regression where stderr redirection prevented packet parsing
- Python approach is more maintainable and robust

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:58:39 -08:00
Robert McMahon 7e9006a69b Fix packet parsing regression: use flexible grep pattern
- Change grep pattern from '^[0-9]+\t' (requires tab) to '^[0-9]+' (matches working test capture)
- Add -q flag back to suppress packet count output
- Filter out empty lines and whitespace-only lines
- Fix debug section to use temp file before deletion

This fixes the regression where only 1 packet was parsed despite the pcap
file containing 216 packets. The tab requirement in the grep pattern was
too strict and didn't match tshark's actual output format.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:52:41 -08:00
Robert McMahon 8c9487984a Fix regression: use temp file for tshark output parsing
- Write tshark output to temp file first to avoid pipe issues
- Redirect stderr to /dev/null to suppress field errors
- Filter to only keep lines starting with frame numbers
- This should fix the issue where only 1 packet was parsed instead of 217

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:37:41 -08:00
Robert McMahon b01098a613 Fix regression: improve packet parsing robustness
- Filter output to only keep lines starting with frame numbers
- Remove complex error filtering that was removing valid packet data
- Use head to limit output size
- This should fix the issue where only 1 packet was parsed instead of 217

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:37:29 -08:00
Robert McMahon 9bf8594c48 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>
2026-02-13 14:35:47 -08:00
Robert McMahon 43c096e5d2 Focus analysis on 802.11 headers only, ignore encrypted payloads
- Remove IP/TCP/UDP field extraction (payloads are encrypted)
- Extract 802.11 frame control fields: protected, retry, duration
- Analyze QoS Data frames (type 2, subtype 8) which iperf uses
- Show encryption status and frame characteristics
- Update field numbers for radiotap.present (now field 11)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:31:16 -08:00
Robert McMahon ee168ad839 Add IP traffic analysis to identify iperf packets
- Extract IP addresses, TCP/UDP ports from frames
- Look for TCP port 5001 (iperf default)
- Show frame type breakdown (Management/Control/Data)
- Analyze frames involving server MAC address
- This will help identify where iperf traffic is in the capture

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:29:38 -08:00
Robert McMahon 0b946a6d53 Fix packet parsing by removing restrictive display filter
- Remove -Y filter that was excluding frames without RA/TA
- Process all frames and handle missing fields gracefully
- Add warning when parsed count differs from raw packet count
- This should fix the issue where pcap has 217 packets but script only shows 1

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:24:14 -08:00
Robert McMahon bc282a348a Fix KEEP_PCAP not working with sudo
- Add --keep-pcap command-line flag that works with sudo
- Environment variable KEEP_PCAP still works with 'sudo -E'
- Usage: sudo ./test_monitor_tshark.sh wlan0 36 10 --keep-pcap
- Or: KEEP_PCAP=1 sudo -E ./test_monitor_tshark.sh wlan0 36 10

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:15:23 -08:00
Robert McMahon ba4fb72a40 Add diagnostics for pcap file capture issues
- Check if pcap file exists and show its size
- Count raw packets in pcap file using capinfos or tshark
- Add sync after capture to ensure file is written
- This will help diagnose why main capture shows few/no packets

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:13:19 -08:00
Robert McMahon 73358f9223 Add cleanup message and option to keep temporary pcap file
- Show message when deleting temporary pcap file
- Add KEEP_PCAP environment variable option to keep the file for analysis
  Usage: KEEP_PCAP=1 sudo ./test_monitor_tshark.sh wlan0 36 10

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:10:36 -08:00
Robert McMahon 84a16cf62b Add unique RA/TA pair counting to test_monitor_tshark.sh
Display unique RA/TA pairs with frame counts, sorted by count (descending).
This helps identify which devices are communicating with each other and
the volume of traffic between each pair.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:08:25 -08:00
Robert McMahon 39058bdbf3 Output temporary pcap filename for debugging
Display the name of the temporary pcap file being used for capture.
This helps with debugging and allows users to inspect the file if needed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:07:28 -08:00
Robert McMahon 5ee50bc184 Fix capture by using pcap file intermediate step
Capture to a temporary pcap file first, then parse it. This prevents
tshark from exiting early when encountering frames without RA/TA fields
during live capture. The capture phase won't error on missing fields,
and the parsing phase uses a display filter to only extract RA/TA from
frames that have them.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:06:59 -08:00
Robert McMahon aed791efae Suppress stderr to allow tshark to continue despite field errors
Redirect stderr to /dev/null to suppress 'Some fields aren't valid' errors
when tshark encounters frames without RA/TA fields. This should allow
tshark to continue capturing instead of exiting early.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:05:34 -08:00
Robert McMahon 189444c88f Add display filter to capture only frames with RA/TA
Use tshark display filter to only capture frames that have RA or TA fields.
This prevents tshark from erroring when encountering management frames
that don't have these fields, which was causing early termination of captures.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:04:11 -08:00
Robert McMahon a50c03166c Improve tshark error handling and packet counting
- Add -q flag to suppress tshark summary output
- Handle exit code 1 (field availability issues) as non-fatal
- Better filter out tshark status messages from packet counting
- Improve packet line detection to exclude status messages

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:02:50 -08:00
Robert McMahon 744bc35597 Fix tshark field names for RA/TA display
Replace invalid wlan.addr1/wlan.addr2 with wlan.ra/wlan.ta fields.
These fields are the correct tshark field names for Receiver Address
and Transmitter Address in monitor mode captures.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:01:36 -08:00
Robert McMahon 1e9191f6c7 Fix timeout handling and display RA/TA in test_monitor_tshark.sh
- Fix script exit on timeout: handle exit code 124 from timeout command
- Add RA (Receiver Address) and TA (Transmitter Address) display in initial test capture
- Update main capture to show RA/TA instead of SA/DA for better monitor mode visibility
- Use wlan.addr1 and wlan.addr2 fields for universal compatibility across frame types

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 14:00:08 -08:00
Robert McMahon 8d607a5f66 Improve packet display formatting in test_monitor_tshark.sh
- Replace raw tab-separated values with readable format
- Show 'Frame X: PLCP header (radiotap) = yes/no' instead of '1 1'
- Add field labels for main capture sample packets
- Show SA, DA, type, subtype, and PLCP status in readable format

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 13:56:46 -08:00
Robert McMahon 8576960251 Fix stats display in test_monitor_tshark.sh
- Filter out 'X packets captured' summary lines from packet count
- Only count lines with tab-separated fields (actual packet data)
- Add sync to force output flush
- Ensure stats always display immediately after capture
- Remove trap that was interfering with normal flow

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 13:55:54 -08:00
Robert McMahon fb7dca0137 Show capture statistics immediately after capture completes
- Display stats right after 'Capturing packets' line completes
- Show packet count, PLCP count, and packet rate immediately
- Move sample packets display after stats
- Reorganize output for better readability

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 13:54:11 -08:00
Robert McMahon b80a9d818b Fix test_monitor_tshark.sh to always show counters
- Add message that capture may take time
- Always display packet and PLCP counts
- Better parsing of tshark output
- Separate warnings/errors from packet data
- Show note if packets captured but no PLCP headers

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 13:52:07 -08:00
Robert McMahon cc180b7868 Improve test_monitor_tshark.sh output and error handling
- Add progress messages and debug output
- Show tshark warnings/errors
- Always display counters even if no packets captured
- Better handling of empty output
- Show sample packets when available
- Add DLT check before capture

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 13:51:54 -08:00
Robert McMahon a98a255147 Add PLCP header counting to test_monitor_tshark.sh
- Add radiotap.present field to capture output
- Count packets with PLCP headers (radiotap information)
- Display PLCP count in both test capture and final summary
- Show warning if no PLCP headers detected (may indicate wrong DLT)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 13:50:00 -08:00
Robert McMahon 5827518041 Fix compilation errors in monitor.c
- Add forward declaration for verify_monitor_mode
- Initialize cb to NULL in verify_monitor_mode
- Add missing nla_put_failure label and error handling

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 13:49:06 -08:00
Robert McMahon 680253c120 Improve test_monitor_tshark.sh: add duration option and better packet counting
- Add duration parameter (3rd argument, default 10 seconds, minimum 1 second)
- Change initial check to capture for 1 second instead of just 1 packet
- Count packets from actual capture output instead of running twice
- Fix field names (use wlan.fc.type/subtype instead of wlan.type)
- Show packet count summary at the end
- Display more packets (50 instead of 20)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 13:47:51 -08:00
Robert McMahon fa93fc26f1 Add tshark test script and fix monitor mode setup
- Add test_monitor_tshark.sh to verify monitor mode works with tshark
- Fix set_monitor_mode to wait for Netlink response
- Improve libpcap initialization with pcap_create/pcap_set_rfmon/pcap_activate
- Add interface up/down control before/after setting monitor mode
- Add verification step to confirm monitor mode was set correctly

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 13:44:28 -08:00
Robert McMahon 122484463f Improve channel verification and add debug output
- Add fallback channel verification using 'iw' command
- Show data link type on startup
- Print first 10 non-data frames for debugging
- Add periodic status during capture loop

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 11:54:48 -08:00
Robert McMahon 2fcc2e9691 Add channel verification after setting monitor mode
- Add get_current_channel() function to query actual channel/frequency
- Add freq_to_channel() helper to convert frequency back to channel
- Display verified channel and frequency after setting monitor mode
- Warn if requested channel doesn't match actual channel

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 11:52:56 -08:00
Robert McMahon f9acd111f6 Update README.md: fix pkg-config package name for Fedora
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 13:34:41 -08:00
Robert McMahon 7fc038afcf Add INSTALL.md with dependency installation instructions for Fedora and Debian
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 13:33:41 -08:00
Robert McMahon bd34a6c249 Fix build system issues
- Remove obsolete AC_PROG_CC_C99 macro
- Fix Makefile.am: remove undefined wireless_monitor_HEADERS
- Add missing automake helper scripts

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 13:30:32 -08:00
Robert McMahon 38fbce9061 Initial commit: Linux wireless monitor for ESP32 verification
A C program using GNU Automake for capturing and parsing 802.11 WiFi
frame headers in monitor mode. Designed to verify ESP32 monitor code
by comparing Linux vs ESP32 frame parsing.

Features:
- Monitor mode setup using libnl3
- Packet capture using libpcap
- 802.11 frame parsing (RA, TA, duration, retry flag)
- MAC address filtering (matches ESP32 filter behavior)
- Output format matches ESP32 debug logs for easy comparison

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 13:26:17 -08:00