1use std::fmt;
16
17use nom::bits::{bits, streaming};
18use nom::error::{Error, ErrorKind};
19use nom::number::streaming::be_u8;
20use nom::IResult;
21#[cfg(feature = "serde")]
22use serde::{Deserialize, Serialize};
23
24const OPTIONS_HEADER: u8 = 0x83;
25
26#[derive(Clone, PartialEq, Eq)]
27#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28pub enum MobileIDType {
29 Off,
30
31 Esn,
33
34 Equipment,
37
38 Subscriber,
41
42 Defined,
44
45 PhoneNumber,
47
48 IpAddress,
50
51 Cdma,
54}
55
56impl MobileIDType {
57 pub fn parse(input: &[u8]) -> IResult<&[u8], MobileIDType> {
58 let (i, _): (&[u8], u8) = be_u8::<_, (_, ErrorKind)>(input).unwrap();
59 let (i, b): (&[u8], u8) = be_u8::<_, (_, ErrorKind)>(i).unwrap();
60
61 match b {
62 0 => Ok((i, MobileIDType::Off)),
63 1 => Ok((i, MobileIDType::Esn)),
64 2 => Ok((i, MobileIDType::Equipment)),
65 3 => Ok((i, MobileIDType::Subscriber)),
66 4 => Ok((i, MobileIDType::Defined)),
67 5 => Ok((i, MobileIDType::PhoneNumber)),
68 6 => Ok((i, MobileIDType::IpAddress)),
69 7 => Ok((i, MobileIDType::Cdma)),
70 _ => panic!("not found"),
71 }
72 }
73}
74
75impl fmt::Display for MobileIDType {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 match *self {
78 MobileIDType::Off => write!(f, "MobileIDType::Off"),
79 MobileIDType::Esn => write!(f, "MobileIDType::Esn"),
80 MobileIDType::Equipment => write!(f, "MobileIDType::Equipament"),
81 MobileIDType::Subscriber => write!(f, "MobileIDType::Subscriber"),
82 MobileIDType::Defined => write!(f, "MobileIDType::Defined"),
83 MobileIDType::PhoneNumber => write!(f, "MobileIDType::PhoneNumber"),
84 MobileIDType::IpAddress => write!(f, "MobileIDType::IpAddress"),
85 MobileIDType::Cdma => write!(f, "MobileIDType::Cdma"),
86 }
87 }
88}
89
90impl fmt::Debug for MobileIDType {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 match *self {
93 MobileIDType::Off => write!(f, "MobileIDType::Off"),
94 MobileIDType::Esn => write!(f, "MobileIDType::Esn"),
95 MobileIDType::Equipment => write!(f, "MobileIDType::Equipament"),
96 MobileIDType::Subscriber => write!(f, "MobileIDType::Subscriber"),
97 MobileIDType::Defined => write!(f, "MobileIDType::Defined"),
98 MobileIDType::PhoneNumber => write!(f, "MobileIDType::PhoneNumber"),
99 MobileIDType::IpAddress => write!(f, "MobileIDType::IpAddress"),
100 MobileIDType::Cdma => write!(f, "MobileIDType::Cdma"),
101 }
102 }
103}
104
105#[derive(Debug)]
106#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
107pub struct MobileID(pub String);
108
109impl MobileID {
110 pub fn len(&self) -> usize {
111 self.0.len()
112 }
113
114 pub fn parse(input: &[u8]) -> IResult<&[u8], Self> {
115 let (i, a): (&[u8], u8) = be_u8::<_, (_, ErrorKind)>(input).unwrap();
116 let (i, b): (&[u8], &[u8]) = nom::bytes::streaming::take(a)(i)?;
117 let mut id = String::from("");
118 for d in b.iter() {
119 id.push_str(&format!("{0:2x}", d))
120 }
121 Ok((i, Self(id)))
122 }
123
124 pub fn is_empty(&self) -> bool {
125 self.len() == 0
126 }
127}
128
129#[derive(Debug)]
130#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
131pub struct OptionsStatus {
132 pub is_mobile_id: bool,
134
135 pub is_mobile_id_type: bool,
137
138 pub is_authentication_world: bool,
140
141 pub is_routing: bool,
143
144 pub is_forwarding: bool,
146
147 pub is_response_redirection: bool,
149
150 pub is_options_extension: bool,
152
153 pub is_always_set: bool,
155}
156
157impl OptionsStatus {
158 pub fn is_mobile_id(&self) -> bool {
159 self.is_mobile_id
160 }
161
162 pub fn is_mobile_id_type(&self) -> bool {
163 self.is_mobile_id_type
164 }
165
166 pub fn is_authentication_world(&self) -> bool {
167 self.is_authentication_world
168 }
169
170 pub fn is_routing(&self) -> bool {
171 self.is_routing
172 }
173
174 pub fn is_forwarding(&self) -> bool {
175 self.is_forwarding
176 }
177
178 pub fn is_response_redirection(&self) -> bool {
179 self.is_response_redirection
180 }
181
182 pub fn is_options_extension(&self) -> bool {
183 self.is_options_extension
184 }
185
186 pub fn is_always_set(&self) -> bool {
187 self.is_always_set
188 }
189}
190
191fn is_options_header(input: u8) -> bool {
192 input == OPTIONS_HEADER
193}
194
195#[derive(Debug)]
196#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
197pub struct OptionsHeader {
198 pub mobile_id: Option<MobileID>,
200
201 pub mobile_id_type: Option<MobileIDType>,
203
204 pub authentication_world: Option<bool>,
206
207 pub routing: Option<bool>,
209
210 pub forwarding: Option<bool>,
212
213 pub response_redirection: Option<bool>,
215
216 pub options_extension: Option<bool>,
218}
219
220impl OptionsHeader {
221 pub fn parse(input: &[u8]) -> IResult<&[u8], Option<Self>> {
222 if !is_options_header(input[0]) {
224 panic!("");
225 }
226
227 let (i, opt_status) = parse_options_status(input)?;
228 let mut opt_header = OptionsHeader {
229 mobile_id: None,
230 mobile_id_type: None,
231 authentication_world: None,
232 routing: None,
233 forwarding: None,
234 response_redirection: None,
235 options_extension: None,
236 };
237 let mut inp: &[u8] = &[];
238
239 if opt_status.is_mobile_id() {
241 let (i, mob_id) = MobileID::parse(i)?;
242 opt_header.mobile_id = Some(mob_id);
243 inp = i;
244 }
245
246 if opt_status.is_mobile_id_type() {
248 let (i, mob_id_tp) = MobileIDType::parse(inp)?;
249 opt_header.mobile_id_type = Some(mob_id_tp);
250 inp = i;
251 }
252
253 if opt_status.is_authentication_world() {
254 unimplemented!()
255 }
256 if opt_status.is_routing() {
257 unimplemented!()
258 }
259
260 if opt_status.is_forwarding() {
261 unimplemented!()
262 }
263
264 if opt_status.is_response_redirection() {
265 unimplemented!()
266 }
267
268 if opt_status.is_options_extension() {
269 unimplemented!()
270 }
271
272 Ok((inp, Some(opt_header)))
273 }
274}
275
276fn parse_options_status(input: &[u8]) -> IResult<&[u8], OptionsStatus> {
277 #[allow(clippy::type_complexity)]
278 let (i, b): (&[u8], (u8, u8, u8, u8, u8, u8, u8, u8)) =
279 bits::<_, _, Error<(&[u8], usize)>, _, _>(nom::sequence::tuple((
280 streaming::take(1u8),
281 streaming::take(1u8),
282 streaming::take(1u8),
283 streaming::take(1u8),
284 streaming::take(1u8),
285 streaming::take(1u8),
286 streaming::take(1u8),
287 streaming::take(1u8),
288 )))(input)?;
289 Ok((
290 i,
291 OptionsStatus {
292 is_mobile_id: b.7 == 1,
293 is_mobile_id_type: b.6 == 1,
294 is_authentication_world: b.5 == 1,
295 is_routing: b.4 == 1,
296 is_forwarding: b.3 == 1,
297 is_response_redirection: b.2 == 1,
298 is_options_extension: b.1 == 1,
299 is_always_set: b.0 == 1,
300 },
301 ))
302}
303
304#[cfg(test)]
305mod tests {
306 use super::{MobileIDType, OptionsHeader};
307
308 #[test]
309 fn test_parse_options_headers() {
310 let data: [u8; 117] = [
311 0x83, 0x05, 0x46, 0x34, 0x66, 0x32, 0x35, 0x01, 0x01, 0x01, 0x02,
312 0x3a, 0x86, 0x5f, 0xf1, 0x3a, 0x54, 0x5f, 0xf1, 0x3a, 0x57, 0xf1,
313 0xe2, 0x85, 0x78, 0xe4, 0x22, 0xd6, 0x40, 0x00, 0x01, 0x36, 0xf8,
314 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0xff,
315 0x8d, 0x02, 0x1e, 0x1e, 0x00, 0x7b, 0x21, 0x10, 0x00, 0x00, 0x00,
316 0x31, 0xe0, 0x00, 0x00, 0x10, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
317 0x22, 0x2a, 0x32, 0x00, 0x00, 0x03, 0xf1, 0x00, 0x00, 0x00, 0x00,
318 0x00, 0x00, 0x00, 0x00, 0x01, 0xc8, 0x2d, 0x3f, 0x01, 0xc8, 0x2d,
319 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 ];
323
324 let (i, opt_header) = OptionsHeader::parse(&data).unwrap();
325 match opt_header {
326 Some(opt_h) => {
327 assert_eq!(i.len(), 108);
328
329 if let Some(mob_id) = opt_h.mobile_id {
330 assert_eq!(mob_id.len(), 10);
331 assert_eq!(mob_id.0, String::from("4634663235"));
332 }
333
334 if let Some(mob_id_tp) = opt_h.mobile_id_type {
335 assert_eq!(mob_id_tp, MobileIDType::Esn);
336 assert_eq!(
337 format!("{}", mob_id_tp),
338 String::from("MobileIDType::Esn")
339 );
340 }
341 }
342 None => (),
343 }
344 }
345}