xref: /aosp_15_r20/external/autotest/docs/wifi-basics-codelab.md (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Codelab: Using wifi Autotests to learn 802.11 basics
2*9c5db199SXin Li
3*9c5db199SXin LiThe Autotest infrastructure provides packet capture functionality which we can
4*9c5db199SXin Liuse to intercept and view WiFi packets that are sent between the
5*9c5db199SXin LiDevice-Under-Test (DUT) and router during a test. In this codelab we will
6*9c5db199SXin Lianalyze the packet sequence during the connection process to learn the basics
7*9c5db199SXin Liof 802.11 connection protocols.
8*9c5db199SXin Li
9*9c5db199SXin Li## Setup
10*9c5db199SXin Li
11*9c5db199SXin Li### Prerequisites
12*9c5db199SXin Li
13*9c5db199SXin Li* Access to a wifi test setup (local or in test lab). Read the
14*9c5db199SXin Li  [wificell documentation] for some background.
15*9c5db199SXin Li* Understanding of Autotest and the [test_that] command.
16*9c5db199SXin Li
17*9c5db199SXin Li### Configuration Considerations
18*9c5db199SXin Li
19*9c5db199SXin LiThis codelab can be completed from either a personal testing setup or a
20*9c5db199SXin Lidedicated setup in our testing lab, but there are a few special considerations
21*9c5db199SXin Liin each case. For instance, some of the commands in this lab will use the
22*9c5db199SXin Livariable `${DUT_HOSTNAME}`, and the value of this variable is dependent on the
23*9c5db199SXin Litesting setup that you use. Further considerations are included below in the
24*9c5db199SXin Liinstructions for each option.
25*9c5db199SXin Li
26*9c5db199SXin Li#### Using the wifi testing labs
27*9c5db199SXin Li
28*9c5db199SXin LiOur testing lab setups are operated through the skylab infrastructure. If you
29*9c5db199SXin Lidon't have the skylab tool installed on your machine, follow the instructions
30*9c5db199SXin Liin the [skylab tools guide].
31*9c5db199SXin Li
32*9c5db199SXin LiOnce you have the skylab tool, you'll need to run the login command and follow
33*9c5db199SXin Liits instructions to get started.
34*9c5db199SXin Li
35*9c5db199SXin Li```bash
36*9c5db199SXin Liskylab login
37*9c5db199SXin Li```
38*9c5db199SXin Li
39*9c5db199SXin LiFor this codelab, you will need to use a `wificell` test setup. Available DUTs
40*9c5db199SXin Lican be found on the [skylab portal]. To find a wificell test setup, visit the
41*9c5db199SXin Liportal and filter for *label-wificell = true* (the filter should already be
42*9c5db199SXin Liset when you click the link). You'll need to find a setup who's current task
43*9c5db199SXin Liis *idle* with dut_state *ready*, and then lock it while in use. To lock a DUT
44*9c5db199SXin Liin the skylab use this command to lease it for the specified number of
45*9c5db199SXin Liminutes (60 minutes should suffice for this codelab, but if your lease
46*9c5db199SXin Liexpires you can simply lease your DUT again):
47*9c5db199SXin Li
48*9c5db199SXin Li```bash
49*9c5db199SXin Liskylab lease-dut -minutes ${NUM_MINUTES} ${DUT_NAME}
50*9c5db199SXin Li```
51*9c5db199SXin Li
52*9c5db199SXin Li*** note
53*9c5db199SXin Li**Note:** There are several similar fields on the bot page that can potentially
54*9c5db199SXin Libe confused. Bots are listed by their *id* field in the skylab search portal,
55*9c5db199SXin Liwhich usually takes a form similar to `crossk-chromeos15-row2-rack4-host6`.
56*9c5db199SXin Li*dut_name* is referred to in this document by the variable `${DUT_NAME}`, and
57*9c5db199SXin Liis typically the *id* without `crossk`, e.g. `chromeos15-row2-rack4-host6`. The
58*9c5db199SXin Lihostname for a DUT (`${DUT_HOSTNAME}` in this doc) is not shown on the skylab
59*9c5db199SXin Libot page, but it is the *dut_name* with '.cros' appended e.g.
60*9c5db199SXin Li`chromeos15-row2-rack4-host6.cros`.
61*9c5db199SXin Li***
62*9c5db199SXin Li
63*9c5db199SXin LiAutotest requires a working build of the board type being tested on, so it is
64*9c5db199SXin Libest to pick a board for which you have already built an image on your machine.
65*9c5db199SXin Li
66*9c5db199SXin LiAutotest will automatically determine the hostnames of the router and packet
67*9c5db199SXin Licapture device but if you want to access them directly, say through ssh,
68*9c5db199SXin Liyou can use the hostnames **${DUT\_NAME}-router.cros** and
69*9c5db199SXin Li**${DUT\_NAME}-pcap.cros** respectively. You can access each with ssh
70*9c5db199SXin Lithrough the root user with password `test0000`.
71*9c5db199SXin Li
72*9c5db199SXin LiLastly, Autotest may have issues with hosts that have the `chameleon` label.
73*9c5db199SXin LiIf you are having [chameleon issues], the current workaround is to set
74*9c5db199SXin Li*enable_ssh_tunnel_for_chameleon: True* in
75*9c5db199SXin Li`src/third_party/autotest/files/global_config.ini`.
76*9c5db199SXin Li
77*9c5db199SXin Li#### Using a local testing setup
78*9c5db199SXin Li
79*9c5db199SXin LiFor a local test setup, you'll need a flashed DUT and two flashed Google-made
80*9c5db199SXin Liwifi routers that run ChromeOS, all running special test images. The
81*9c5db199SXin LiGoogle-made routers can be either of the boards `whirlwind` or `gale`,
82*9c5db199SXin Liand see [network_WiFi_UpdateRouter] for what images they should be running.
83*9c5db199SXin LiIn order for Autotest to determine the hostnames of your router and packet
84*9c5db199SXin Licapture device, you'll have to designate their IP addresses within your chroot.
85*9c5db199SXin LiAssign the IP address of your DUT to 'dut', and the IPs of your routers to
86*9c5db199SXin Li'dut-router' and 'dut-pcap' by adding lines like these to `/etc/hosts`:
87*9c5db199SXin Li
88*9c5db199SXin Li```bash
89*9c5db199SXin Lixxx.xxx.xxx.xxx dut-router
90*9c5db199SXin Lixxx.xxx.xxx.xxx dut-pcap
91*9c5db199SXin Lixxx.xxx.xxx.xxx dut
92*9c5db199SXin Li```
93*9c5db199SXin Li
94*9c5db199SXin LiNow, you can use **${DUT\_HOSTNAME}** = '*dut*' and Autotest will use your
95*9c5db199SXin Lihosts file to find the other devices. The final consideration when using a
96*9c5db199SXin Lilocal testing setup is that the designated testbeds are contained in shielding
97*9c5db199SXin Liboxes which isolate them from other signals, while your local setup is
98*9c5db199SXin Liprobably held in open air. This means that your packet capture device will also
99*9c5db199SXin Lipick up packets from any other devices broadcasting in your area. This will make
100*9c5db199SXin Lithe packet feed noisier, but you can still find all the packets involved in the
101*9c5db199SXin Liconnection process so its not a dealbreaker for this codelab.
102*9c5db199SXin Li
103*9c5db199SXin Li### Let's get started
104*9c5db199SXin Li
105*9c5db199SXin Li[network_WiFi_SimpleConnect] is a very simple test that connects and disconnects
106*9c5db199SXin Lia DUT from a router, so it's ideal for our purposes in this codelab. The test
107*9c5db199SXin Liitself is held at `server/site_tests/network_WiFi_SimpleConnect/` in the
108*9c5db199SXin LiAutotest repository. Briefly look through this file to get a sense for what it
109*9c5db199SXin Liis doing.
110*9c5db199SXin Li
111*9c5db199SXin LiBefore you make any changes to code, be sure to start a new branch within the
112*9c5db199SXin LiAutotest repository.
113*9c5db199SXin Li
114*9c5db199SXin Li#### 1. Gather pcap data
115*9c5db199SXin Li
116*9c5db199SXin LiOur first goal is to initiate packet capture and record all of the frames that
117*9c5db199SXin Liour pcap device sees throughout the test. Conveniently,
118*9c5db199SXin Li[network_WiFi_SimpleConnect] already utilizes a pcap device, which is accessed
119*9c5db199SXin Liat `self.context.capture_host`. Before the testing starts, the test begins
120*9c5db199SXin Licapturing packets by calling `start_capture()` on the capture device, and after
121*9c5db199SXin Lithe test completes, `stop_capture()` completes the capturing process.
122*9c5db199SXin Li`stop_capture()` returns a list of filepaths that hold the captured packets, so
123*9c5db199SXin Lilet's store the results of this function in a variable:
124*9c5db199SXin Li
125*9c5db199SXin Li```python3
126*9c5db199SXin Licapture_results = self.context.capture_host.stop_capture()
127*9c5db199SXin Li```
128*9c5db199SXin Li
129*9c5db199SXin LiThe pcap file is accessible at `capture_results[0].local_pcap_path`, so let's
130*9c5db199SXin Liprint out a dump of our captured packets. Add these lines after the call to
131*9c5db199SXin Li`stop_capture()`:
132*9c5db199SXin Li
133*9c5db199SXin Li```python3
134*9c5db199SXin Lipackets = open(capture_results[0].local_pcap_path, 'r')
135*9c5db199SXin Lilogging.info(packets.read())
136*9c5db199SXin Lipackets.close()
137*9c5db199SXin Li```
138*9c5db199SXin Li
139*9c5db199SXin LiNow, lets run the test and see what we can learn:
140*9c5db199SXin Li
141*9c5db199SXin Li```bash
142*9c5db199SXin Litest_that --fast -b ${BOARD} ${DUT_HOSTNAME} network_WiFi_SimpleConnect.wifi_check5HT20
143*9c5db199SXin Li```
144*9c5db199SXin Li
145*9c5db199SXin LiThat's a lot of garbage. The packets aren't going to be much use to us in their
146*9c5db199SXin Licurrent state. In the next section, we'll use Wireshark to translate the packets
147*9c5db199SXin Liinto a readable form that we can study.
148*9c5db199SXin Li
149*9c5db199SXin Li#### 2. Use Wireshark to analyze the packets
150*9c5db199SXin Li
151*9c5db199SXin LiPyshark is a wrapper for Wireshark within Python, and we'll be using it in this
152*9c5db199SXin Licodelab to interperet our captured packets. Learn more at the
153*9c5db199SXin Li[Pyshark documentation] page.
154*9c5db199SXin Li
155*9c5db199SXin LiDelete the lines you just added and replace them with calls to Pyshark that will
156*9c5db199SXin Liparse and translate the packets, then write the packets to a file:
157*9c5db199SXin Li
158*9c5db199SXin Li```python3
159*9c5db199SXin Li
160*9c5db199SXin Liimport pyshark
161*9c5db199SXin Licapture = pyshark.FileCapture(
162*9c5db199SXin Li    input_file=capture_results[0].local_pcap_path)
163*9c5db199SXin Licapture.load_packets(timeout=2)
164*9c5db199SXin Li
165*9c5db199SXin Lipacket_file = open('/tmp/pcap', 'w')
166*9c5db199SXin Lifor packet in capture:
167*9c5db199SXin Li    packet_file.write(str(packet))
168*9c5db199SXin Lipacket_file.close()
169*9c5db199SXin Li
170*9c5db199SXin Li```
171*9c5db199SXin Li
172*9c5db199SXin LiRun the Autotest again and open `/tmp/pcap`. Look at that, tons of
173*9c5db199SXin Lihuman-readable data! Maybe even a little too much? Right now we're getting the
174*9c5db199SXin Lientirety of every packet, but we only need a few fields. As a final step, we're
175*9c5db199SXin Ligoing to parse out the needed fields from each packet so we can digest some
176*9c5db199SXin Lirelevant information about the connection process. Add the following methods to
177*9c5db199SXin Lithe global scope of [network_WiFi_SimpleConnect]:
178*9c5db199SXin Li
179*9c5db199SXin Li```python3
180*9c5db199SXin Li
181*9c5db199SXin Lidef _fetch_frame_field_value(frame, field):
182*9c5db199SXin Li    layer_object = frame
183*9c5db199SXin Li    for layer in field.split('.'):
184*9c5db199SXin Li        try:
185*9c5db199SXin Li            layer_object = getattr(layer_object, layer)
186*9c5db199SXin Li        except AttributeError:
187*9c5db199SXin Li            return None
188*9c5db199SXin Li    return layer_object
189*9c5db199SXin Li
190*9c5db199SXin Li"""
191*9c5db199SXin LiParses input frames and stores frames of type listed in filter_types.
192*9c5db199SXin LiIf filter_types is empty, stores all parsed frames.
193*9c5db199SXin Li"""
194*9c5db199SXin Lidef parse_frames(capture_frames, filter_types):
195*9c5db199SXin Li    frames = []
196*9c5db199SXin Li    for frame in capture_frames:
197*9c5db199SXin Li        frame_type = _fetch_frame_field_value(
198*9c5db199SXin Li            frame, 'wlan.fc_type_subtype')
199*9c5db199SXin Li        if filter_types and frame_type not in filter_types:
200*9c5db199SXin Li            continue
201*9c5db199SXin Li        frametime = frame.sniff_time
202*9c5db199SXin Li        source_addr = _fetch_frame_field_value(
203*9c5db199SXin Li            frame, 'wlan.sa')
204*9c5db199SXin Li        dest_addr = _fetch_frame_field_value(
205*9c5db199SXin Li            frame, 'wlan.da')
206*9c5db199SXin Li        frames.append([frametime, source_addr, dest_addr, frame_type])
207*9c5db199SXin Li    return frames
208*9c5db199SXin Li
209*9c5db199SXin Li```
210*9c5db199SXin Li
211*9c5db199SXin LiUsing these functions, you can retrieve a timestamp, the source address, the
212*9c5db199SXin Lidestination address, and the frame subtype for every packet that your pcap
213*9c5db199SXin Lidevice captured over the course of the test. The keywords within
214*9c5db199SXin Li`parse_frames()` ('wlan.sa', 'wlan.da', 'wlan.fc_type_subtype'), are special
215*9c5db199SXin LiWireshark filters that correspond to the relevant data we are looking for.
216*9c5db199SXin LiThere are over 242000 such filters which you can find in the [wireshark docs].
217*9c5db199SXin Li
218*9c5db199SXin LiNow we just need to call `parse_frames()` and upgrade our packet logging logic.
219*9c5db199SXin LiReplace the file logging logic from above with the following code which parses
220*9c5db199SXin Lithe frames into a much more readable format:
221*9c5db199SXin Li
222*9c5db199SXin Li```python3
223*9c5db199SXin Li
224*9c5db199SXin LiframeTypesToFilter = {}
225*9c5db199SXin Liframes = parse_frames(capture, frameTypesToFilter)
226*9c5db199SXin Li
227*9c5db199SXin Lipacket_file = open('/tmp/pcap', 'w')
228*9c5db199SXin Lipacket_file.write('{:^28s}|{:^19s}|{:^19s}|{:^6s}\n'.format(
229*9c5db199SXin Li    'Timestamp', 'Source Address', 'Receiver Address', 'Type'))
230*9c5db199SXin Lipacket_file.write('---------------------------------------------------------------------------\n')
231*9c5db199SXin Lifor packet in frames:
232*9c5db199SXin Li    packet_file.write('{:^28s}|{:^19s}|{:^19s}|{:^6s}\n'.format(
233*9c5db199SXin Li        str(packet[0]), packet[1], packet[2], packet[3]))
234*9c5db199SXin Lipacket_file.close()
235*9c5db199SXin Li
236*9c5db199SXin Li```
237*9c5db199SXin Li
238*9c5db199SXin LiThis time when we run the test we can very concisely see every single packet
239*9c5db199SXin Lithat our pcap device captured, and we get only the data which is relevant to
240*9c5db199SXin Liour purposes. Later on we'll populate `frameTypesToFilter` to single out the
241*9c5db199SXin Liframes that are relevant to the connection/disconnection process, but first
242*9c5db199SXin Lilet's look deeper into the frames themselves.
243*9c5db199SXin Li
244*9c5db199SXin Li#### 3. Learn some 802.11 background
245*9c5db199SXin Li
246*9c5db199SXin LiBefore we start analyzing the packets, we need some background on 802.11 frames.
247*9c5db199SXin LiThe state machine below represents the 802.11 connection/disconnection protocol.
248*9c5db199SXin LiAs you can see, a connection's state is determined by the authentication and
249*9c5db199SXin Liassociation status between its devices. The types of packets that a device is
250*9c5db199SXin Liable to send and receive are dependent on the state of its connections.
251*9c5db199SXin Li
252*9c5db199SXin Li![State Machine](assets/wifi-state-machine.gif)
253*9c5db199SXin Li
254*9c5db199SXin Li##### Authentication and Association
255*9c5db199SXin Li
256*9c5db199SXin LiIn order to ensure security, users must be authenticated to a network before
257*9c5db199SXin Lithey are allowed to use the network. The authentication process itself is not
258*9c5db199SXin Listrictly defined by the 802.11 protocol, but it usually consists of a robust
259*9c5db199SXin Licryptographic exchange that allows the network to trust the user. Once a user
260*9c5db199SXin Lihas been authenticated to the network, it is *trusted*, but it is still not
261*9c5db199SXin Liactually a member of the network until it has been *associated*. Association
262*9c5db199SXin Lican be thought of as the proccess of actually joining the network, and also
263*9c5db199SXin Liacts as a sort of *registration* that allows the network to determine which
264*9c5db199SXin Liaccess point to use for a given user.
265*9c5db199SXin Li
266*9c5db199SXin Li##### Class 1 frames
267*9c5db199SXin Li
268*9c5db199SXin LiClass 1 frames can be sent in any state, and they are used to support the basic
269*9c5db199SXin Lioperations of 802.11 connections. Class 1 frames are called *Management Frames*
270*9c5db199SXin Liand they allow devices to find a network and negotiate their connection status.
271*9c5db199SXin Li
272*9c5db199SXin Li**Some class 1 frames:**
273*9c5db199SXin Li
274*9c5db199SXin Li* *Beacons* are frames that access points send out on a regular interval to
275*9c5db199SXin Libroadcast their existence to the world. Devices are only aware of access points
276*9c5db199SXin Libecause they can see the beacon frames they send.
277*9c5db199SXin Li* Devices respond to beacons with *Probe Requests* which in turn let the
278*9c5db199SXin Linetwork know of their existence. The probe request also includes a list of all
279*9c5db199SXin Lidata rates the device supports, which the network can use to check for
280*9c5db199SXin Licompatibility with those supported by the access point.
281*9c5db199SXin Li* Access points respond with *Probe Responses* which either confirm or deny
282*9c5db199SXin Licompatibility.
283*9c5db199SXin Li* If the two are compatible, they can engage in the authentication/association
284*9c5db199SXin Liprocess as explained above with various *Association* and *Authentication*
285*9c5db199SXin Liframes.
286*9c5db199SXin Li
287*9c5db199SXin Li##### Class 2 frames
288*9c5db199SXin Li
289*9c5db199SXin LiClass 2 frames can only be sent from a successfully authenticated device, which
290*9c5db199SXin Limeans they can be sent in states 2 and 3. Class 2 frames are called
291*9c5db199SXin Li*Control Frames*, and their purpose is to allow authenticated devices to
292*9c5db199SXin Linegotiate the sending of data between them. Request to send (RTS), clear to send
293*9c5db199SXin Li(CTS), and acknowledge (ACK) are all examples of class 2 frames.
294*9c5db199SXin Li
295*9c5db199SXin Li##### Class 3 frames
296*9c5db199SXin Li
297*9c5db199SXin LiClass 3 frames can only be sent from an authenticated and associated device,
298*9c5db199SXin Limeaning they can only be sent while in state 3. Class 3 frames are
299*9c5db199SXin Li*Data Frames* and they make up all of the actual bulk of wireless
300*9c5db199SXin Licommunication. All frames which are used to send non-meta data between devices
301*9c5db199SXin Liare data frames.
302*9c5db199SXin Li
303*9c5db199SXin Li#### 4. Let's analyze some packets
304*9c5db199SXin Li
305*9c5db199SXin LiNow that we have a basic understanding of 802.11 frame classes, we can use our
306*9c5db199SXin Licaptured packets to study the 802.11 connection/disconnection protocol in
307*9c5db199SXin Liaction. Near the bottom of this page is a set of [lookup tables] that outline
308*9c5db199SXin Lievery type of frame in the 802.11 protocol, which you can use to determine what
309*9c5db199SXin Likind of packets we picked up.
310*9c5db199SXin Li
311*9c5db199SXin Li[Solutions and hints] to the questions below can be found after the
312*9c5db199SXin Lilookup tables at the bottom of this page, but please do your best to answer
313*9c5db199SXin Lithem yourself before referring to the solutions.
314*9c5db199SXin Li
315*9c5db199SXin LiLets see if we can answer some basic questions about your configuration based
316*9c5db199SXin Lion the context of the captured packets:
317*9c5db199SXin Li
318*9c5db199SXin Li1. What is the MAC address of your router? (you may already know this, but
319*9c5db199SXin Li   try to infer from the context of the packets)
320*9c5db199SXin Li1. What is the MAC address of your DUT?
321*9c5db199SXin Li1. What is the beacon interval (time between beacons) of your router?
322*9c5db199SXin Li1. What could a receiver address of *ff:ff:ff:ff:ff:ff* indicate?
323*9c5db199SXin Li
324*9c5db199SXin LiNow, try to find the frames where the DUT and router negotiate their connection.
325*9c5db199SXin LiDepending on how noisy your setup is this could be somewhat difficult, but you
326*9c5db199SXin Lishould be able to see the authentication/association process in action by
327*9c5db199SXin Lilooking for some key frame types. (Hint: look for a class 3 frame being sent
328*9c5db199SXin Lifrom your DUT to your router, and work back to see the frames that got them
329*9c5db199SXin Lithere). Study the process and compare the flow to the frame class descriptions
330*9c5db199SXin Liabove.
331*9c5db199SXin Li
332*9c5db199SXin Li#### 5. Filter the frames and check your results
333*9c5db199SXin Li
334*9c5db199SXin LiWe can populate `framesToFilter` with frame type codes (i.e. '0x04') to show
335*9c5db199SXin Lionly the frames that are a part of the connection process. Based on what
336*9c5db199SXin Liyou know about the 802.11 state machine, begin filtering for frames
337*9c5db199SXin Lithat you know are relevant. Do not include beacon frames (type 0x08) because
338*9c5db199SXin Liwhile they are a part of the connection process, there are so many of them
339*9c5db199SXin Lithat they will clog up the output. After improving the filter, add the
340*9c5db199SXin Lifollowing code to the bottom of [network_WiFi_SimpleConnect] to produce another
341*9c5db199SXin Lioutput file which only shows the frametypes so the testing script can parse
342*9c5db199SXin Lithem.
343*9c5db199SXin Li
344*9c5db199SXin Li```python3
345*9c5db199SXin Li
346*9c5db199SXin Lioutput_file = open('/tmp/filtered_pcap', 'w')
347*9c5db199SXin Lifor packet in frames:
348*9c5db199SXin Li    output_file.write(str(packet[3]) + '\n')
349*9c5db199SXin Lioutput_file.close()
350*9c5db199SXin Li
351*9c5db199SXin Li```
352*9c5db199SXin Li
353*9c5db199SXin LiNow, test your ouput file by running the testing python script:
354*9c5db199SXin Li
355*9c5db199SXin Li```bash
356*9c5db199SXin Lipython wifi-basics-codelab-pcap-test.py
357*9c5db199SXin Li```
358*9c5db199SXin Li
359*9c5db199SXin LiThis script will check your output to see if you've isolated the correct
360*9c5db199SXin Liframes and that the entire connection sequence can be seen. If the script
361*9c5db199SXin Lifails, keep adjusting your filter until it succeeds. After you have passed the
362*9c5db199SXin Litest, review `/tmp/pcap` again to see the entire process in action. Finally,
363*9c5db199SXin Lirefer back to the questions in [section 4] one last time to see if you've
364*9c5db199SXin Ligained any new insight into the 802.11 protocol.
365*9c5db199SXin Li
366*9c5db199SXin Li## Lookup Tables
367*9c5db199SXin Li
368*9c5db199SXin Li### Management Frames (Class 1)
369*9c5db199SXin Li
370*9c5db199SXin Li| Subtype Value | Hex Encoding | Subtype Name           |
371*9c5db199SXin Li|---------------|--------------|------------------------|
372*9c5db199SXin Li| 0000          | 0x00         | Association Request    |
373*9c5db199SXin Li| 0001          | 0x01         | Association Response   |
374*9c5db199SXin Li| 0010          | 0x02         | Reassociation Request  |
375*9c5db199SXin Li| 0011          | 0x03         | Reassociation Response |
376*9c5db199SXin Li| 0100          | 0x04         | Probe Request          |
377*9c5db199SXin Li| 0101          | 0x05         | Probe Response         |
378*9c5db199SXin Li| 1000          | 0x08         | Beacon                 |
379*9c5db199SXin Li| 1001          | 0x09         | ATIM                   |
380*9c5db199SXin Li| 1010          | 0x0a         | Disassociation         |
381*9c5db199SXin Li| 1011          | 0x0b         | Authentication         |
382*9c5db199SXin Li| 1100          | 0x0c         | Deauthentication       |
383*9c5db199SXin Li| 1101          | 0x0d         | Action                 |
384*9c5db199SXin Li
385*9c5db199SXin Li### Control Frames (Class 2)
386*9c5db199SXin Li
387*9c5db199SXin Li| Subtype Value | Hex Encoding | Subtype Name                 |
388*9c5db199SXin Li|---------------|--------------|------------------------------|
389*9c5db199SXin Li| 1000          | 0x18         | Block Acknowedgement Request |
390*9c5db199SXin Li| 1001          | 0x19         | Block Acknowledgement        |
391*9c5db199SXin Li| 1010          | 0x1a         | Power Save (PS)-Poll         |
392*9c5db199SXin Li| 1011          | 0x1b         | RTS                          |
393*9c5db199SXin Li| 1100          | 0x1c         | CTS                          |
394*9c5db199SXin Li| 1101          | 0x1d         | Acknowledgement (ACK)        |
395*9c5db199SXin Li| 1110          | 0x1e         | Contention-Free (CF)-End     |
396*9c5db199SXin Li| 1111          | 0x1f         | CF-End+CF-ACK                |
397*9c5db199SXin Li
398*9c5db199SXin Li### Data Frames (Class 3)
399*9c5db199SXin Li
400*9c5db199SXin Li| Subtype Value | Hex Encoding | Subtype Name                               |
401*9c5db199SXin Li|---------------|--------------|--------------------------------------------|
402*9c5db199SXin Li| 0000          | 0x20         | Data                                       |
403*9c5db199SXin Li| 0001          | 0x21         | Data + CF-Ack                              |
404*9c5db199SXin Li| 0010          | 0x22         | Data + CF-Poll                             |
405*9c5db199SXin Li| 0011          | 0x23         | Data + CF-Ack+CF-Poll                      |
406*9c5db199SXin Li| 0100          | 0x24         | Null Data (no data transmitted)            |
407*9c5db199SXin Li| 0101          | 0x25         | CF-Ack (no data transmitted)               |
408*9c5db199SXin Li| 0110          | 0x26         | CF-Poll (no data transmitted)              |
409*9c5db199SXin Li| 0111          | 0x27         | CF-Ack + CF-Poll (no data transmitted)     |
410*9c5db199SXin Li| 1000          | 0x28         | QoS Data                                   |
411*9c5db199SXin Li| 1001          | 0x29         | Qos Data + CF-Ack                          |
412*9c5db199SXin Li| 1010          | 0x2a         | QoS Data + CF-Poll                         |
413*9c5db199SXin Li| 1011          | 0x2b         | QoS Data + CF-Ack + CF-Poll                |
414*9c5db199SXin Li| 1100          | 0x2c         | QoS Null (no data transmitted)             |
415*9c5db199SXin Li| 1101          | 0x2d         | Qos CF-Ack (no data transmitted)           |
416*9c5db199SXin Li| 1110          | 0x2e         | QoS CF-Poll (no data transmitted)          |
417*9c5db199SXin Li| 1111          | 0x2f         | QoS CF-Ack + CF-Poll (no data transmitted) |
418*9c5db199SXin Li
419*9c5db199SXin Li## Solutions and hints
420*9c5db199SXin Li
421*9c5db199SXin Li### Configuration questions
422*9c5db199SXin Li
423*9c5db199SXin Li1. Your router should be sending many beacon packets (type 0x08 frames), so
424*9c5db199SXin Li   look for the source address of the frames of type 0x08.
425*9c5db199SXin Li1. Your DUT can be recognized as the device which has a "conversation" with
426*9c5db199SXin Li   your router. I.e. you should be able to see one IP which is the
427*9c5db199SXin Li   sender/receiver of several different management frames (0x00, 0x01, etc.)
428*9c5db199SXin Li   with your router.
429*9c5db199SXin Li1. The beacon interval is the time a device waits between sending beacon
430*9c5db199SXin Li   frames. You can determine this interval for a device by finding the time
431*9c5db199SXin Li   that passes between two beacons being transmitted by the
432*9c5db199SXin Li   device. The beacon interval for your router is most likely 100ms.
433*9c5db199SXin Li1. A receiver address of *ff:ff:ff:ff:ff:ff* indicates that the frame is
434*9c5db199SXin Li   being broadcasted to any receiver that can hear it. This is pattern is
435*9c5db199SXin Li   used for beacon frames because these frames are intended as a sort of 'ping'
436*9c5db199SXin Li   to all nearby devices.
437*9c5db199SXin Li
438*9c5db199SXin Li### Packet filter solution
439*9c5db199SXin Li
440*9c5db199SXin LiThe testing script is looking for a particular packet sequence that
441*9c5db199SXin Lishows the DUT and router connecting to each other. The golden connection
442*9c5db199SXin Lisequence is as follows:
443*9c5db199SXin Li
444*9c5db199SXin Li1. Probe Request: 0x04
445*9c5db199SXin Li1. Probe Response: 0x05
446*9c5db199SXin Li1. Authentication: 0x0b
447*9c5db199SXin Li1. Assoc Request: 0x00
448*9c5db199SXin Li1. Assoc Response: 0x01
449*9c5db199SXin Li1. Deauthentication: 0x0c
450*9c5db199SXin Li
451*9c5db199SXin LiIn practice, we have noticed that many of the recorded connection sequences do
452*9c5db199SXin Linot include an Assoc Request packet, so the script is tolerant of that case.
453*9c5db199SXin Li
454*9c5db199SXin LiFinally, the script also verifies that no non-relevant frames were included,
455*9c5db199SXin Liso any non class 1 frames in the output file will cause failure. (Although,
456*9c5db199SXin Lionly the frames in the sequence above are strictly required.)
457*9c5db199SXin Li
458*9c5db199SXin Li[chameleon issues]: https://crbug.com/964549
459*9c5db199SXin Li[lookup tables]: #lookup-tables
460*9c5db199SXin Li[network_WiFi_UpdateRouter]: ../server/site_tests/network_WiFi_UpdateRouter/network_WiFi_UpdateRouter.py
461*9c5db199SXin Li[network_WiFi_SimpleConnect]: ../server/site_tests/network_WiFi_SimpleConnect/network_WiFi_SimpleConnect.py
462*9c5db199SXin Li[Pyshark documentation]: https://kiminewt.github.io/pyshark/
463*9c5db199SXin Li[section 4]: #4_let_s-analyze-some-packets
464*9c5db199SXin Li[skylab portal]: https://chromeos-swarming.appspot.com/botlist?c=id&c=task&c=dut_state&c=label-board&c=label-model&c=label-pool&c=os&c=provisionable-cros-version&c=status&d=asc&f=label-wificell%3ATrue&k=label-wificell&s=id
465*9c5db199SXin Li[skylab tools guide]: http://go/skylab-cli
466*9c5db199SXin Li[solutions and hints]: #solutions-and-hints
467*9c5db199SXin Li[test_that]: ./test-that.md
468*9c5db199SXin Li[wificell documentation]: ./wificell.md
469*9c5db199SXin Li[wireshark docs]: https://www.wireshark.org/docs/dfref/
470