semtech_udp/packet/
parser.rs

1use super::*;
2use crate::tx_ack::Data;
3use std::{convert::TryFrom, result::Result};
4
5const PROTOCOL_VERSION_INDEX: usize = 0;
6const IDENTIFIER_INDEX: usize = 3;
7const PREFIX_LEN: usize = IDENTIFIER_INDEX + 1;
8const GATEWAY_MAC_LEN: usize = 8;
9
10fn random_token(buffer: &[u8]) -> u16 {
11    (buffer[1] as u16) << 8 | buffer[2] as u16
12}
13
14pub fn gateway_mac(buffer: &[u8]) -> Result<MacAddress, ParseError> {
15    if buffer.len() < GATEWAY_MAC_LEN {
16        Err(ParseError::InvalidPacketLength(
17            buffer.len(),
18            GATEWAY_MAC_LEN,
19        ))
20    } else {
21        Ok(MacAddress::new(
22            buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7],
23        ))
24    }
25}
26
27impl Packet {
28    pub fn parse_uplink(buffer: &[u8]) -> Result<Up, ParseError> {
29        match Self::parse(buffer)? {
30            Packet::Up(up) => Ok(up),
31            Packet::Down(down) => Err(ParseError::UnexpectedDownlink(down)),
32        }
33    }
34    pub fn parse_downlink(buffer: &[u8]) -> Result<Down, ParseError> {
35        match Self::parse(buffer)? {
36            Packet::Down(down) => Ok(down),
37            Packet::Up(up) => Err(ParseError::UnexpectedUplink(Box::new(up))),
38        }
39    }
40}
41
42impl Packet {
43    pub fn parse(buffer: &[u8]) -> Result<Packet, ParseError> {
44        if buffer.len() < PREFIX_LEN {
45            return Err(ParseError::InvalidPacketLength(buffer.len(), PREFIX_LEN));
46        }
47
48        let protocol_version = buffer[PROTOCOL_VERSION_INDEX];
49        if protocol_version != PROTOCOL_VERSION {
50            return Err(ParseError::InvalidProtocolVersion(protocol_version));
51        };
52
53        let frame_identifier = buffer[IDENTIFIER_INDEX];
54        match Identifier::try_from(frame_identifier) {
55            Err(_) => Err(ParseError::InvalidIdentifier(frame_identifier)),
56            Ok(id) => {
57                // the token is before the identifier which we've already done a length check for
58                let random_token = random_token(buffer);
59                let buffer = &buffer[PREFIX_LEN..];
60
61                Ok(match id {
62                    // up packets
63                    Identifier::PullData => {
64                        let gateway_mac = gateway_mac(buffer)?;
65                        pull_data::Packet {
66                            random_token,
67                            gateway_mac,
68                        }
69                        .into()
70                    }
71                    Identifier::PushData => {
72                        let gateway_mac = gateway_mac(buffer)?;
73                        let json_str =
74                            std::str::from_utf8(&buffer[GATEWAY_MAC_LEN..terminate(buffer)])?;
75                        let data = serde_json::from_str(json_str).map_err(|json_error| {
76                            ParseError::InvalidJson {
77                                identifier: id,
78                                json_str: json_str.into(),
79                                json_error,
80                            }
81                        })?;
82                        push_data::Packet {
83                            random_token,
84                            gateway_mac,
85                            data,
86                        }
87                        .into()
88                    }
89                    Identifier::TxAck => {
90                        let gateway_mac = gateway_mac(buffer)?;
91                        let data = if buffer.len() > GATEWAY_MAC_LEN {
92                            // guard against some packet forwarders that put a 0 byte as the last byte
93                            if buffer.len() == GATEWAY_MAC_LEN + 1 && buffer[GATEWAY_MAC_LEN] == 0 {
94                                Data::default()
95                            } else {
96                                let json_str = std::str::from_utf8(
97                                    &buffer[GATEWAY_MAC_LEN..terminate(buffer)],
98                                )?;
99                                serde_json::from_str(json_str).map_err(|json_error| {
100                                    ParseError::InvalidJson {
101                                        identifier: id,
102                                        json_str: json_str.into(),
103                                        json_error,
104                                    }
105                                })?
106                            }
107                        } else {
108                            Data::default()
109                        };
110                        tx_ack::Packet {
111                            random_token,
112                            gateway_mac,
113                            data,
114                        }
115                        .into()
116                    }
117                    // down packets
118                    Identifier::PushAck => push_ack::Packet { random_token }.into(),
119                    Identifier::PullAck => pull_ack::Packet { random_token }.into(),
120                    Identifier::PullResp => {
121                        let json_str = std::str::from_utf8(&buffer[..terminate(buffer)])?;
122                        let data = serde_json::from_str(json_str).map_err(|json_error| {
123                            ParseError::InvalidJson {
124                                identifier: id,
125                                json_str: json_str.into(),
126                                json_error,
127                            }
128                        })?;
129                        pull_resp::Packet { random_token, data }.into()
130                    }
131                })
132            }
133        }
134    }
135}
136
137// deals with null byte terminated json
138fn terminate(buf: &[u8]) -> usize {
139    if buf.is_empty() {
140        0
141    } else if buf[buf.len() - 1] == 0 {
142        buf.len() - 1
143    } else {
144        buf.len()
145    }
146}