wlan_frame_writer/
lib.rs

1// Copyright 2021 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
5pub use wlan_frame_writer_macro::{
6    append_frame_to, write_frame, write_frame_to_vec, write_frame_with_fixed_slice,
7};
8
9pub use fdf::Arena as __Arena;
10pub use {wlan_common as __wlan_common, zerocopy as __zerocopy};
11
12#[cfg(test)]
13extern crate self as wlan_frame_writer;
14
15#[cfg(test)]
16mod tests {
17    use super::*;
18    use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
19    use ieee80211::MacAddr;
20    use wlan_common::append::VecCursor;
21    use wlan_common::error::FrameWriteError;
22    use wlan_common::ie::rsn::akm::{Akm, PSK};
23    use wlan_common::ie::rsn::cipher::{Cipher, CCMP_128, TKIP};
24    use wlan_common::ie::rsn::rsne;
25    use wlan_common::ie::{self, wpa};
26    use wlan_common::mac::*;
27    use wlan_common::organization::Oui;
28
29    fn make_mgmt_hdr() -> MgmtHdr {
30        MgmtHdr {
31            frame_ctrl: FrameControl(0x4321),
32            duration: 42,
33            addr1: MacAddr::from([7; 6]),
34            addr2: MacAddr::from([6; 6]),
35            addr3: MacAddr::from([5; 6]),
36            seq_ctrl: SequenceControl(0x8765),
37        }
38    }
39
40    #[test]
41    fn write_emit_offset_default_source() {
42        let mut offset = 0;
43        write_frame!({
44            ies: {
45                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8],
46                offset @ extended_supported_rates: &[1u8, 2, 3, 4]
47            }
48        })
49        .expect("frame construction failed");
50        assert_eq!(offset, 10);
51    }
52
53    #[test]
54    fn write_emit_offset_fixed_buffer() {
55        let mut buffer = [0u8; 30];
56        let mut offset = 0;
57        let (frame_start, frame_end) = write_frame_with_fixed_slice!(&mut buffer[..], {
58            ies: {
59                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8],
60                offset @ extended_supported_rates: &[1u8, 2, 3, 4]
61            }
62        })
63        .expect("frame construction failed");
64        assert_eq!(frame_start, 0);
65        assert_eq!(frame_end, 16);
66        assert_eq!(offset, 10);
67    }
68
69    #[test]
70    fn write_emit_offset_fixed_buffer_fill_zeroes() {
71        let mut buffer = [0u8; 30];
72        let mut offset = 0;
73        let (frame_start, frame_end) = write_frame_with_fixed_slice!(&mut buffer[..], {
74            fill_zeroes: (),
75            ies: {
76                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8],
77                offset @ extended_supported_rates: &[1u8, 2, 3, 4]
78            }
79        })
80        .expect("frame construction failed");
81        assert_eq!(frame_start, 14);
82        assert_eq!(frame_end, 30);
83        assert_eq!(offset, 24);
84    }
85
86    #[test]
87    fn write_emit_offset_tracked_append() {
88        let mut offset = 0;
89        append_frame_to!(VecCursor::new(), {
90            ies: {
91                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8],
92                offset @ extended_supported_rates: &[1u8, 2, 3, 4]
93            }
94        })
95        .expect("frame construction failed");
96        assert_eq!(offset, 10);
97    }
98
99    #[test]
100    fn write_emit_offset_vec() {
101        let mut offset = 0;
102        write_frame_to_vec!({
103            ies: {
104                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8],
105                offset @ extended_supported_rates: &[1u8, 2, 3, 4]
106            }
107        })
108        .expect("frame construction failed");
109        assert_eq!(offset, 10);
110    }
111
112    #[test]
113    fn write_buf_empty_vec() {
114        let buffer = write_frame_to_vec!({
115            ies: { ssid: &b"foobar"[..] }
116        })
117        .expect("frame construction failed");
118        assert_eq!(buffer.len(), 8);
119        assert_eq!(&[0, 6, 102, 111, 111, 98, 97, 114,][..], &buffer[..]);
120    }
121
122    #[test]
123    fn write_fixed_buffer() {
124        let mut buffer = [0u8; 10];
125        let (frame_start, frame_end) = write_frame_with_fixed_slice!(&mut buffer[..], {
126            ies: { ssid: &b"foobar"[..] }
127        })
128        .expect("frame construction failed");
129        assert_eq!(frame_start, 0);
130        assert_eq!(frame_end, 8);
131        assert_eq!(&[0, 6, 102, 111, 111, 98, 97, 114,][..], &buffer[frame_start..frame_end]);
132    }
133
134    #[test]
135    fn write_fixed_buffer_with_fill_zeroes() {
136        let mut buffer = [0u8; 10];
137        let (frame_start, frame_end) = write_frame_with_fixed_slice!(&mut buffer[..], {
138            fill_zeroes: (),
139            ies: { ssid: &b"foobar"[..] },
140        })
141        .expect("frame construction failed");
142        assert_eq!(frame_start, 2);
143        assert_eq!(frame_end, 10);
144        assert_eq!(&[0, 6, 102, 111, 111, 98, 97, 114,][..], &buffer[frame_start..frame_end]);
145        // Also check the macro filled the beginning with zeroes.
146        assert_eq!(&[0, 0, 0, 6, 102, 111, 111, 98, 97, 114,][..], &buffer[..frame_end]);
147    }
148
149    #[test]
150    fn write_ssid() {
151        let buffer = write_frame!({
152            ies: { ssid: &b"foobar"[..] }
153        })
154        .expect("frame construction failed");
155        assert_eq!(buffer.len(), 8);
156        assert_eq!(&[0, 6, 102, 111, 111, 98, 97, 114,][..], &buffer[..]);
157    }
158
159    #[test]
160    fn write_ssid_empty() {
161        let buffer = write_frame!({
162            ies: { ssid: [0u8; 0] }
163        })
164        .expect("frame construction failed");
165        assert_eq!(buffer.len(), 2);
166        assert_eq!(&[0, 0][..], &buffer[..]);
167    }
168
169    #[test]
170    fn write_ssid_max() {
171        let buffer = write_frame!({
172            ies: { ssid: [2u8; (fidl_ieee80211::MAX_SSID_BYTE_LEN as usize)] }
173        })
174        .expect("frame construction failed");
175        assert_eq!(buffer.len(), 34);
176        #[rustfmt::skip]
177        assert_eq!(
178            &[
179                0, 32,
180                2, 2, 2, 2, 2, 2, 2, 2,
181                2, 2, 2, 2, 2, 2, 2, 2,
182                2, 2, 2, 2, 2, 2, 2, 2,
183                2, 2, 2, 2, 2, 2, 2, 2,
184            ][..],
185            &buffer[..]
186        );
187    }
188
189    #[test]
190    fn write_ssid_too_large() {
191        assert!(matches!(
192            write_frame!({
193                ies: { ssid: [2u8; 33] }
194            }),
195            Err(FrameWriteError::InvalidData(_))
196        ));
197    }
198
199    #[test]
200    fn write_tim() {
201        let buffer = write_frame_to_vec!({
202            ies: {
203                tim: ie::TimView {
204                    header: ie::TimHeader {
205                        dtim_count: 1,
206                        dtim_period: 2,
207                        bmp_ctrl: ie::BitmapControl(3)
208                    },
209                    bitmap: &[4, 5, 6][..],
210                }
211            }
212        })
213        .expect("failed to write frame");
214        assert_eq!(buffer.len(), 8);
215        assert_eq!(&[5, 6, 1, 2, 3, 4, 5, 6][..], &buffer[..]);
216    }
217
218    #[test]
219    fn write_tim_empty_bitmap() {
220        assert!(matches!(
221            write_frame_to_vec!({
222                ies: {
223                    tim: ie::TimView {
224                        header: ie::TimHeader {
225                            dtim_count: 1,
226                            dtim_period: 2,
227                            bmp_ctrl: ie::BitmapControl(3)
228                        },
229                        bitmap: &[][..],
230                    }
231                }
232            }),
233            Err(FrameWriteError::InvalidData(_))
234        ));
235    }
236
237    #[test]
238    fn write_tim_bitmap_too_long() {
239        assert!(matches!(
240            write_frame_to_vec!({
241                ies: {
242                    tim: ie::TimView {
243                        header: ie::TimHeader {
244                            dtim_count: 1,
245                            dtim_period: 2,
246                            bmp_ctrl: ie::BitmapControl(3)
247                        },
248                        bitmap: &[0xFF_u8; 252][..],
249                    }
250                }
251            }),
252            Err(FrameWriteError::InvalidData(_))
253        ));
254    }
255
256    #[test]
257    fn write_rates() {
258        let buffer = write_frame!({
259            ies: { supported_rates: &[1u8, 2, 3, 4, 5] }
260        })
261        .expect("frame construction failed");
262        assert_eq!(buffer.len(), 7);
263        assert_eq!(&[1, 5, 1, 2, 3, 4, 5,][..], &buffer[..]);
264    }
265
266    #[test]
267    fn write_rates_too_large() {
268        let buffer = write_frame!({
269            ies: { supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9] }
270        })
271        .expect("frame construction failed");
272        assert_eq!(buffer.len(), 10);
273        assert_eq!(&[1, 8, 1, 2, 3, 4, 5, 6, 7, 8][..], &buffer[..]);
274    }
275
276    #[test]
277    fn write_rates_empty() {
278        assert!(matches!(
279            write_frame!({
280                ies: { supported_rates: &[] }
281            }),
282            Err(FrameWriteError::InvalidData(_))
283        ));
284    }
285
286    #[test]
287    fn write_extended_supported_rates_too_few_rates() {
288        assert!(matches!(
289            write_frame!({
290                ies: {
291                    supported_rates: &[1u8, 2, 3, 4, 5, 6],
292                    extended_supported_rates: &[1u8, 2, 3, 4]
293                }
294            }),
295            Err(FrameWriteError::InvalidData(_))
296        ));
297    }
298
299    #[test]
300    fn write_extended_supported_rates_too_many_rates() {
301        assert!(matches!(
302            write_frame!({
303                ies: {
304                    supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9],
305                    extended_supported_rates: &[1u8, 2, 3, 4]
306                }
307            }),
308            Err(FrameWriteError::InvalidData(_))
309        ));
310    }
311
312    #[test]
313    fn write_extended_supported_rates_continued() {
314        let buffer = write_frame!({
315            ies: {
316                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9],
317                extended_supported_rates: {/* continue rates */}
318            }
319        })
320        .expect("frame construction failed");
321        assert_eq!(buffer.len(), 13);
322        assert_eq!(&[1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 1, 9][..], &buffer[..]);
323    }
324
325    #[test]
326    fn write_extended_supported_rates_separate() {
327        let buffer = write_frame!({
328            ies: {
329                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8],
330                extended_supported_rates: &[11u8, 12, 13],
331            }
332        })
333        .expect("frame construction failed");
334        assert_eq!(buffer.len(), 15);
335        assert_eq!(&[1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 3, 11, 12, 13][..], &buffer[..]);
336    }
337
338    #[test]
339    fn write_rsne() {
340        let rsne = rsne::Rsne::wpa2_rsne();
341
342        let buffer = write_frame!({
343            ies: { rsne: &rsne, }
344        })
345        .expect("frame construction failed");
346        assert_eq!(buffer.len(), 20);
347        assert_eq!(
348            &[
349                48, 18, // Element header
350                1, 0, // Version
351                0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
352                1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
353                1, 0, 0x00, 0x0F, 0xAC, 2, // 1 AKM: PSK
354            ][..],
355            &buffer[..]
356        );
357    }
358
359    #[test]
360    fn write_wpa1() {
361        let wpa_ie = wpa::WpaIe {
362            multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: TKIP },
363            unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: TKIP }],
364            akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
365        };
366
367        let buffer = write_frame!({
368            ies: { wpa1: &wpa_ie, }
369        })
370        .expect("frame construction failed");
371        assert_eq!(buffer.len(), 24);
372        assert_eq!(
373            &[
374                0xdd, 0x16, // Vendor IE header
375                0x00, 0x50, 0xf2, // MSFT OUI
376                0x01, 0x01, 0x00, // WPA IE header
377                0x00, 0x50, 0xf2, 0x02, // multicast cipher: TKIP
378                0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher: TKIP
379                0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
380            ][..],
381            &buffer[..]
382        );
383    }
384
385    #[test]
386    fn write_match_optional_positive() {
387        let wpa_ie = wpa::WpaIe {
388            multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: TKIP },
389            unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: TKIP }],
390            akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
391        };
392
393        let buffer = write_frame!({
394            ies: {
395                wpa1?: match 2u8 {
396                    1 => None,
397                    2 => Some(&wpa_ie),
398                    _ => None,
399                },
400            }
401        })
402        .expect("frame construction failed");
403        assert_eq!(buffer.len(), 24);
404        assert_eq!(
405            &[
406                0xdd, 0x16, // Vendor IE header
407                0x00, 0x50, 0xf2, // MSFT OUI
408                0x01, 0x01, 0x00, // WPA IE header
409                0x00, 0x50, 0xf2, 0x02, // multicast cipher: TKIP
410                0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher: TKIP
411                0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
412            ][..],
413            &buffer[..]
414        );
415    }
416
417    #[test]
418    fn write_match_optional_negative() {
419        let wpa_ie = wpa::WpaIe {
420            multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: TKIP },
421            unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: TKIP }],
422            akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
423        };
424
425        let buffer = write_frame!({
426            ies: {
427                // Add another field that is present since write_frame!() will
428                // return an error if no bytes are buffer.len().
429                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8],
430                wpa1?: match 1u8 {
431                    1 => None,
432                    2 => Some(&wpa_ie),
433                    _ => None,
434                },
435            }
436        })
437        .expect("frame construction failed");
438
439        // Only supported rates are written.
440        assert_eq!(buffer.len(), 10);
441        assert_eq!(&[1, 8, 1, 2, 3, 4, 5, 6, 7, 8][..], &buffer[..]);
442    }
443
444    #[test]
445    fn write_match_required() {
446        let wpa_ie_first = wpa::WpaIe {
447            multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: TKIP },
448            unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: TKIP }],
449            akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
450        };
451        let wpa_ie_second = wpa::WpaIe {
452            multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: CCMP_128 },
453            unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: CCMP_128 }],
454            akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
455        };
456
457        let buffer = write_frame!({
458            ies: {
459                wpa1: match 1u8 {
460                    1 => &wpa_ie_first,
461                    _ => &wpa_ie_second,
462                },
463            }
464        })
465        .expect("frame construction failed");
466        assert_eq!(buffer.len(), 24);
467        assert_eq!(
468            &[
469                0xdd, 0x16, // Vendor IE header
470                0x00, 0x50, 0xf2, // MSFT OUI
471                0x01, 0x01, 0x00, // WPA IE header
472                0x00, 0x50, 0xf2, 0x02, // multicast cipher: TKIP
473                0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher: TKIP
474                0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
475            ][..],
476            &buffer[..]
477        );
478
479        let buffer = write_frame!({
480            ies: {
481                wpa1: match 2u8 {
482                    1 => &wpa_ie_first,
483                    _ => &wpa_ie_second,
484                },
485            }
486        })
487        .expect("frame construction failed");
488        assert_eq!(buffer.len(), 24);
489        assert_eq!(
490            &[
491                0xdd, 0x16, // Vendor IE header
492                0x00, 0x50, 0xf2, // MSFT OUI
493                0x01, 0x01, 0x00, // WPA IE header
494                0x00, 0x50, 0xf2, 0x04, // multicast cipher: CCMP_128
495                0x01, 0x00, 0x00, 0x50, 0xf2, 0x04, // 1 unicast cipher: CCMP_128
496                0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
497            ][..],
498            &buffer[..]
499        );
500    }
501
502    #[test]
503    fn write_ht_caps() {
504        let buffer = write_frame!({
505            ies: {
506                ht_cap: &ie::HtCapabilities {
507                    ht_cap_info: ie::HtCapabilityInfo(0x1234),
508                    ampdu_params: ie::AmpduParams(42),
509                    mcs_set: ie::SupportedMcsSet(0x1200_3400_5600_7800_9000_1200_3400_5600),
510                    ht_ext_cap: ie::HtExtCapabilities(0x1234),
511                    txbf_cap: ie::TxBfCapability(0x12345678),
512                    asel_cap: ie::AselCapability(43),
513                },
514            }
515        })
516        .expect("frame construction failed");
517        assert_eq!(buffer.len(), 28);
518        assert_eq!(
519            &[
520                45, 26, // Element header
521                0x34, 0x12, // ht_cap_info
522                42,   // ampdu_params
523                0, 0x56, 0, 0x34, 0, 0x12, 0, 0x90, 0, 0x78, 0, 0x56, 0, 0x34, 0,
524                0x12, // mcs_set
525                0x34, 0x12, // ht_ext_cap
526                0x78, 0x56, 0x34, 0x12, // txbf_cap
527                43,   // asel_cap
528            ][..],
529            &buffer[..]
530        );
531    }
532
533    #[test]
534    fn write_vht_caps() {
535        let buffer = write_frame!({
536            ies: {
537                vht_cap: &ie::VhtCapabilities {
538                    vht_cap_info: ie::VhtCapabilitiesInfo(0x1200_3400),
539                    vht_mcs_nss: ie::VhtMcsNssSet(0x1200_3400_5600_7800),
540                },
541            }
542        })
543        .expect("frame construction failed");
544        assert_eq!(buffer.len(), 14);
545        assert_eq!(
546            &[
547                191, 12, // Element header
548                0, 0x34, 0, 0x12, // vht_cap_info
549                0, 0x78, 0, 0x56, 0, 0x34, 0, 0x12, // vht_mcs_nss
550            ][..],
551            &buffer[..]
552        );
553    }
554
555    #[test]
556    fn write_dsss_param_set() {
557        let buffer = write_frame!({
558            ies: {
559                dsss_param_set: &ie::DsssParamSet {
560                    current_channel: 42
561                },
562            }
563        })
564        .expect("frame construction failed");
565        assert_eq!(buffer.len(), 3);
566        assert_eq!(&[3, 1, 42][..], &buffer[..]);
567    }
568
569    #[test]
570    fn write_bss_max_idle_period() {
571        let buffer = write_frame!({
572            ies: {
573                bss_max_idle_period: &ie::BssMaxIdlePeriod {
574                    max_idle_period: 42,
575                    idle_options: ie::IdleOptions(8),
576                },
577            }
578        })
579        .expect("frame construction failed");
580        assert_eq!(buffer.len(), 5);
581        assert_eq!(&[90, 3, 42, 0, 8,][..], &buffer[..]);
582    }
583
584    #[test]
585    fn write_fields() {
586        // Some expression which can't be statically evaluated but always returns true.
587        let v = vec![5; 5];
588        let always_true = v.len() < 6;
589        let mut ht_capabilities = None;
590        if !always_true {
591            ht_capabilities = Some(ie::HtCapabilities {
592                ht_cap_info: ie::HtCapabilityInfo(0x1234),
593                ampdu_params: ie::AmpduParams(42),
594                mcs_set: ie::SupportedMcsSet(0x1200_3400_5600_7800_9000_1200_3400_5600),
595                ht_ext_cap: ie::HtExtCapabilities(0x1234),
596                txbf_cap: ie::TxBfCapability(0x12345678),
597                asel_cap: ie::AselCapability(43),
598            });
599        }
600
601        let buffer = write_frame!({
602            ies: {
603                ssid: if always_true { &[2u8; 2][..] } else { &[2u8; 33][..] },
604                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9],
605                ht_cap?: ht_capabilities,
606                vht_cap?: if always_true {
607                    &ie::VhtCapabilities {
608                        vht_cap_info: ie::VhtCapabilitiesInfo(0x1200_3400),
609                        vht_mcs_nss: ie::VhtMcsNssSet(0x1200_3400_5600_7800),
610                    }
611                },
612                extended_supported_rates: {},
613            }
614        })
615        .expect("frame construction failed");
616        assert_eq!(buffer.len(), 31);
617        #[rustfmt::skip]
618        assert_eq!(
619            &[
620                0, 2, 2, 2, // SSID
621                1, 8, 1, 2, 3, 4, 5, 6, 7, 8, // rates
622                191, 12, // VHT Element header
623                0, 0x34, 0, 0x12, // vht_cap_info
624                0, 0x78, 0, 0x56, 0, 0x34, 0, 0x12, // vht_mcs_nss
625                50, 1, 9, // extended rates
626            ][..],
627            &buffer[..]
628        );
629    }
630
631    #[test]
632    fn write_headers() {
633        let buffer = write_frame!({
634            headers: {
635                // Struct expressions:
636                MgmtHdr: &MgmtHdr {
637                    frame_ctrl: FrameControl(0x1234),
638                    duration: 42,
639                    addr1: MacAddr::from([7; 6]),
640                    addr2: MacAddr::from([6; 6]),
641                    addr3: MacAddr::from([5; 6]),
642                    seq_ctrl: SequenceControl(0x5678),
643                },
644                // Block expression:
645                DeauthHdr: {
646                    &DeauthHdr { reason_code: fidl_ieee80211::ReasonCode::MicFailure.into() }
647                },
648                // Repeat and literal expressions:
649                MacAddr: &MacAddr::from([2u8; 6]),
650                u8: &42u8,
651                // Function invocation:
652                MgmtHdr: &make_mgmt_hdr(),
653            }
654        })
655        .expect("frame construction failed");
656        assert_eq!(buffer.len(), 57);
657        #[rustfmt::skip]
658        assert_eq!(
659            &[
660                // Struct expression: MgmtHdr
661                0x34, 0x12, 42, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 0x78, 0x56,
662                // Struct expression: DeauthHdr
663                14, 0,
664                // Repeat and literal expressions:
665                2, 2, 2, 2, 2, 2,
666                42,
667                // Function call: MgmtHdr
668                0x21, 0x43, 42, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 0x65, 0x87,
669            ][..],
670            &buffer[..]
671        );
672    }
673
674    #[test]
675    fn write_body() {
676        let buffer = write_frame!({
677            body: &[9u8; 9],
678        })
679        .expect("frame construction failed");
680        assert_eq!(buffer.len(), 9);
681        assert_eq!(&[9, 9, 9, 9, 9, 9, 9, 9, 9][..], &buffer[..]);
682    }
683
684    #[test]
685    fn write_payload() {
686        let buffer = write_frame!({
687            payload: &[9u8; 9],
688        })
689        .expect("frame construction failed");
690        assert_eq!(buffer.len(), 9);
691        assert_eq!(&[9, 9, 9, 9, 9, 9, 9, 9, 9][..], &buffer[..]);
692    }
693
694    #[test]
695    fn write_complex() {
696        let buffer = write_frame!({
697            headers: {
698                MgmtHdr: &MgmtHdr {
699                    frame_ctrl: FrameControl(0x1234),
700                    duration: 42,
701                    addr1: MacAddr::from([7; 6]),
702                    addr2: MacAddr::from([6; 6]),
703                    addr3: MacAddr::from([5; 6]),
704                    seq_ctrl: SequenceControl(0x5678),
705                },
706                DeauthHdr: {
707                    &DeauthHdr { reason_code: fidl_ieee80211::ReasonCode::MicFailure.into() }
708                },
709                MacAddr: &MacAddr::from([2u8; 6]),
710                u8: &42u8,
711                MgmtHdr: &make_mgmt_hdr(),
712            },
713            body: vec![41u8; 3],
714            ies: {
715                ssid: &[2u8; 2][..],
716                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9],
717                vht_cap: &ie::VhtCapabilities {
718                    vht_cap_info: ie::VhtCapabilitiesInfo(0x1200_3400),
719                    vht_mcs_nss: ie::VhtMcsNssSet(0x1200_3400_5600_7800),
720                },
721                extended_supported_rates: {},
722            },
723            payload: vec![42u8; 5]
724        })
725        .expect("frame construction failed");
726        assert_eq!(buffer.len(), 96);
727        #[rustfmt::skip]
728        assert_eq!(
729            &[
730                // Headers:
731                0x34, 0x12, 42, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 0x78, 0x56,
732                14, 0,
733                2, 2, 2, 2, 2, 2,
734                42,
735                0x21, 0x43, 42, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 0x65, 0x87,
736                // Body:
737                41, 41, 41,
738                // Fields:
739                0, 2, 2, 2, // SSID
740                1, 8, 1, 2, 3, 4, 5, 6, 7, 8, // rates
741                191, 12, // VHT Element header
742                0, 0x34, 0, 0x12, // vht_cap_info
743                0, 0x78, 0, 0x56, 0, 0x34, 0, 0x12, // vht_mcs_nss
744                50, 1, 9, // extended rates
745                // Payload:
746                42, 42, 42, 42, 42,
747            ][..],
748            &buffer[..]
749        );
750    }
751
752    #[test]
753    fn write_complex_verify_order() {
754        let buffer = write_frame!({
755            payload: vec![42u8; 5],
756            ies: {
757                ssid: &[2u8; 2][..],
758                supported_rates: &[1u8, 2, 3, 4, 5, 6, 7, 8, 9],
759                vht_cap: &ie::VhtCapabilities {
760                    vht_cap_info: ie::VhtCapabilitiesInfo(0x1200_3400),
761                    vht_mcs_nss: ie::VhtMcsNssSet(0x1200_3400_5600_7800),
762                },
763                extended_supported_rates: {},
764            },
765            body: vec![41u8; 3],
766            headers: {
767                MgmtHdr: &MgmtHdr {
768                    frame_ctrl: FrameControl(0x1234),
769                    duration: 42,
770                    addr1: MacAddr::from([7; 6]),
771                    addr2: MacAddr::from([6; 6]),
772                    addr3: MacAddr::from([5; 6]),
773                    seq_ctrl: SequenceControl(0x5678),
774                },
775                DeauthHdr: {
776                    &DeauthHdr { reason_code: fidl_ieee80211::ReasonCode::MicFailure.into() }
777                },
778                MacAddr: &MacAddr::from([2u8; 6]),
779                u8: &42u8,
780                MgmtHdr: &make_mgmt_hdr(),
781            },
782        })
783        .expect("frame construction failed");
784        assert_eq!(buffer.len(), 96);
785        #[rustfmt::skip]
786        assert_eq!(
787            &[
788                // Headers:
789                0x34, 0x12, 42, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 0x78, 0x56,
790                14, 0,
791                2, 2, 2, 2, 2, 2,
792                42,
793                0x21, 0x43, 42, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 0x65, 0x87,
794                // Body:
795                41, 41, 41,
796                // Fields:
797                0, 2, 2, 2, // SSID
798                1, 8, 1, 2, 3, 4, 5, 6, 7, 8, // rates
799                191, 12, // VHT Element header
800                0, 0x34, 0, 0x12, // vht_cap_info
801                0, 0x78, 0, 0x56, 0, 0x34, 0, 0x12, // vht_mcs_nss
802                50, 1, 9, // extended rates
803                // Payload:
804                42, 42, 42, 42, 42,
805            ][..],
806            &buffer[..]
807        );
808    }
809
810    #[test]
811    fn write_nothing() {
812        let buffer = write_frame!({}).expect("frame construction failed");
813        assert_eq!(0, buffer.len());
814        assert_eq!(&[0u8; 0], &buffer[..]);
815    }
816}