wlan_common/ie/wsc/
parse.rs
1use 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
18pub 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}