wlan_common/ie/wsc/
parse.rs

1// Copyright 2020 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::*;
6use crate::error::{FrameParseError, FrameParseResult};
7use anyhow::{format_err, Context};
8use zerocopy::SplitByteSlice;
9
10macro_rules! validate {
11    ( $condition:expr, $message:expr ) => {
12        if !$condition {
13            return Err($crate::error::FrameParseError(format!($message)));
14        }
15    };
16}
17
18/// Parse the Wi-Fi Simple Configuration from the probe response
19/// This operation performs a copy of the data.
20pub fn parse_probe_resp_wsc(raw_body: &[u8]) -> Result<ProbeRespWsc, anyhow::Error> {
21    let mut version = None;
22    let mut wps_state = None;
23    let mut ap_setup_locked = false;
24    let mut selected_reg = false;
25    let mut selected_reg_config_methods = None;
26    let mut response_type = None;
27    let mut uuid_e = None;
28    let mut manufacturer = None;
29    let mut model_name = None;
30    let mut model_number = None;
31    let mut serial_number = None;
32    let mut primary_device_type = None;
33    let mut device_name = None;
34    let mut config_methods = None;
35    let mut rf_bands = None;
36    let mut vendor_ext = vec![];
37
38    for (id, body) in Reader::new(raw_body) {
39        match id {
40            Id::VERSION => version = Some(parse_version(body)?),
41            Id::WPS_STATE => wps_state = Some(parse_wps_state(body)?),
42            Id::AP_SETUP_LOCKED => ap_setup_locked = parse_bool(body).context("AP setup locked")?,
43            Id::SELECTED_REG => selected_reg = parse_bool(body).context("Selected reg")?,
44            Id::SELECTED_REG_CONFIG_METHODS => {
45                selected_reg_config_methods = Some(parse_selected_reg_config_methods(body)?)
46            }
47            Id::RESPONSE_TYPE => response_type = Some(parse_response_type(body)?),
48            Id::UUID_E => uuid_e = Some(parse_uuid_e(body)?),
49            Id::MANUFACTURER => manufacturer = Some(parse_manufacturer(body)?.to_vec()),
50            Id::MODEL_NAME => model_name = Some(parse_model_name(body)?.to_vec()),
51            Id::MODEL_NUMBER => model_number = Some(parse_model_number(body)?.to_vec()),
52            Id::SERIAL_NUMBER => serial_number = Some(parse_serial_number(body)?.to_vec()),
53            Id::PRIMARY_DEVICE_TYPE => primary_device_type = Some(parse_primary_device_type(body)?),
54            Id::DEVICE_NAME => device_name = Some(parse_device_name(body)?.to_vec()),
55            Id::CONFIG_METHODS => config_methods = Some(parse_config_methods(body)?),
56            Id::RF_BANDS => rf_bands = Some(parse_rf_bands(body)?),
57            Id::VENDOR_EXT => vendor_ext.extend_from_slice(body),
58            _ => (),
59        }
60    }
61
62    let version = version.ok_or_else(|| format_err!("Missing version"))?;
63    let wps_state = wps_state.ok_or_else(|| format_err!("Missing WSC state"))?;
64    let response_type = response_type.ok_or_else(|| format_err!("Missing response type"))?;
65    let uuid_e = uuid_e.ok_or_else(|| format_err!("Missing UUID-E"))?;
66    let manufacturer = manufacturer.ok_or_else(|| format_err!("Missing manufacturer"))?;
67    let model_name = model_name.ok_or_else(|| format_err!("Missing model name"))?;
68    let model_number = model_number.ok_or_else(|| format_err!("Missing model number"))?;
69    let serial_number = serial_number.ok_or_else(|| format_err!("Missing serial number"))?;
70    let primary_device_type =
71        primary_device_type.ok_or_else(|| format_err!("Missing primary device type"))?;
72    let device_name = device_name.ok_or_else(|| format_err!("Missing device name"))?;
73    let config_methods = config_methods.ok_or_else(|| format_err!("Missing config methods"))?;
74
75    Ok(ProbeRespWsc {
76        version,
77        wps_state,
78        ap_setup_locked,
79        selected_reg,
80        selected_reg_config_methods,
81        response_type,
82        uuid_e,
83        manufacturer,
84        model_name,
85        model_number,
86        serial_number,
87        primary_device_type,
88        device_name,
89        config_methods,
90        rf_bands,
91        vendor_ext,
92    })
93}
94
95pub fn parse_version(raw_body: &[u8]) -> FrameParseResult<u8> {
96    validate!(raw_body.len() == 1, "Version attribute is not the right length");
97    Ok(raw_body[0])
98}
99
100pub fn parse_wps_state(raw_body: &[u8]) -> FrameParseResult<WpsState> {
101    validate!(raw_body.len() == 1, "WPS state attribute is not the right length");
102    Ok(WpsState(raw_body[0]))
103}
104
105pub fn parse_bool(raw_body: &[u8]) -> FrameParseResult<bool> {
106    validate!(raw_body.len() == 1, "Bool attribute is not the right length");
107    Ok(raw_body[0] != 0)
108}
109
110pub fn parse_selected_reg_config_methods(raw_body: &[u8]) -> FrameParseResult<[u8; 2]> {
111    raw_body
112        .try_into()
113        .map_err(|_| FrameParseError(format!("Failed to parse selected registrar config methods")))
114}
115
116pub fn parse_response_type(raw_body: &[u8]) -> FrameParseResult<u8> {
117    validate!(raw_body.len() == 1, "Response type attribute is not the right length");
118    Ok(raw_body[0])
119}
120
121pub fn parse_uuid_e(raw_body: &[u8]) -> FrameParseResult<[u8; 16]> {
122    raw_body.try_into().map_err(|_| FrameParseError(format!("Failed to parse UUID IE")))
123}
124
125pub fn parse_manufacturer<B: SplitByteSlice>(raw_body: B) -> FrameParseResult<B> {
126    validate!(raw_body.len() <= MANUFACTURER_ATTR_MAX_LEN, "Manufacturer attribute is too long");
127    Ok(raw_body)
128}
129
130pub fn parse_model_name<B: SplitByteSlice>(raw_body: B) -> FrameParseResult<B> {
131    validate!(raw_body.len() <= MODEL_NAME_ATTR_MAX_LEN, "Model name attribute is too long");
132    Ok(raw_body)
133}
134
135pub fn parse_model_number<B: SplitByteSlice>(raw_body: B) -> FrameParseResult<B> {
136    validate!(raw_body.len() <= MODEL_NUMBER_ATTR_MAX_LEN, "Model number attribute is too long");
137    Ok(raw_body)
138}
139
140pub fn parse_serial_number<B: SplitByteSlice>(raw_body: B) -> FrameParseResult<B> {
141    validate!(raw_body.len() <= SERIAL_NUMBER_ATTR_MAX_LEN, "Serial number attribute is too long");
142    Ok(raw_body)
143}
144
145pub fn parse_primary_device_type(raw_body: &[u8]) -> FrameParseResult<[u8; 8]> {
146    raw_body.try_into().map_err(|_| FrameParseError(format!("Failed to parse primary device type")))
147}
148
149pub fn parse_device_name<B: SplitByteSlice>(raw_body: B) -> FrameParseResult<B> {
150    validate!(raw_body.len() <= DEVICE_NAME_ATTR_MAX_LEN, "Serial number attribute is too long");
151    Ok(raw_body)
152}
153
154pub fn parse_config_methods(raw_body: &[u8]) -> FrameParseResult<[u8; 2]> {
155    raw_body.try_into().map_err(|_| FrameParseError(format!("Failed to parse config methods")))
156}
157
158pub fn parse_rf_bands(raw_body: &[u8]) -> FrameParseResult<u8> {
159    validate!(raw_body.len() == 1, "RF Bands is not the right length");
160    Ok(raw_body[0])
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166    use crate::ie::fake_ies::{fake_probe_resp_wsc_ie, fake_probe_resp_wsc_ie_bytes};
167
168    #[test]
169    fn test_parse_probe_resp_wsc() {
170        #[rustfmt::skip]
171        let raw = fake_probe_resp_wsc_ie_bytes();
172        let expected = fake_probe_resp_wsc_ie();
173
174        let parsed = parse_probe_resp_wsc(&raw[..]);
175        assert!(parsed.is_ok());
176        assert_eq!(parsed.unwrap(), expected);
177    }
178}