1 use byteorder::{ByteOrder, NetworkEndian}; 2 use core::fmt; 3 4 use super::{Error, Result}; 5 6 enum_with_unknown! { 7 /// Ethernet protocol type. 8 pub enum EtherType(u16) { 9 Ipv4 = 0x0800, 10 Arp = 0x0806, 11 Ipv6 = 0x86DD 12 } 13 } 14 15 impl fmt::Display for EtherType { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result16 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 17 match *self { 18 EtherType::Ipv4 => write!(f, "IPv4"), 19 EtherType::Ipv6 => write!(f, "IPv6"), 20 EtherType::Arp => write!(f, "ARP"), 21 EtherType::Unknown(id) => write!(f, "0x{id:04x}"), 22 } 23 } 24 } 25 26 /// A six-octet Ethernet II address. 27 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)] 28 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 29 pub struct Address(pub [u8; 6]); 30 31 impl Address { 32 /// The broadcast address. 33 pub const BROADCAST: Address = Address([0xff; 6]); 34 35 /// Construct an Ethernet address from a sequence of octets, in big-endian. 36 /// 37 /// # Panics 38 /// The function panics if `data` is not six octets long. from_bytes(data: &[u8]) -> Address39 pub fn from_bytes(data: &[u8]) -> Address { 40 let mut bytes = [0; 6]; 41 bytes.copy_from_slice(data); 42 Address(bytes) 43 } 44 45 /// Return an Ethernet address as a sequence of octets, in big-endian. as_bytes(&self) -> &[u8]46 pub const fn as_bytes(&self) -> &[u8] { 47 &self.0 48 } 49 50 /// Query whether the address is an unicast address. is_unicast(&self) -> bool51 pub fn is_unicast(&self) -> bool { 52 !(self.is_broadcast() || self.is_multicast()) 53 } 54 55 /// Query whether this address is the broadcast address. is_broadcast(&self) -> bool56 pub fn is_broadcast(&self) -> bool { 57 *self == Self::BROADCAST 58 } 59 60 /// Query whether the "multicast" bit in the OUI is set. is_multicast(&self) -> bool61 pub const fn is_multicast(&self) -> bool { 62 self.0[0] & 0x01 != 0 63 } 64 65 /// Query whether the "locally administered" bit in the OUI is set. is_local(&self) -> bool66 pub const fn is_local(&self) -> bool { 67 self.0[0] & 0x02 != 0 68 } 69 } 70 71 impl fmt::Display for Address { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 73 let bytes = self.0; 74 write!( 75 f, 76 "{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}", 77 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5] 78 ) 79 } 80 } 81 82 /// A read/write wrapper around an Ethernet II frame buffer. 83 #[derive(Debug, Clone)] 84 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 85 pub struct Frame<T: AsRef<[u8]>> { 86 buffer: T, 87 } 88 89 mod field { 90 use crate::wire::field::*; 91 92 pub const DESTINATION: Field = 0..6; 93 pub const SOURCE: Field = 6..12; 94 pub const ETHERTYPE: Field = 12..14; 95 pub const PAYLOAD: Rest = 14..; 96 } 97 98 /// The Ethernet header length 99 pub const HEADER_LEN: usize = field::PAYLOAD.start; 100 101 impl<T: AsRef<[u8]>> Frame<T> { 102 /// Imbue a raw octet buffer with Ethernet frame structure. new_unchecked(buffer: T) -> Frame<T>103 pub const fn new_unchecked(buffer: T) -> Frame<T> { 104 Frame { buffer } 105 } 106 107 /// Shorthand for a combination of [new_unchecked] and [check_len]. 108 /// 109 /// [new_unchecked]: #method.new_unchecked 110 /// [check_len]: #method.check_len new_checked(buffer: T) -> Result<Frame<T>>111 pub fn new_checked(buffer: T) -> Result<Frame<T>> { 112 let packet = Self::new_unchecked(buffer); 113 packet.check_len()?; 114 Ok(packet) 115 } 116 117 /// Ensure that no accessor method will panic if called. 118 /// Returns `Err(Error)` if the buffer is too short. check_len(&self) -> Result<()>119 pub fn check_len(&self) -> Result<()> { 120 let len = self.buffer.as_ref().len(); 121 if len < HEADER_LEN { 122 Err(Error) 123 } else { 124 Ok(()) 125 } 126 } 127 128 /// Consumes the frame, returning the underlying buffer. into_inner(self) -> T129 pub fn into_inner(self) -> T { 130 self.buffer 131 } 132 133 /// Return the length of a frame header. header_len() -> usize134 pub const fn header_len() -> usize { 135 HEADER_LEN 136 } 137 138 /// Return the length of a buffer required to hold a packet with the payload 139 /// of a given length. buffer_len(payload_len: usize) -> usize140 pub const fn buffer_len(payload_len: usize) -> usize { 141 HEADER_LEN + payload_len 142 } 143 144 /// Return the destination address field. 145 #[inline] dst_addr(&self) -> Address146 pub fn dst_addr(&self) -> Address { 147 let data = self.buffer.as_ref(); 148 Address::from_bytes(&data[field::DESTINATION]) 149 } 150 151 /// Return the source address field. 152 #[inline] src_addr(&self) -> Address153 pub fn src_addr(&self) -> Address { 154 let data = self.buffer.as_ref(); 155 Address::from_bytes(&data[field::SOURCE]) 156 } 157 158 /// Return the EtherType field, without checking for 802.1Q. 159 #[inline] ethertype(&self) -> EtherType160 pub fn ethertype(&self) -> EtherType { 161 let data = self.buffer.as_ref(); 162 let raw = NetworkEndian::read_u16(&data[field::ETHERTYPE]); 163 EtherType::from(raw) 164 } 165 } 166 167 impl<'a, T: AsRef<[u8]> + ?Sized> Frame<&'a T> { 168 /// Return a pointer to the payload, without checking for 802.1Q. 169 #[inline] payload(&self) -> &'a [u8]170 pub fn payload(&self) -> &'a [u8] { 171 let data = self.buffer.as_ref(); 172 &data[field::PAYLOAD] 173 } 174 } 175 176 impl<T: AsRef<[u8]> + AsMut<[u8]>> Frame<T> { 177 /// Set the destination address field. 178 #[inline] set_dst_addr(&mut self, value: Address)179 pub fn set_dst_addr(&mut self, value: Address) { 180 let data = self.buffer.as_mut(); 181 data[field::DESTINATION].copy_from_slice(value.as_bytes()) 182 } 183 184 /// Set the source address field. 185 #[inline] set_src_addr(&mut self, value: Address)186 pub fn set_src_addr(&mut self, value: Address) { 187 let data = self.buffer.as_mut(); 188 data[field::SOURCE].copy_from_slice(value.as_bytes()) 189 } 190 191 /// Set the EtherType field. 192 #[inline] set_ethertype(&mut self, value: EtherType)193 pub fn set_ethertype(&mut self, value: EtherType) { 194 let data = self.buffer.as_mut(); 195 NetworkEndian::write_u16(&mut data[field::ETHERTYPE], value.into()) 196 } 197 198 /// Return a mutable pointer to the payload. 199 #[inline] payload_mut(&mut self) -> &mut [u8]200 pub fn payload_mut(&mut self) -> &mut [u8] { 201 let data = self.buffer.as_mut(); 202 &mut data[field::PAYLOAD] 203 } 204 } 205 206 impl<T: AsRef<[u8]>> AsRef<[u8]> for Frame<T> { as_ref(&self) -> &[u8]207 fn as_ref(&self) -> &[u8] { 208 self.buffer.as_ref() 209 } 210 } 211 212 impl<T: AsRef<[u8]>> fmt::Display for Frame<T> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result213 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 214 write!( 215 f, 216 "EthernetII src={} dst={} type={}", 217 self.src_addr(), 218 self.dst_addr(), 219 self.ethertype() 220 ) 221 } 222 } 223 224 use crate::wire::pretty_print::{PrettyIndent, PrettyPrint}; 225 226 impl<T: AsRef<[u8]>> PrettyPrint for Frame<T> { pretty_print( buffer: &dyn AsRef<[u8]>, f: &mut fmt::Formatter, indent: &mut PrettyIndent, ) -> fmt::Result227 fn pretty_print( 228 buffer: &dyn AsRef<[u8]>, 229 f: &mut fmt::Formatter, 230 indent: &mut PrettyIndent, 231 ) -> fmt::Result { 232 let frame = match Frame::new_checked(buffer) { 233 Err(err) => return write!(f, "{indent}({err})"), 234 Ok(frame) => frame, 235 }; 236 write!(f, "{indent}{frame}")?; 237 238 match frame.ethertype() { 239 #[cfg(feature = "proto-ipv4")] 240 EtherType::Arp => { 241 indent.increase(f)?; 242 super::ArpPacket::<&[u8]>::pretty_print(&frame.payload(), f, indent) 243 } 244 #[cfg(feature = "proto-ipv4")] 245 EtherType::Ipv4 => { 246 indent.increase(f)?; 247 super::Ipv4Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent) 248 } 249 #[cfg(feature = "proto-ipv6")] 250 EtherType::Ipv6 => { 251 indent.increase(f)?; 252 super::Ipv6Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent) 253 } 254 _ => Ok(()), 255 } 256 } 257 } 258 259 /// A high-level representation of an Internet Protocol version 4 packet header. 260 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 261 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 262 pub struct Repr { 263 pub src_addr: Address, 264 pub dst_addr: Address, 265 pub ethertype: EtherType, 266 } 267 268 impl Repr { 269 /// Parse an Ethernet II frame and return a high-level representation. parse<T: AsRef<[u8]> + ?Sized>(frame: &Frame<&T>) -> Result<Repr>270 pub fn parse<T: AsRef<[u8]> + ?Sized>(frame: &Frame<&T>) -> Result<Repr> { 271 frame.check_len()?; 272 Ok(Repr { 273 src_addr: frame.src_addr(), 274 dst_addr: frame.dst_addr(), 275 ethertype: frame.ethertype(), 276 }) 277 } 278 279 /// Return the length of a header that will be emitted from this high-level representation. buffer_len(&self) -> usize280 pub const fn buffer_len(&self) -> usize { 281 HEADER_LEN 282 } 283 284 /// Emit a high-level representation into an Ethernet II frame. emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, frame: &mut Frame<T>)285 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, frame: &mut Frame<T>) { 286 frame.set_src_addr(self.src_addr); 287 frame.set_dst_addr(self.dst_addr); 288 frame.set_ethertype(self.ethertype); 289 } 290 } 291 292 #[cfg(test)] 293 mod test { 294 // Tests that are valid with any combination of 295 // "proto-*" features. 296 use super::*; 297 298 #[test] test_broadcast()299 fn test_broadcast() { 300 assert!(Address::BROADCAST.is_broadcast()); 301 assert!(!Address::BROADCAST.is_unicast()); 302 assert!(Address::BROADCAST.is_multicast()); 303 assert!(Address::BROADCAST.is_local()); 304 } 305 } 306 307 #[cfg(test)] 308 #[cfg(feature = "proto-ipv4")] 309 mod test_ipv4 { 310 // Tests that are valid only with "proto-ipv4" 311 use super::*; 312 313 static FRAME_BYTES: [u8; 64] = [ 314 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x08, 0x00, 0xaa, 315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 318 0x00, 0x00, 0x00, 0xff, 319 ]; 320 321 static PAYLOAD_BYTES: [u8; 50] = [ 322 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 325 0x00, 0x00, 0x00, 0x00, 0xff, 326 ]; 327 328 #[test] test_deconstruct()329 fn test_deconstruct() { 330 let frame = Frame::new_unchecked(&FRAME_BYTES[..]); 331 assert_eq!( 332 frame.dst_addr(), 333 Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]) 334 ); 335 assert_eq!( 336 frame.src_addr(), 337 Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]) 338 ); 339 assert_eq!(frame.ethertype(), EtherType::Ipv4); 340 assert_eq!(frame.payload(), &PAYLOAD_BYTES[..]); 341 } 342 343 #[test] test_construct()344 fn test_construct() { 345 let mut bytes = vec![0xa5; 64]; 346 let mut frame = Frame::new_unchecked(&mut bytes); 347 frame.set_dst_addr(Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06])); 348 frame.set_src_addr(Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16])); 349 frame.set_ethertype(EtherType::Ipv4); 350 frame.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]); 351 assert_eq!(&frame.into_inner()[..], &FRAME_BYTES[..]); 352 } 353 } 354 355 #[cfg(test)] 356 #[cfg(feature = "proto-ipv6")] 357 mod test_ipv6 { 358 // Tests that are valid only with "proto-ipv6" 359 use super::*; 360 361 static FRAME_BYTES: [u8; 54] = [ 362 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x86, 0xdd, 0x60, 363 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 366 ]; 367 368 static PAYLOAD_BYTES: [u8; 40] = [ 369 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 370 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 371 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 372 ]; 373 374 #[test] test_deconstruct()375 fn test_deconstruct() { 376 let frame = Frame::new_unchecked(&FRAME_BYTES[..]); 377 assert_eq!( 378 frame.dst_addr(), 379 Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]) 380 ); 381 assert_eq!( 382 frame.src_addr(), 383 Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]) 384 ); 385 assert_eq!(frame.ethertype(), EtherType::Ipv6); 386 assert_eq!(frame.payload(), &PAYLOAD_BYTES[..]); 387 } 388 389 #[test] test_construct()390 fn test_construct() { 391 let mut bytes = vec![0xa5; 54]; 392 let mut frame = Frame::new_unchecked(&mut bytes); 393 frame.set_dst_addr(Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06])); 394 frame.set_src_addr(Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16])); 395 frame.set_ethertype(EtherType::Ipv6); 396 assert_eq!(PAYLOAD_BYTES.len(), frame.payload_mut().len()); 397 frame.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]); 398 assert_eq!(&frame.into_inner()[..], &FRAME_BYTES[..]); 399 } 400 } 401