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