wlan_common/ie/
write.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
5use super::constants::*;
6use super::fields::*;
7use super::id::Id;
8use super::rsn::rsne;
9use super::{wpa, wsc};
10use crate::append::{Append, BufferTooSmall};
11use crate::error::FrameWriteError;
12use crate::organization::Oui;
13use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
14use zerocopy::IntoBytes;
15
16macro_rules! validate {
17    ( $condition:expr, $fmt:expr $(, $args:expr)* $(,)? ) => {
18        if !$condition {
19            return Err($crate::error::FrameWriteError::InvalidData(format!($fmt, $($args,)*)));
20        }
21    };
22}
23
24macro_rules! write_ie {
25    ( $buf:expr, $id:expr, $( $part:expr ),* ) => {
26        {
27            let body_len = 0 $( + ::std::mem::size_of_val($part) )*;
28            validate!(body_len <= crate::ie::IE_MAX_LEN,
29                "Element body length {} exceeds max of 255", body_len);
30            if !$buf.can_append(2 + body_len) {
31                return Err(FrameWriteError::BufferTooSmall);
32            }
33            $buf.append_value(&$id)
34                    .expect("expected enough room in the buffer for element id");
35            $buf.append_byte(body_len as u8)
36                    .expect("expected enough room in the buffer for element length");
37            $(
38                $buf.append_value($part)
39                        .expect("expected enough room in the buffer for element fields");
40            )*
41            Ok(())
42        }
43    }
44}
45
46pub fn write_ssid<B: Append>(buf: &mut B, ssid: &[u8]) -> Result<(), FrameWriteError> {
47    validate!(
48        ssid.len() <= (fidl_ieee80211::MAX_SSID_BYTE_LEN as usize),
49        "SSID is too long (max: {} bytes, got: {})",
50        fidl_ieee80211::MAX_SSID_BYTE_LEN,
51        ssid.len()
52    );
53    write_ie!(buf, Id::SSID, ssid)
54}
55
56pub fn write_supported_rates<B: Append>(buf: &mut B, rates: &[u8]) -> Result<(), FrameWriteError> {
57    validate!(!rates.is_empty(), "List of Supported Rates is empty");
58    validate!(
59        rates.len() <= SUPPORTED_RATES_MAX_LEN,
60        "Too many Supported Rates (max {}, got {})",
61        SUPPORTED_RATES_MAX_LEN,
62        rates.len()
63    );
64    write_ie!(buf, Id::SUPPORTED_RATES, rates)
65}
66
67pub fn write_extended_supported_rates<B: Append>(
68    buf: &mut B,
69    rates: &[u8],
70) -> Result<(), FrameWriteError> {
71    validate!(!rates.is_empty(), "List of Extended Supported Rates is empty");
72    validate!(
73        rates.len() <= EXTENDED_SUPPORTED_RATES_MAX_LEN,
74        "Too many Extended Supported Rates (max {}, got {})",
75        EXTENDED_SUPPORTED_RATES_MAX_LEN,
76        rates.len()
77    );
78    write_ie!(buf, Id::EXTENDED_SUPPORTED_RATES, rates)
79}
80
81pub fn write_rsne<B: Append>(buf: &mut B, rsne: &rsne::Rsne) -> Result<(), FrameWriteError> {
82    rsne.write_into(buf).map_err(|e| e.into())
83}
84
85pub fn write_ht_capabilities<B: Append>(
86    buf: &mut B,
87    ht_cap: &HtCapabilities,
88) -> Result<(), FrameWriteError> {
89    write_ie!(buf, Id::HT_CAPABILITIES, ht_cap.as_bytes())
90}
91
92pub fn write_ht_operation<B: Append>(
93    buf: &mut B,
94    ht_op: &HtOperation,
95) -> Result<(), FrameWriteError> {
96    write_ie!(buf, Id::HT_OPERATION, ht_op.as_bytes())
97}
98
99pub fn write_dsss_param_set<B: Append>(
100    buf: &mut B,
101    dsss: &DsssParamSet,
102) -> Result<(), FrameWriteError> {
103    write_ie!(buf, Id::DSSS_PARAM_SET, dsss)
104}
105
106pub fn write_tim<B: Append>(
107    buf: &mut B,
108    header: &TimHeader,
109    bitmap: &[u8],
110) -> Result<(), FrameWriteError> {
111    validate!(!bitmap.is_empty(), "Partial virtual bitmap in TIM is empty");
112    validate!(
113        bitmap.len() <= TIM_MAX_BITMAP_LEN,
114        "Partial virtual bitmap in TIM too large (max: {} bytes, got {})",
115        TIM_MAX_BITMAP_LEN,
116        bitmap.len()
117    );
118    write_ie!(buf, Id::TIM, header, bitmap)
119}
120
121pub fn write_bss_max_idle_period<B: Append>(
122    buf: &mut B,
123    bss_max_idle_period: &BssMaxIdlePeriod,
124) -> Result<(), FrameWriteError> {
125    write_ie!(buf, Id::BSS_MAX_IDLE_PERIOD, bss_max_idle_period)
126}
127
128pub fn write_vht_capabilities<B: Append>(
129    buf: &mut B,
130    vht_cap: &VhtCapabilities,
131) -> Result<(), FrameWriteError> {
132    write_ie!(buf, Id::VHT_CAPABILITIES, vht_cap.as_bytes())
133}
134
135pub fn write_vht_operation<B: Append>(
136    buf: &mut B,
137    vht_op: &VhtOperation,
138) -> Result<(), FrameWriteError> {
139    write_ie!(buf, Id::VHT_OPERATION, vht_op.as_bytes())
140}
141
142/// Writes the entire WPA1 IE into the given buffer, including the vendor IE header.
143pub fn write_wpa1_ie<B: Append>(buf: &mut B, wpa_ie: &wpa::WpaIe) -> Result<(), BufferTooSmall> {
144    let len = std::mem::size_of::<Oui>() + 1 + wpa_ie.len();
145    if !buf.can_append(len + 2) {
146        return Err(BufferTooSmall);
147    }
148    buf.append_value(&Id::VENDOR_SPECIFIC)?;
149    buf.append_byte(len as u8)?;
150    buf.append_value(&Oui::MSFT)?;
151    buf.append_byte(wpa::VENDOR_SPECIFIC_TYPE)?;
152    wpa_ie.write_into(buf)
153}
154
155/// Writes the entire WSC IE into the given buffer, including the vendor IE header.
156pub fn write_wsc_ie<B: Append>(buf: &mut B, wsc: &[u8]) -> Result<(), BufferTooSmall> {
157    let len = std::mem::size_of::<Oui>() + 1 + wsc.len();
158    if !buf.can_append(len + 2) {
159        return Err(BufferTooSmall);
160    }
161    buf.append_value(&Id::VENDOR_SPECIFIC)?;
162    buf.append_byte(len as u8)?;
163    buf.append_value(&Oui::MSFT)?;
164    buf.append_byte(wsc::VENDOR_SPECIFIC_TYPE)?;
165    buf.append_bytes(wsc)
166}
167
168pub fn write_wmm_param<B: Append>(buf: &mut B, wmm_param: &WmmParam) -> Result<(), BufferTooSmall> {
169    let len = std::mem::size_of::<Oui>() + 3 + ::std::mem::size_of_val(wmm_param);
170    if !buf.can_append(len + 2) {
171        return Err(BufferTooSmall);
172    }
173    buf.append_value(&Id::VENDOR_SPECIFIC)?;
174    buf.append_byte(len as u8)?;
175    buf.append_value(&Oui::MSFT)?;
176    buf.append_byte(WMM_OUI_TYPE)?;
177    buf.append_byte(WMM_PARAM_OUI_SUBTYPE)?;
178    // The version byte is 0x01 for both WMM Information and Parameter elements
179    // as of WFA WMM v1.2.0.
180    buf.append_byte(0x1)?;
181    buf.append_bytes(wmm_param.as_bytes())
182}
183
184#[cfg(test)]
185mod tests {
186    use super::*;
187    use crate::buffer_writer::BufferWriter;
188    use crate::ie::rsn::{akm, cipher};
189
190    #[test]
191    fn write_ie_body_too_long() {
192        let mut buf = vec![];
193        let mut f = || write_ie!(buf, Id::SSID, &[0u8; 256][..]);
194        assert_eq!(
195            Err(FrameWriteError::InvalidData(format!(
196                "Element body length 256 exceeds max of 255"
197            ))),
198            f()
199        );
200    }
201
202    #[test]
203    fn write_ie_buffer_too_small() {
204        let mut buf = [7u8; 5];
205        let mut writer = BufferWriter::new(&mut buf[..]);
206        let mut f = || write_ie!(writer, Id::SSID, &[1u8, 2, 3, 4][..]);
207        assert_eq!(Err(FrameWriteError::BufferTooSmall), f());
208        // Expect the buffer to be left untouched
209        assert_eq!(&[7, 7, 7, 7, 7], &buf[..]);
210    }
211
212    #[test]
213    fn write_ie_buffer_exactly_long_enough() {
214        let mut buf = [0u8; 5];
215        let mut writer = BufferWriter::new(&mut buf[..]);
216        let mut f = || write_ie!(writer, Id::SSID, &[1u8, 2, 3][..]);
217        assert_eq!(Ok(()), f());
218        assert_eq!(&[0, 3, 1, 2, 3], &buf[..]);
219    }
220
221    #[test]
222    fn ssid_ok() {
223        let mut buf = vec![];
224        write_ssid(&mut buf, &[1, 2, 3]).expect("expected Ok");
225        assert_eq!(&[0, 3, 1, 2, 3], &buf[..]);
226    }
227
228    #[test]
229    fn ssid_ok_empty() {
230        let mut buf = vec![];
231        write_ssid(&mut buf, &[]).expect("expected Ok");
232        assert_eq!(&[0, 0], &buf[..]);
233    }
234
235    #[test]
236    fn ssid_too_long() {
237        let mut buf = vec![];
238        assert_eq!(
239            Err(FrameWriteError::InvalidData(format!("SSID is too long (max: 32 bytes, got: 33)"))),
240            write_ssid(&mut buf, &[0u8; 33])
241        );
242    }
243
244    #[test]
245    fn supported_rates_ok() {
246        let mut buf = vec![];
247        write_supported_rates(&mut buf, &[1, 2, 3, 4, 5, 6, 7, 8]).expect("expected Ok");
248        assert_eq!(&[1, 8, 1, 2, 3, 4, 5, 6, 7, 8], &buf[..]);
249    }
250
251    #[test]
252    fn supported_rates_empty() {
253        let mut buf = vec![];
254        assert_eq!(
255            Err(FrameWriteError::InvalidData(format!("List of Supported Rates is empty"))),
256            write_supported_rates(&mut buf, &[])
257        );
258    }
259
260    #[test]
261    fn supported_rates_too_long() {
262        let mut buf = vec![];
263        assert_eq!(
264            Err(FrameWriteError::InvalidData(format!("Too many Supported Rates (max 8, got 9)"))),
265            write_supported_rates(&mut buf, &[0u8; 9])
266        );
267    }
268
269    #[test]
270    fn ext_supported_rates_ok() {
271        let mut buf = vec![];
272        write_extended_supported_rates(&mut buf, &[1, 2, 3, 4, 5, 6, 7, 8]).expect("expected Ok");
273        assert_eq!(&[50, 8, 1, 2, 3, 4, 5, 6, 7, 8], &buf[..]);
274    }
275
276    #[test]
277    fn ext_supported_rates_empty() {
278        let mut buf = vec![];
279        assert_eq!(
280            Err(FrameWriteError::InvalidData(format!("List of Extended Supported Rates is empty"))),
281            write_extended_supported_rates(&mut buf, &[])
282        );
283    }
284
285    #[test]
286    fn dsss_param_set() {
287        let mut buf = vec![];
288        write_dsss_param_set(&mut buf, &DsssParamSet { current_channel: 6 }).expect("expected Ok");
289        assert_eq!(&[3, 1, 6], &buf[..]);
290    }
291
292    #[test]
293    fn tim_ok() {
294        let mut buf = vec![];
295        write_tim(
296            &mut buf,
297            &TimHeader { dtim_count: 1, dtim_period: 2, bmp_ctrl: BitmapControl(3) },
298            &[4, 5, 6],
299        )
300        .expect("expected Ok");
301        assert_eq!(&[5, 6, 1, 2, 3, 4, 5, 6], &buf[..]);
302    }
303
304    #[test]
305    fn tim_empty_bitmap() {
306        let mut buf = vec![];
307        assert_eq!(
308            Err(FrameWriteError::InvalidData(format!("Partial virtual bitmap in TIM is empty"))),
309            write_tim(
310                &mut buf,
311                &TimHeader { dtim_count: 1, dtim_period: 2, bmp_ctrl: BitmapControl(3) },
312                &[]
313            )
314        );
315    }
316
317    #[test]
318    fn tim_bitmap_too_long() {
319        let mut buf = vec![];
320        assert_eq!(
321            Err(FrameWriteError::InvalidData(format!(
322                "Partial virtual bitmap in TIM too large (max: 251 bytes, got 252)"
323            ))),
324            write_tim(
325                &mut buf,
326                &TimHeader { dtim_count: 1, dtim_period: 2, bmp_ctrl: BitmapControl(3) },
327                &[0u8; 252][..]
328            )
329        );
330    }
331
332    #[test]
333    fn test_write_wpa1_ie() {
334        let wpa_ie = wpa::WpaIe {
335            multicast_cipher: cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::TKIP },
336            unicast_cipher_list: vec![cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::TKIP }],
337            akm_list: vec![akm::Akm { oui: Oui::MSFT, suite_type: akm::PSK }],
338        };
339        let expected: Vec<u8> = vec![
340            0xdd, 0x16, // Vendor IE header
341            0x00, 0x50, 0xf2, // MSFT OUI
342            0x01, 0x01, 0x00, // WPA IE header
343            0x00, 0x50, 0xf2, 0x02, // multicast cipher: AKM
344            0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher: TKIP
345            0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
346        ];
347        let mut buf = vec![];
348        write_wpa1_ie(&mut buf, &wpa_ie).expect("WPA1 write to a Vec should never fail");
349        assert_eq!(&expected[..], &buf[..]);
350    }
351
352    #[test]
353    fn test_write_wpa1_ie_buffer_too_small() {
354        let wpa_ie = wpa::WpaIe {
355            multicast_cipher: cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::TKIP },
356            unicast_cipher_list: vec![cipher::Cipher { oui: Oui::MSFT, suite_type: cipher::TKIP }],
357            akm_list: vec![akm::Akm { oui: Oui::MSFT, suite_type: akm::PSK }],
358        };
359
360        let mut buf = [0u8; 10];
361        let mut writer = BufferWriter::new(&mut buf[..]);
362        write_wpa1_ie(&mut writer, &wpa_ie).expect_err("WPA1 write to short buf should fail");
363        // The buffer is not long enough, so no bytes should be written.
364        assert_eq!(writer.into_written().len(), 0);
365    }
366
367    #[test]
368    fn test_write_wmm_param() {
369        let wmm_param = WmmParam {
370            wmm_info: WmmInfo(0).with_ap_wmm_info(ApWmmInfo(0).with_uapsd(true)),
371            _reserved: 0,
372            ac_be_params: WmmAcParams {
373                aci_aifsn: WmmAciAifsn(0).with_aifsn(3).with_aci(0),
374                ecw_min_max: EcwMinMax(0).with_ecw_min(4).with_ecw_max(10),
375                txop_limit: 0,
376            },
377            ac_bk_params: WmmAcParams {
378                aci_aifsn: WmmAciAifsn(0).with_aifsn(7).with_aci(1),
379                ecw_min_max: EcwMinMax(0).with_ecw_min(4).with_ecw_max(10),
380                txop_limit: 0,
381            },
382            ac_vi_params: WmmAcParams {
383                aci_aifsn: WmmAciAifsn(0).with_aifsn(2).with_aci(2),
384                ecw_min_max: EcwMinMax(0).with_ecw_min(3).with_ecw_max(4),
385                txop_limit: 94,
386            },
387            ac_vo_params: WmmAcParams {
388                aci_aifsn: WmmAciAifsn(0).with_aifsn(2).with_aci(3),
389                ecw_min_max: EcwMinMax(0).with_ecw_min(2).with_ecw_max(3),
390                txop_limit: 47,
391            },
392        };
393        let expected: Vec<u8> = vec![
394            // WMM parameters
395            0xdd, 0x18, // Vendor IE header
396            0x00, 0x50, 0xf2, // MSFT OUI
397            0x02, 0x01, // WMM Type and WMM Parameter Subtype
398            0x01, // Version 1
399            0x80, // U-APSD enabled
400            0x00, // reserved
401            0x03, 0xa4, 0x00, 0x00, // AC_BE parameters
402            0x27, 0xa4, 0x00, 0x00, // AC_BK parameters
403            0x42, 0x43, 0x5e, 0x00, // AC_VI parameters
404            0x62, 0x32, 0x2f, 0x00, // AC_VO parameters
405        ];
406        let mut buf = vec![];
407        write_wmm_param(&mut buf, &wmm_param).expect("WmmParam write to a Vec should never fail");
408        assert_eq!(&expected[..], &buf[..]);
409    }
410
411    #[test]
412    fn ht_capabilities_ok() {
413        let mut buf = vec![];
414        let ht_cap = crate::ie::fake_ies::fake_ht_capabilities();
415        write_ht_capabilities(&mut buf, &ht_cap).expect("writing ht cap");
416        assert_eq!(
417            &buf[..],
418            &[
419                45, 26, // HT Cap id and length
420                254, 1, 0, 255, 0, 0, 0, 1, // byte 0-7
421                0, 0, 0, 0, 0, 0, 0, 1, // byte 8-15
422                0, 0, 0, 0, 0, 0, 0, 0, // byte 16-23
423                0, 0, // byte 24-25
424            ]
425        );
426    }
427
428    #[test]
429    fn ht_operation_ok() {
430        let mut buf = vec![];
431        let ht_op = crate::ie::fake_ies::fake_ht_operation();
432        write_ht_operation(&mut buf, &ht_op).expect("writing ht op");
433        assert_eq!(
434            &buf[..],
435            &[
436                61, 22, // HT Op id and length
437                36, 5, 20, 0, 0, 0, 255, 0, // byte 0-7
438                0, 0, 1, 0, 0, 0, 0, 0, // byte 8-15
439                0, 0, 1, 0, 0, 0, // byte 16-21
440            ]
441        );
442    }
443
444    #[test]
445    fn vht_capabilities_ok() {
446        let mut buf = vec![];
447        let vht_cap = crate::ie::fake_ies::fake_vht_capabilities();
448        write_vht_capabilities(&mut buf, &vht_cap).expect("writing vht cap");
449        assert_eq!(
450            &buf[..],
451            &[
452                191, 12, // VHT Cap id and length
453                177, 2, 0, 177, 3, 2, 99, 67, // byte 0-7
454                3, 2, 99, 3, // byte 8-11
455            ]
456        );
457    }
458
459    #[test]
460    fn vht_operation_ok() {
461        let mut buf = vec![];
462        let vht_op = crate::ie::fake_ies::fake_vht_operation();
463        write_vht_operation(&mut buf, &vht_op).expect("writing vht op");
464        assert_eq!(
465            &buf[..],
466            &[
467                192, 5, // VHT Op id and length
468                1, 42, 0, 27, 27, // byte 0-4
469            ]
470        );
471    }
472
473    #[test]
474    fn rsne_ok() {
475        let mut buf = vec![];
476        let rsne = rsne::from_bytes(&crate::test_utils::fake_frames::fake_wpa2_rsne()[..])
477            .expect("creating rsne")
478            .1;
479        write_rsne(&mut buf, &rsne).expect("writing rsne");
480        assert_eq!(
481            &buf[..],
482            &[
483                48, 18, // RSNE id and length
484                1, 0, 0, 15, 172, 4, 1, 0, // byte 0-7
485                0, 15, 172, 4, 1, 0, 0, 15, // byte 8-15
486                172, 2, // byte 16-17
487            ]
488        );
489    }
490
491    #[test]
492    fn bss_max_idle_period_ok() {
493        let mut buf = vec![];
494        write_bss_max_idle_period(
495            &mut buf,
496            &BssMaxIdlePeriod {
497                max_idle_period: 99,
498                idle_options: IdleOptions(0).with_protected_keep_alive_required(true),
499            },
500        )
501        .expect("writing bss max idle period");
502        assert_eq!(&buf[..], &[90, 3, 99, 0, 1]);
503    }
504}