1use byteorder::{BigEndian, ReadBytesExt};
2use bytes::{Buf, BufMut, BytesMut};
3use std::io::{Cursor, Error, Read};
4
5const AARP_MIN_LEN: usize = 28;
6
7pub type EthernetMac = [u8; 6];
8
9#[derive(Debug)]
10pub enum AarpError {
11 InvalidSize,
12 UnknownOpcode(u16),
13 StdIoError(Error),
14}
15
16impl From<Error> for AarpError {
17 fn from(err: Error) -> AarpError {
18 AarpError::StdIoError(err)
19 }
20}
21
22#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
23pub struct AppleTalkAddress {
24 pub network_number: u16,
25 pub node_number: u8,
26}
27
28impl AppleTalkAddress {
29 pub fn decode(address_bytes: [u8; 4]) -> Self {
30 let network_number = u16::from_be_bytes([address_bytes[1], address_bytes[2]]);
31 let node_number = address_bytes[3];
32
33 AppleTalkAddress {
34 network_number,
35 node_number,
36 }
37 }
38
39 pub fn encode(&self, encoded_address: &mut [u8; 4]) {
40 encoded_address[0] = 0;
41 encoded_address[1..=2].copy_from_slice(&self.network_number.to_be_bytes());
42 encoded_address[3] = self.node_number;
43 }
44
45 pub fn matches(&self, other: &AppleTalkAddress, source: AddressSource) -> bool {
46 match source {
47 AddressSource::LocalTalk => self.node_number == other.node_number,
48 AddressSource::EtherTalkPhase1 => self.node_number == other.node_number,
49 AddressSource::EtherTalkPhase2 => self == other,
50 }
51 }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum AddressSource {
56 EtherTalkPhase2,
57 EtherTalkPhase1,
58 LocalTalk,
59}
60
61#[repr(u16)]
62#[derive(Debug, PartialEq, Eq, Copy, Clone)]
63pub enum AarpOpcode {
64 Request = 1,
65 Response = 2,
66 Probe = 3,
67}
68
69#[derive(Debug, PartialEq, Eq)]
70pub struct AarpPacket {
71 pub hardware_type: u16,
72 pub protocol_type: u16,
73 pub hardware_size: u8, pub protocol_size: u8, pub opcode: AarpOpcode,
76 pub sender_addr: EthernetMac,
77 pub sender_protocol: AppleTalkAddress,
78 pub target_addr: EthernetMac,
79 pub target_protocol: AppleTalkAddress,
80}
81
82impl AarpPacket {
83 pub const LEN: usize = 28;
84
85 pub fn parse(buf: &[u8]) -> Result<Self, AarpError> {
86 if buf.len() < AARP_MIN_LEN {
87 return Err(AarpError::InvalidSize);
88 }
89
90 let mut cursor = Cursor::new(buf);
91 let hardware_type = cursor.read_u16::<BigEndian>()?;
92 let protocol_type = cursor.read_u16::<BigEndian>()?;
93 let hardware_size = cursor.read_u8()?;
94 let protocol_size = cursor.read_u8()?;
95 let opcode = {
96 let opcode = cursor.read_u16::<BigEndian>()?;
97
98 match opcode {
99 1 => AarpOpcode::Request,
100 2 => AarpOpcode::Response,
101 3 => AarpOpcode::Probe,
102 _ => return Err(AarpError::UnknownOpcode(opcode)),
103 }
104 };
105
106 let mut sender_addr: [u8; 6] = [0u8; 6];
107 cursor.read_exact(&mut sender_addr)?;
108
109 let mut protocol: [u8; 4] = [0u8; 4];
110 cursor.read_exact(&mut protocol)?;
111 let sender_protocol = AppleTalkAddress::decode(protocol);
112
113 let mut target_addr: [u8; 6] = [0u8; 6];
114 cursor.read_exact(&mut target_addr)?;
115
116 cursor.read_exact(&mut protocol)?;
117 let target_protocol = AppleTalkAddress::decode(protocol);
118
119 Ok(Self {
120 hardware_type,
121 protocol_type,
122 hardware_size,
123 protocol_size,
124 opcode,
125 sender_addr,
126 sender_protocol,
127 target_addr,
128 target_protocol,
129 })
130 }
131
132 pub fn to_bytes(&self, buffer: &mut [u8]) -> usize {
133 let mut buf = BytesMut::with_capacity(buffer.len());
134 buf.put_u16(self.hardware_type);
135 buf.put_u16(self.protocol_type);
136 buf.put_u8(self.hardware_size);
137 buf.put_u8(self.protocol_size);
138 buf.put_u16(self.opcode as u16);
139
140 buf.put_slice(&self.sender_addr);
141
142 let mut sender_protocol_encoded = [0u8; 4];
143 self.sender_protocol.encode(&mut sender_protocol_encoded);
144 buf.put_slice(&sender_protocol_encoded);
145
146 buf.put_slice(&self.target_addr);
147
148 let mut target_protocol_encoded = [0u8; 4];
149 self.target_protocol.encode(&mut target_protocol_encoded);
150 buf.put_slice(&target_protocol_encoded);
151
152 let used = buf.chunk();
153 buffer[..used.len()].copy_from_slice(used);
154
155 used.len()
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use assert_hex::assert_eq_hex;
163
164 #[test]
165 fn test_parse_aarp() {
166 let test_data: &[u8] = &[
167 0x00, 0x01, 0x80, 0x9b, 0x06, 0x04, 0x00, 0x03, 0x00, 0x0c, 0x29, 0x0d, 0x56, 0xe3,
168 0x00, 0xff, 0x54, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x54, 0x44,
169 ];
170
171 let packet = AarpPacket::parse(test_data).expect("failed to parse");
172
173 assert_eq_hex!(packet.hardware_type, 1);
174 assert_eq_hex!(packet.protocol_type, 0x809b);
175 assert_eq_hex!(packet.hardware_size, 6);
176 assert_eq_hex!(packet.protocol_size, 4);
177 assert_eq_hex!(packet.opcode, AarpOpcode::Probe);
178 assert_eq_hex!(packet.sender_addr, [0x00u8, 0x0c, 0x29, 0x0d, 0x56, 0xe3]);
179 assert_eq_hex!(packet.sender_protocol.network_number, 65364);
180 assert_eq_hex!(packet.sender_protocol.node_number, 68);
181 assert_eq_hex!(packet.target_addr, [0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00]);
182 assert_eq_hex!(packet.target_protocol.network_number, 65364);
183 assert_eq_hex!(packet.target_protocol.node_number, 68);
184 }
185
186 #[test]
187 fn test_generate_aarp() {
188 let test_pkt = AarpPacket {
189 hardware_type: 1,
190 protocol_type: 0x809b,
191 hardware_size: 6,
192 protocol_size: 4,
193 opcode: AarpOpcode::Probe,
194 sender_addr: [0x00u8, 0x0c, 0x29, 0x0d, 0x56, 0xe3],
195 sender_protocol: AppleTalkAddress {
196 network_number: 65310,
197 node_number: 248,
198 },
199 target_addr: [0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00],
200 target_protocol: AppleTalkAddress {
201 network_number: 65310,
202 node_number: 248,
203 },
204 };
205
206 let mut test_buf: [u8; 100] = [0u8; 100];
207
208 let pkt_size = test_pkt.to_bytes(&mut test_buf);
209 let sized = &test_buf[..pkt_size];
210 let expected_bin_data = &[
211 0x00u8, 0x01, 0x80, 0x9b, 0x06, 0x04, 0x00, 0x03, 0x00, 0x0c, 0x29, 0x0d, 0x56, 0xe3,
212 0x00, 0xff, 0x1e, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1e, 0xf8,
213 ];
214
215 assert_eq_hex!(sized, expected_bin_data);
216 }
217
218 #[test]
219 fn test_dogfood() {
220 let test_pkt = AarpPacket {
221 hardware_type: 1,
222 protocol_type: 0x809b,
223 hardware_size: 6,
224 protocol_size: 4,
225 opcode: AarpOpcode::Request,
226 sender_addr: [0x00u8, 0x0c, 0x29, 0x0d, 0x56, 0xe3],
227 sender_protocol: AppleTalkAddress {
228 network_number: 12345,
229 node_number: 100,
230 },
231 target_addr: [0x00u8, 0x01, 0x02, 0x03, 0x04, 0x05],
232 target_protocol: AppleTalkAddress {
233 network_number: 54321,
234 node_number: 200,
235 },
236 };
237
238 let mut test_buf: [u8; 100] = [0u8; 100];
239 let pkt_size = test_pkt.to_bytes(&mut test_buf);
240 let sized = &test_buf[..pkt_size];
241
242 let parsed = AarpPacket::parse(sized).expect("failed to parse");
243
244 assert_eq!(test_pkt, parsed);
245 }
246}