wlan_common/test_utils/
fake_frames.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::mac::*;
6use ieee80211::{MacAddr, MacAddrBytes};
7
8pub const EAPOL_PDU: &[u8] = &[5, 5, 5, 5, 5, 5, 5, 5];
9
10pub fn make_mgmt_frame(ht_ctrl: bool) -> Vec<u8> {
11    #[rustfmt::skip]
12        let mut bytes = vec![
13        1, if ht_ctrl { 128 } else { 1 }, // fc
14        2, 2, // duration
15        3, 3, 3, 3, 3, 3, // addr1
16        4, 4, 4, 4, 4, 4, // addr2
17        5, 5, 5, 5, 5, 5, // addr3
18        6, 6, // sequence control
19    ];
20    if ht_ctrl {
21        bytes.extend_from_slice(&[8, 8, 8, 8]);
22    }
23    bytes.extend_from_slice(&[9, 9, 9]);
24    bytes
25}
26
27pub fn make_data_hdr(
28    addr4: Option<MacAddr>,
29    qos_ctrl: [u8; 2],
30    ht_ctrl: Option<[u8; 4]>,
31) -> Vec<u8> {
32    let mut fc = FrameControl(0);
33    fc.set_frame_type(FrameType::DATA);
34    fc.set_data_subtype(DataSubtype(0).with_qos(true));
35    fc.set_from_ds(addr4.is_some());
36    fc.set_to_ds(addr4.is_some());
37    fc.set_htc_order(ht_ctrl.is_some());
38    let fc = fc.0.to_le_bytes();
39
40    #[rustfmt::skip]
41        let mut bytes = vec![
42        // Data Header
43        fc[0], fc[1], // fc
44        2, 2, // duration
45        3, 3, 3, 3, 3, 3, // addr1
46        4, 4, 4, 4, 4, 4, // addr2
47        5, 5, 5, 5, 5, 5, // addr3
48        6, 6, // sequence control
49    ];
50
51    if let Some(addr4) = addr4 {
52        bytes.extend_from_slice(addr4.as_slice());
53    }
54
55    bytes.extend_from_slice(&qos_ctrl);
56
57    if let Some(ht_ctrl) = ht_ctrl {
58        bytes.extend_from_slice(&ht_ctrl);
59    }
60    bytes
61}
62
63pub fn make_data_frame_single_llc(addr4: Option<MacAddr>, ht_ctrl: Option<[u8; 4]>) -> Vec<u8> {
64    make_data_frame_single_llc_payload(addr4, ht_ctrl, &[11, 11, 11][..])
65}
66
67pub fn make_data_frame_single_llc_payload(
68    addr4: Option<MacAddr>,
69    ht_ctrl: Option<[u8; 4]>,
70    payload: &[u8],
71) -> Vec<u8> {
72    let qos_ctrl = [1, 1];
73    let mut bytes = make_data_hdr(addr4, qos_ctrl, ht_ctrl);
74    #[rustfmt::skip]
75        bytes.extend_from_slice(&[
76        // LLC Header
77        7, 7, 7, // DSAP, SSAP & control
78        8, 8, 8, // OUI
79        9, 10, // eth type
80    ]);
81    bytes.extend_from_slice(payload);
82    bytes
83}
84
85pub fn make_null_data_frame() -> Vec<u8> {
86    let fc = FrameControl(0)
87        .with_frame_type(FrameType::DATA)
88        .with_data_subtype(DataSubtype(0).with_null(true))
89        .with_to_ds(true);
90    let fc = fc.0.to_le_bytes();
91
92    #[rustfmt::skip]
93    let bytes = vec![
94        fc[0], fc[1], // FC
95        2, 2, // duration
96        3, 3, 3, 3, 3, 3, // addr1
97        4, 4, 4, 4, 4, 4, // addr2
98        5, 5, 5, 5, 5, 5, // addr3
99        6, 6, // sequence control
100    ];
101    bytes
102}
103
104pub fn make_data_frame_with_padding() -> Vec<u8> {
105    let mut bytes = make_data_hdr(None, [1, 1], None);
106    #[rustfmt::skip]
107        bytes.extend(vec![
108        // Padding
109        2, 2,
110        // LLC Header
111        7, 7, 7, // DSAP, SSAP & control
112        8, 8, 8, // OUI
113        9, 10, //eth type
114        11, 11, 11, 11, 11, // payload
115    ]);
116    bytes
117}
118
119#[rustfmt::skip]
120pub const MSDU_1_LLC_HDR : &[u8] = &[
121    0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00,
122];
123
124#[rustfmt::skip]
125pub const MSDU_1_PAYLOAD : &[u8] = &[
126    0x33, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
127    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
128    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
129    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
130    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
131    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
132    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
133    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
134    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
135    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
136    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
137    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
138    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
139    0x01, 0x02, 0x03, 0x04,
140];
141
142#[rustfmt::skip]
143pub const MSDU_2_LLC_HDR : &[u8] = &[
144    0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x01,
145];
146
147#[rustfmt::skip]
148pub const MSDU_2_PAYLOAD : &[u8] = &[
149    // Payload
150    0x99, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
151    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
152    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
153    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
154    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
155    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
156    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
157    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
158    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
159    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
160    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
161    0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
162];
163
164pub fn make_data_frame_amsdu() -> Vec<u8> {
165    let mut qos_ctrl = QosControl(0);
166    qos_ctrl.set_amsdu_present(true);
167    let mut amsdu_data_frame = make_data_hdr(None, qos_ctrl.0.to_le_bytes(), None);
168    #[rustfmt::skip]
169    amsdu_data_frame.extend(&[
170        // A-MSDU Subframe #1
171        0x78, 0x8a, 0x20, 0x0d, 0x67, 0x03, // dst_addr
172        0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xab, // src_addr
173        0x00, 0x74, // MSDU length
174    ]);
175    amsdu_data_frame.extend(MSDU_1_LLC_HDR);
176    amsdu_data_frame.extend(MSDU_1_PAYLOAD);
177
178    #[rustfmt::skip]
179    amsdu_data_frame.extend(&[
180        // Padding
181        0x00, 0x00,
182        // A-MSDU Subframe #2
183        0x78, 0x8a, 0x20, 0x0d, 0x67, 0x04, // dst_addr
184        0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xac, // src_addr
185        0x00, 0x66, // MSDU length
186    ]);
187    amsdu_data_frame.extend(MSDU_2_LLC_HDR);
188    amsdu_data_frame.extend(MSDU_2_PAYLOAD);
189    amsdu_data_frame
190}
191
192pub fn make_eapol_frame(addr1: MacAddr) -> (MacAddr, MacAddr, Vec<u8>) {
193    #[rustfmt::skip]
194    let mut frame = vec![
195        // Data header:
196        0b0000_10_00, 0b000000_1_0, // FC
197        0, 0, // Duration
198        6, 6, 6, 6, 6, 6, // addr1
199        7, 7, 7, 7, 7, 7, // addr2
200        7, 7, 7, 7, 7, 7, // addr3
201        0x10, 0, // Sequence Control
202        // LLC header:
203        0xaa, 0xaa, 0x03, // dsap ssap ctrl
204        0x00, 0x00, 0x00, // oui
205        0x88, 0x8E, // protocol id (EAPOL)
206    ];
207    // overwrite addr1
208    frame[4..10].copy_from_slice(addr1.as_array());
209    // EAPOL frame:
210    frame.extend(EAPOL_PDU);
211
212    // (src, dst, data frame)
213    (MacAddr::from([7; 6]), addr1, frame)
214}
215
216pub fn make_data_frame_amsdu_padding_too_short() -> Vec<u8> {
217    let mut qos_ctrl = QosControl(0);
218    qos_ctrl.set_amsdu_present(true);
219    let mut amsdu_data_frame = make_data_hdr(None, qos_ctrl.0.to_le_bytes(), None);
220    #[rustfmt::skip]
221        amsdu_data_frame.extend(&[
222        // A-MSDU Subframe #1
223        0x78, 0x8a, 0x20, 0x0d, 0x67, 0x03, // dst_addr
224        0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xab, // src_addr
225        0x00, 0x74, // MSDU length
226    ]);
227    amsdu_data_frame.extend(MSDU_1_LLC_HDR);
228    amsdu_data_frame.extend(MSDU_1_PAYLOAD);
229
230    #[rustfmt::skip]
231    amsdu_data_frame.extend(&[
232        // Padding is shorter than needed (1 vs 2)
233        0x00,
234        // A-MSDU Subframe #2
235        0x78, 0x8a, 0x20, 0x0d, 0x67, 0x04, // dst_addr
236        0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xac, // src_addr
237        0x00, 0x66, // MSDU length
238    ]);
239    amsdu_data_frame.extend(MSDU_2_LLC_HDR);
240    amsdu_data_frame.extend(MSDU_2_PAYLOAD);
241    amsdu_data_frame
242}
243
244pub fn fake_wpa1_ie_body(enhanced: bool) -> Vec<u8> {
245    let cipher = if enhanced { 0x4 } else { 0x2 }; // unicast cipher is CCMP-128 or TKIP
246    vec![
247        0x01, 0x00, // WPA version
248        0x00, 0x50, 0xf2, 0x02, // multicast cipher: TKIP
249        0x01, 0x00, 0x00, 0x50, 0xf2, cipher, // 1 unicast cipher
250        0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
251    ]
252}
253
254pub fn fake_wpa1_ie(enhanced: bool) -> Vec<u8> {
255    let mut ie = vec![
256        0xdd, 0x16, 0x00, 0x50, 0xf2, // IE header
257        0x01, // MSFT specific IE type (WPA)
258    ];
259    ie.append(&mut fake_wpa1_ie_body(enhanced));
260    ie
261}
262
263fn attach_rsne_header(rsne_body: &[u8]) -> Vec<u8> {
264    let mut ies = vec![48, rsne_body.len() as u8]; // Element Header
265    ies.extend_from_slice(&rsne_body[..]);
266    ies
267}
268
269pub fn fake_wpa2_rsne() -> Vec<u8> {
270    attach_rsne_header(&[
271        1, 0, // Version
272        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
273        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
274        1, 0, 0x00, 0x0F, 0xAC, 2, // 1 AKM: PSK
275    ])
276}
277
278pub fn fake_wpa2_mfpc_rsne() -> Vec<u8> {
279    attach_rsne_header(&[
280        1, 0, // Version
281        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
282        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
283        1, 0, 0x00, 0x0F, 0xAC, 2, // 1 AKM: PSK
284        0x8C, 0x00, // RSN capabilities: MFP capable, 16 PTKSA replay counters
285    ])
286}
287
288pub fn fake_wpa2_mfpr_rsne() -> Vec<u8> {
289    attach_rsne_header(&[
290        1, 0, // Version
291        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
292        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
293        1, 0, 0x00, 0x0F, 0xAC, 2, // 1 AKM: PSK
294        0xCC, 0x00, // RSN capabilities: MFP capable + required, 16 PTKSA replay counters
295    ])
296}
297
298pub fn fake_wpa2_tkip_only_rsne() -> Vec<u8> {
299    attach_rsne_header(&[
300        1, 0, // Version
301        0x00, 0x0F, 0xAC, 2, // Group Cipher: TKIP
302        1, 0, 0x00, 0x0F, 0xAC, 2, // 1 Pairwise Cipher: TKIP
303        1, 0, 0x00, 0x0F, 0xAC, 2, // 1 AKM: PSK
304    ])
305}
306
307pub fn fake_wpa2_tkip_ccmp_rsne() -> Vec<u8> {
308    attach_rsne_header(&[
309        1, 0, // Version
310        0x00, 0x0F, 0xAC, 2, // Group Cipher: TKIP
311        2, 0, 0x00, 0x0F, 0xAC, 2, 0x00, 0x0F, 0xAC, 4, // 2 Pairwise Ciphers: TKIP, CCMP-128
312        1, 0, 0x00, 0x0F, 0xAC, 2, // 1 AKM: PSK
313    ])
314}
315
316pub fn fake_wpa2_wpa3_rsne() -> Vec<u8> {
317    attach_rsne_header(&[
318        1, 0, // Version
319        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
320        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
321        2, 0, 0x00, 0x0F, 0xAC, 8, 0x00, 0x0F, 0xAC, 2, // 2 AKM: SAE, PSK
322        0x8C, 0x00, // RSN capabilities: MFP capable, 16 PTKSA replay counters
323    ])
324}
325
326// Wpa2/Wpa3 with management frame protection (MFP) required flag set to true
327pub fn fake_wpa2_wpa3_mfpr_rsne() -> Vec<u8> {
328    attach_rsne_header(&[
329        1, 0, // Version
330        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
331        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
332        2, 0, 0x00, 0x0F, 0xAC, 8, 0x00, 0x0F, 0xAC, 2, // 2 AKM: SAE, PSK
333        0xCC, 0x00, // RSN capabilities: MFP capable + required, 16 PTKSA replay counters
334    ])
335}
336
337// Wpa2/Wpa3 without any management frame protection flags set.
338pub fn fake_wpa2_wpa3_no_mfp_rsne() -> Vec<u8> {
339    attach_rsne_header(&[
340        1, 0, // Version
341        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
342        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
343        2, 0, 0x00, 0x0F, 0xAC, 8, 0x00, 0x0F, 0xAC, 2, // 2 AKM: SAE, PSK
344    ])
345}
346
347pub fn fake_wpa3_rsne() -> Vec<u8> {
348    attach_rsne_header(&[
349        1, 0, // Version
350        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
351        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
352        1, 0, 0x00, 0x0F, 0xAC, 8, // 1 AKM: SAE
353        0xCC, 0x00, // RSN capabilities: MFP capable + required, 16 PTKSA replay counters
354    ])
355}
356
357pub fn fake_wpa3_transition_rsne() -> Vec<u8> {
358    attach_rsne_header(&[
359        1, 0, // Version
360        0x00, 0x0F, 0xAC, 2, // Group Cipher: TKIP
361        1, 0, 0x00, 0x0F, 0xAC, 4, // Pairwise Cipher: CCMP-128
362        1, 0, 0x00, 0x0F, 0xAC, 8, // 1 AKM: SAE
363        0xCC, 0x00, // RSN capabilities: MFP capable + required, 16 PTKSA replay counters
364    ])
365}
366
367pub fn fake_owe_rsne() -> Vec<u8> {
368    attach_rsne_header(&[
369        1, 0, // Version
370        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
371        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
372        1, 0, 0x00, 0x0F, 0xAC, 18, // 1 AKM: OWE
373        0xCC, 0x00, // RSN capabilities: MFP capable + required, 16 PTKSA replay counters
374    ])
375}
376
377// Valid except for management frame protection (MFP) required flag not being set
378pub fn invalid_wpa3_rsne() -> Vec<u8> {
379    attach_rsne_header(&[
380        1, 0, // Version
381        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
382        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
383        1, 0, 0x00, 0x0F, 0xAC, 8, // 1 AKM: SAE
384        0x8C, 0x00, // RSN capabilities: MFP capable, 16 PTKSA replay counters
385    ])
386}
387
388pub fn fake_wpa2_enterprise_rsne() -> Vec<u8> {
389    attach_rsne_header(&[
390        1, 0, // Version
391        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
392        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
393        1, 0, 0x00, 0x0F, 0xAC, 1, // 1 AKM: EAP (802.1X)
394    ])
395}
396
397pub fn fake_wpa3_enterprise_192_bit_rsne() -> Vec<u8> {
398    attach_rsne_header(&[
399        1, 0, // Version
400        0x00, 0x0F, 0xAC, 9, // Group Cipher: GCMP-256
401        1, 0, 0x00, 0x0F, 0xAC, 9, // 1 Pairwise Cipher: GCMP-256
402        1, 0, 0x00, 0x0F, 0xAC, 12, // 1 AKM: EAP-SUITEB-SHA384 (HMAC-SHA-384)
403        0xCC, 0x00, // RSN capabilities: MFP capable + required, 16 PTKSA replay counters
404        0x00, 0x00, // 0 PMKID
405        0x00, 0x0F, 0xAC,
406        12, // Group Management Cipher: BIP-Ghttps://fxbug.dev/42076911 (BIP-GCMP-256)
407    ])
408}
409
410// Invalid due to group management not being specified (thus defaulting to BIP-CMAC-128, which
411// is not part of WPA3 Enterprise 192-bit)
412pub fn invalid_wpa3_enterprise_192_bit_rsne() -> Vec<u8> {
413    attach_rsne_header(&[
414        1, 0, // Version
415        0x00, 0x0F, 0xAC, 9, // Group Cipher: GCMP-256
416        1, 0, 0x00, 0x0F, 0xAC, 9, // 1 Pairwise Cipher: GCMP-256
417        1, 0, 0x00, 0x0F, 0xAC, 12, // 1 AKM: EAP-SUITEB-SHA384 (HMAC-SHA-384)
418        0xCC, 0x00, // RSN capabilities: MFP capable + required, 16 PTKSA replay counters
419    ])
420}
421
422pub fn fake_eap_rsne() -> Vec<u8> {
423    attach_rsne_header(&[
424        1, 0, // Version
425        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
426        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
427        1, 0, 0x00, 0x0F, 0xAC, 1, // 1 AKM:  802.1X
428    ])
429}
430
431// RSNE with AKM that we can't classify into a protection type
432pub fn fake_unknown_rsne() -> Vec<u8> {
433    attach_rsne_header(&[
434        1, 0, // Version
435        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
436        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
437        1, 0, 0x00, 0x0F, 0xAC, 7, // 1 AKM: TDLS
438    ])
439}
440
441pub fn fake_wmm_param_header() -> Vec<u8> {
442    vec![
443        0xdd, 0x18, // Vendor IE header
444        0x00, 0x50, 0xf2, // MSFT OUI
445        0x02, 0x01, // WMM Type and WMM Parameter Subtype
446        0x01, // Version 1
447    ]
448}
449
450pub fn fake_wmm_param_body() -> Vec<u8> {
451    vec![
452        0x80, // U-APSD enabled
453        0x00, // reserved
454        0x03, 0xa4, 0x00, 0x00, // AC_BE parameters
455        0x27, 0xa4, 0x00, 0x00, // AC_BK parameters
456        0x42, 0x43, 0x5e, 0x00, // AC_VI parameters
457        0x62, 0x32, 0x2f, 0x00, // AC_VO parameters
458    ]
459}