802.11 ANALYSIS · COMMAND LINE

tshark for Wi-Fi — The Field Guide

tshark is Wireshark’s dissection engine on the command line. It uses the exact same dissectors as the GUI, so any field you can see in Wireshark’s detail pane has a filter name you can use here — but on the CLI you can count it, script it, and repeat it across a thousand captures. For 802.11 work, that turns a slow point-and-click into a one-line answer. This is the guide I wish existed when I started: every command below is verified against Wireshark/tshark, and it is entirely vendor-neutral.

Wireshark / tshark CLI CWAP analysis workflow

The mental model: a pipeline

Every tshark run is the same four-stage pipeline. Learn the stages and the flags stop feeling arbitrary:

read / capture    dissect    display filter (-Y)    select & format (-T / -e)

-r reads a saved file, -i captures live. -Y keeps only the frames you want (after dissection, so it can reference any field). -T plus -e decides what to print. Because dissection happens before the filter, a display filter can reference any field the GUI shows — that is the whole trick.

Reading a file vs capturing live

-r file.pcap

Read a saved capture (pcap or pcapng). This is where most analysis lives — reproducible, shareable, and safe to run a hundred different ways against the same bytes.

-i wlan0mon -f "..."

Capture live. For over-the-air 802.11 you need an interface in monitor mode; frames then arrive wrapped in a radiotap header carrying RSSI, channel, and rate.

Capture filter (-f) vs display filter (-Y). -f is a libpcap/BPF filter applied before dissection — it cannot reference dissected fields like wlan.ssid, only low-level frame structure. -Y is applied after dissection and can reference anything. Rule of thumb: -f to limit what you capture, -Y to analyze what you already have.

The output modes you actually need

default One summary line per packet — the same column view as the Wireshark packet list. Good for a quick scan of a capture.
-V Full packet detail tree for every frame: every dissected field, every layer. Verbose — pair with -c to cap, or -Y to narrow first.
-O wlan Detail tree for one protocol only (here, 802.11). The fastest way to see exactly how a single frame is laid out, field by field, with decoded values.
-T fields -e f Columnar extraction: print only the fields you name with -e. The workhorse for counting, scripting, and feeding other tools. Repeat -e for more columns.
-T json Structured JSON of the full dissection, for programmatic consumption. Use -T ek for line-delimited JSON on very large captures.
-x Hex + ASCII dump of the raw bytes alongside the tree. Useful when you want to correlate a decoded field back to its exact offset.

802.11 display filters that matter

These are the fields you reach for most in Wi-Fi analysis. Every one works after -Y (to filter) or after -e (to extract).

wlan.fc.type_subtype Frame type + subtype in one value: (type << 4) | subtype. Beacon 0x08, ProbeReq 0x04, ProbeResp 0x05, AssocReq 0x00, AssocResp 0x01, Auth 0x0b, Deauth 0x0c, Disassoc 0x0a, Action 0x0d; RTS 0x1b, CTS 0x1c, ACK 0x1d, BlockAck 0x19, Trigger 0x12; Data 0x20, QoS Data 0x28, Null 0x24.
wlan.sa / wlan.da Source / destination MAC. wlan.ta / wlan.ra are the transmitter / receiver addresses (the ones on the air); wlan.bssid is the cell identifier.
wlan.ssid SSID element, present in Beacon, Probe Request/Response, and (Re)Association Request. Filter or extract network names directly.
wlan.fc.retry Retry bit. wlan.fc.retry==1 selects retransmitted frames — the observable proxy for contention, weak links, or interference.
wlan.fixed.reason_code Reason code carried by Deauthentication / Disassociation. Tells you WHY a station left (e.g. 3 = leaving, 7 = class-3 from non-associated STA, 15 = 4-way timeout).
wlan.fixed.status_code Status code in Authentication / Association Response. 0 = success; non-zero explains a rejected join (e.g. 1 = unspecified, 17 = AP full).
radiotap.dbm_antsignal Per-frame RSSI in dBm, from the radiotap capture header. wlan_radio.channel and radiotap.channel.freq give the channel/frequency the sniffer heard it on.
wlan.tag / wlan.ext_tag Information Elements by ID. wlan.tag.number selects a specific IE; extension elements (HE, EHT) live under wlan.ext_tag.

Field-extraction recipes

This is where tshark earns its keep. Each recipe is one line and answers a real question.

Every unique SSID in a capture
tshark -r capture.pcap -Y 'wlan.fc.type_subtype==0x08' -T fields -e wlan.ssid | sort -u

Beacons only; drop the -Y to include probe frames and see what clients are searching for.

Frame-type histogram (what is this capture made of?)
tshark -r capture.pcap -T fields -e wlan.fc.type_subtype | sort | uniq -c | sort -rn

Instant breakdown of management / control / data mix. A high control-frame share hints at a busy or lossy channel.

RSSI heard per BSSID
tshark -r capture.pcap -Y 'wlan.fc.type_subtype==0x08' -T fields -e wlan.bssid -e radiotap.dbm_antsignal | sort | uniq -c

Remember this is the SNIFFER’s RSSI, not the client’s or AP’s reception — vantage matters.

