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
367// Valid except for management frame protection (MFP) required flag not being set
368pub fn invalid_wpa3_rsne() -> Vec<u8> {
369    attach_rsne_header(&[
370        1, 0, // Version
371        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
372        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
373        1, 0, 0x00, 0x0F, 0xAC, 8, // 1 AKM: SAE
374        0x8C, 0x00, // RSN capabilities: MFP capable, 16 PTKSA replay counters
375    ])
376}
377
378pub fn fake_wpa2_enterprise_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, 1, // 1 AKM: EAP (802.1X)
384    ])
385}
386
387pub fn fake_wpa3_enterprise_192_bit_rsne() -> Vec<u8> {
388    attach_rsne_header(&[
389        1, 0, // Version
390        0x00, 0x0F, 0xAC, 9, // Group Cipher: GCMP-256
391        1, 0, 0x00, 0x0F, 0xAC, 9, // 1 Pairwise Cipher: GCMP-256
392        1, 0, 0x00, 0x0F, 0xAC, 12, // 1 AKM: EAP-SUITEB-SHA384 (HMAC-SHA-384)
393        0xCC, 0x00, // RSN capabilities: MFP capable + required, 16 PTKSA replay counters
394        0x00, 0x00, // 0 PMKID
395        0x00, 0x0F, 0xAC,
396        12, // Group Management Cipher: BIP-Ghttps://fxbug.dev/42076911 (BIP-GCMP-256)
397    ])
398}
399
400// Invalid due to group management not being specified (thus defaulting to BIP-CMAC-128, which
401// is not part of WPA3 Enterprise 192-bit)
402pub fn invalid_wpa3_enterprise_192_bit_rsne() -> Vec<u8> {
403    attach_rsne_header(&[
404        1, 0, // Version
405        0x00, 0x0F, 0xAC, 9, // Group Cipher: GCMP-256
406        1, 0, 0x00, 0x0F, 0xAC, 9, // 1 Pairwise Cipher: GCMP-256
407        1, 0, 0x00, 0x0F, 0xAC, 12, // 1 AKM: EAP-SUITEB-SHA384 (HMAC-SHA-384)
408        0xCC, 0x00, // RSN capabilities: MFP capable + required, 16 PTKSA replay counters
409    ])
410}
411
412pub fn fake_eap_rsne() -> Vec<u8> {
413    attach_rsne_header(&[
414        1, 0, // Version
415        0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
416        1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
417        1, 0, 0x00, 0x0F, 0xAC, 1, // 1 AKM:  802.1X
418    ])
419}
420
421// RSNE with AKM that we can't classify into a protection type
422pub fn fake_unknown_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, 7, // 1 AKM: TDLS
428    ])
429}
430
431pub fn fake_wmm_param_header() -> Vec<u8> {
432    vec![
433        0xdd, 0x18, // Vendor IE header
434        0x00, 0x50, 0xf2, // MSFT OUI
435        0x02, 0x01, // WMM Type and WMM Parameter Subtype
436        0x01, // Version 1
437    ]
438}
439
440pub fn fake_wmm_param_body() -> Vec<u8> {
441    vec![
442        0x80, // U-APSD enabled
443        0x00, // reserved
444        0x03, 0xa4, 0x00, 0x00, // AC_BE parameters
445        0x27, 0xa4, 0x00, 0x00, // AC_BK parameters
446        0x42, 0x43, 0x5e, 0x00, // AC_VI parameters
447        0x62, 0x32, 0x2f, 0x00, // AC_VO parameters
448    ]
449}