blob: ac62cc8c2f7a09517d22ab2d29dd9b78f198938e [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt},
std::io,
};
#[derive(Clone, Copy, Debug)]
pub enum EtherType {
Ipv4 = 0x0800,
}
// IEEE Std 802.3-2015, 3.1.1
#[derive(Clone, Copy, Debug)]
pub struct EthHeader {
pub dst: [u8; 6],
pub src: [u8; 6],
pub eth_type: u16,
}
impl EthHeader {
pub fn from_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
let mut dst = [0u8; 6];
reader.read(&mut dst)?;
let mut src = [0u8; 6];
reader.read(&mut src)?;
let eth_type = reader.read_u16::<LittleEndian>()?;
Ok(Self { dst, src, eth_type })
}
}
pub fn write_eth_header<W: io::Write>(w: &mut W, header: &EthHeader) -> io::Result<()> {
w.write_all(&header.dst)?;
w.write_all(&header.src)?;
w.write_u16::<LittleEndian>(header.eth_type)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_eth_header() {
let mut buf = vec![];
write_eth_header(
&mut buf,
&EthHeader {
dst: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
src: [0x11, 0x12, 0x13, 0x14, 0x15, 0x16],
eth_type: EtherType::Ipv4 as u16,
},
)
.expect("Error writing ethernet header");
#[cfg_attr(rustfmt, rustfmt_skip)]
let expected_frame: &[u8] = &[
// dst
0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
// src
0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
// ether type
0x00, 0x08,
];
assert_eq!(expected_frame, &buf[..]);
}
#[test]
fn parse_eth_header() {
let mut bytes = &[
0x01u8, 0x02, 0x03, 0x04, 0x05, 0x06, // dst
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // src
0x00, 0x08, // ether_type
] as &[u8];
let eth_header = EthHeader::from_reader(&mut bytes).expect("reading eth_header");
assert_eq!(eth_header.dst, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
assert_eq!(eth_header.src, [0x11, 0x12, 0x13, 0x14, 0x15, 0x16]);
assert_eq!(eth_header.eth_type, EtherType::Ipv4 as u16);
}
}