Why did stations leave? (deauth / disassoc reasons)
tshark -r capture.pcap -Y 'wlan.fc.type_subtype==0x0c || wlan.fc.type_subtype==0x0a' -T fields -e wlan.sa -e wlan.da -e wlan.fixed.reason_code

Pair reason codes with the sender to separate AP-initiated from client-initiated departures.

Retry rate (contention / link-quality proxy)
echo "retries: $(tshark -r capture.pcap -Y 'wlan.fc.retry==1' 2>/dev/null | wc -l)  total: $(tshark -r capture.pcap -Y 'wlan' 2>/dev/null | wc -l)"

A rising retry fraction as more devices contend is exactly what CSMA/CA predicts.

Clean CSV for a spreadsheet or script
tshark -r capture.pcap -T fields -E header=y -E separator=, -E quote=d -e frame.time_relative -e wlan.fc.type_subtype -e wlan.sa -e wlan.da -e radiotap.dbm_antsignal > frames.csv

-E header=y adds a header row; separator and quote make it spreadsheet-safe.

The byte-level view — and tshark as ground truth

When you are unsure how a frame is really structured, do not guess — tshark is the reference dissector. Read one frame’s full tree, discover field names, and line the decoded values up against the raw bytes.

tshark -r capture.pcap -Y 'wlan.fc.type_subtype==0x08' -c 1 -O wlan

Full 802.11 tree for one beacon: every field name, every decoded value, in the order they sit in the frame. This is how you learn a frame’s real structure instead of guessing at it.

tshark -G fields | grep -i 'trigger'

Discover the exact filter name for any field. -G fields lists every field the installed dissectors know; grep for a keyword to find what to put after -e or -Y.

tshark -r capture.pcap -Y 'wlan.fc.type_subtype==0x08' -c 1 -x

Hex + ASCII of one frame. Line the bytes up against the -O wlan tree to map a value back to its exact offset — the reference dissector and the raw bytes, side by side.

The method. If you are learning a frame format, writing a parser, or teaching one — hand-decode the bytes yourself, then check your answer against tshark’s -O wlan tree. Where they disagree, tshark is almost always right and your mental model needs a fix. Using the reference dissector as an oracle is the single fastest way to build correct intuition about the air.

Statistics taps (-z)

Pair -z with -q to get just the report. These give a shape-of-the-capture read in one command.

tshark -r capture.pcap -q -z io,phs

Protocol hierarchy: the share of frames at each layer. A one-glance shape of the whole capture.

tshark -r capture.pcap -q -z expert

Expert-info summary: malformed frames, retransmissions, and other dissector-flagged anomalies grouped by severity.

tshark -r capture.pcap -q -z io,stat,1

Frames (and bytes) per 1-second bucket — a quick time series to spot bursts, gaps, or a capture that stopped early.

Speed & correctness flags

-n Disable name resolution (DNS, OUI, port names). Faster and quieter on large captures; you almost always want this for scripted extraction.
-c N Stop after N packets. Essential when pairing with -V / -O so you do not dump the whole capture while exploring.
-2 Two-pass analysis. Needed when a display filter references state only known after the whole capture is read (reassembly, later frames). Slower, but correct.
-q Quiet on stdout — use with -z statistics so you get only the report, not a per-packet dump.
-w out.pcap Write matching frames back out (with -Y) to carve a focused sub-capture from a large one for sharing or deeper work.

Gotchas worth knowing

  • Radiotap and FCS. Over-the-air captures carry a radiotap header (link type 127); RSSI and channel live there, not in the 802.11 header. Whether a trailing FCS is present depends on the adapter — some strip it, some keep it, and it changes where the frame ends.
  • Monitor mode is mandatory for the air. A normal managed interface only hands you decrypted data frames for your own association. To see beacons, control frames, and other stations, the radio must be in monitor mode on the right channel.
  • Discover field names, do not memorize them. tshark -G fields | grep -i keyword is faster and never wrong. The dissector is the source of truth for what is filterable.
  • Quote your filters. Wrap -Y and -f arguments in single quotes so the shell does not eat the ==, ||, or spaces.
  • Two-pass when the filter looks ahead. Filters that depend on later frames or reassembly need -2. If a filter mysteriously matches nothing on a single pass, that is often why.

Cheat sheet

Read a capture, summary view tshark -r f.pcap
Capture live in monitor mode tshark -i wlan0mon
Filter to beacons tshark -r f.pcap -Y 'wlan.fc.type_subtype==0x08'
One frame, full 802.11 tree tshark -r f.pcap -c 1 -O wlan
Extract two fields as columns tshark -r f.pcap -T fields -e wlan.sa -e wlan.ssid
Find a field name tshark -G fields | grep -i ssid
Count by frame type tshark -r f.pcap -T fields -e wlan.fc.type_subtype | sort | uniq -c
Protocol hierarchy tshark -r f.pcap -q -z io,phs
Carve a sub-capture tshark -r f.pcap -Y 'wlan.addr==aa:bb:cc:dd:ee:ff' -w sub.pcap
// keep going
Wireshark Filters → WLAN Pi PCAP Guide → Frame Types → MAC Frame Format → The Sniffer Vantage Trap →

External references: the official tshark man page (wireshark.org/docs), tshark.dev, and the Wireshark display-filter reference. All commands on this page were verified against Wireshark/tshark 4.2.