atmos/kernel/net/
eth_frame.rs1pub const ETH_HEADER_LEN: usize = 14;
21pub const VLAN_TAG_LEN: usize = 4;
23
24pub const ETHERTYPE_IPV4: u16 = 0x0800;
25pub const ETHERTYPE_ARP: u16 = 0x0806;
26pub const ETHERTYPE_VLAN: u16 = 0x8100;
27pub const ETHERTYPE_IPV6: u16 = 0x86DD;
28
29pub const MAC_BROADCAST: [u8; 6] = [0xFF; 6];
31
32#[derive(Debug, PartialEq, Eq, Clone, Copy)]
34pub enum Dispatch {
35 Arp,
37 Ipv4 { start: usize, end: usize },
39 Unsupported { ethertype: u16 },
41}
42
43#[derive(Debug, PartialEq, Eq, Clone, Copy)]
45pub enum FrameError {
46 TooShort { got: usize },
48 TruncatedVlan { got: usize },
50}
51
52pub fn dst_mac(frame: &[u8]) -> Option<[u8; 6]> {
54 if frame.len() < 6 {
55 return None;
56 }
57 let mut m = [0u8; 6];
58 m.copy_from_slice(&frame[..6]);
59 Some(m)
60}
61
62pub fn is_for_us(frame: &[u8], my_mac: [u8; 6]) -> bool {
66 match dst_mac(frame) {
67 None => false,
68 Some(d) => {
69 if d == my_mac || d == MAC_BROADCAST {
70 return true;
71 }
72 d[0] & 0x01 != 0
74 }
75 }
76}
77
78pub fn ethertype_and_payload(frame: &[u8]) -> Result<(u16, usize), FrameError> {
80 if frame.len() < ETH_HEADER_LEN {
81 return Err(FrameError::TooShort { got: frame.len() });
82 }
83 let mut et = ((frame[12] as u16) << 8) | frame[13] as u16;
84 let mut payload_start = ETH_HEADER_LEN;
85 if et == ETHERTYPE_VLAN {
86 if frame.len() < ETH_HEADER_LEN + VLAN_TAG_LEN {
87 return Err(FrameError::TruncatedVlan { got: frame.len() });
88 }
89 et = ((frame[16] as u16) << 8) | frame[17] as u16;
90 payload_start = ETH_HEADER_LEN + VLAN_TAG_LEN;
91 }
92 Ok((et, payload_start))
93}
94
95pub fn dispatch(frame: &[u8]) -> Result<Dispatch, FrameError> {
97 let (et, start) = ethertype_and_payload(frame)?;
98 match et {
99 ETHERTYPE_ARP => Ok(Dispatch::Arp),
100 ETHERTYPE_IPV4 => Ok(Dispatch::Ipv4 {
101 start,
102 end: frame.len(),
103 }),
104 other => Ok(Dispatch::Unsupported { ethertype: other }),
105 }
106}