wlan_common/ie/
owe_transition.rs

1// Copyright 2026 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::buffer_reader::BufferReader;
6use anyhow::{bail, format_err};
7use ieee80211::{Bssid, Ssid};
8
9pub const VENDOR_SPECIFIC_TYPE: u8 = 0x1C;
10
11/// WFA Opportunistic Wireless Encryption Specification v1.0, Section 2.3.1
12#[derive(Eq, PartialEq, Hash, Clone, Debug)]
13pub struct OweTransition {
14    pub bssid: Bssid,
15    pub ssid: Ssid,
16    pub band_and_channel: Option<[u8; 2]>,
17}
18
19pub fn parse_owe_transition(raw_body: &[u8]) -> Result<OweTransition, anyhow::Error> {
20    let mut reader = BufferReader::new(raw_body);
21    const TOO_SHORT_ERR: &'static str = "OWE Transition Element too short";
22    let bssid = *reader
23        .read::<Bssid>()
24        .ok_or_else(|| format_err!("Failed parsing BSSID: {}", TOO_SHORT_ERR))?;
25    let ssid_length = reader
26        .read_byte()
27        .ok_or_else(|| format_err!("Failed parsing SSID length: {}", TOO_SHORT_ERR))?;
28    let ssid = reader
29        .read_array(ssid_length as usize)
30        .ok_or_else(|| format_err!("Failed parsing SSID: {}", TOO_SHORT_ERR))?;
31    let ssid =
32        Ssid::try_from(&*ssid).map_err(|e| format_err!("Unexpected error reading SSID {:?}", e))?;
33
34    let mut band_and_channel = None;
35    if reader.bytes_remaining() > 0 {
36        band_and_channel = Some(*reader.read::<[u8; 2]>().ok_or_else(|| {
37            format_err!("Failed parsing band and channel info: {}", TOO_SHORT_ERR)
38        })?);
39    }
40
41    if reader.bytes_remaining() > 0 {
42        bail!("OWE Transition Element too long");
43    }
44
45    Ok(OweTransition { bssid, ssid, band_and_channel })
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn test_parse_owe_transition() {
54        let raw: Vec<u8> = vec![
55            0x02, 0x00, 0x00, 0x00, 0x00, 0x01, // BSSID
56            0x03, // SSID length
57            0x66, 0x6f, 0x6f, // SSID "foo"
58            0x01, 0x06, // Band and channel
59        ];
60        let owe_transition = parse_owe_transition(&raw).unwrap();
61        assert_eq!(owe_transition.bssid, Bssid::from([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]));
62        assert_eq!(owe_transition.ssid, b"foo"[..]);
63        assert_eq!(owe_transition.band_and_channel, Some([0x01, 0x06]));
64
65        let raw_no_band_channel: Vec<u8> = vec![
66            0x02, 0x00, 0x00, 0x00, 0x00, 0x01, // BSSID
67            0x03, // SSID length
68            0x66, 0x6f, 0x6f, // SSID "foo"
69        ];
70        let owe_transition = parse_owe_transition(&raw_no_band_channel).unwrap();
71        assert_eq!(owe_transition.bssid, Bssid::from([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]));
72        assert_eq!(owe_transition.ssid, b"foo"[..]);
73        assert_eq!(owe_transition.band_and_channel, None);
74    }
75}