-
Notifications
You must be signed in to change notification settings - Fork 457
/
Copy pathethernet.rs
123 lines (113 loc) · 4.46 KB
/
ethernet.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use super::*;
impl InterfaceInner {
pub(super) fn process_ethernet<'frame>(
&mut self,
sockets: &mut SocketSet,
meta: crate::phy::PacketMeta,
frame: &'frame [u8],
fragments: &'frame mut FragmentsBuffer,
) -> Option<EthernetPacket<'frame>> {
let eth_frame = check!(EthernetFrame::new_checked(frame));
// Ignore any packets not directed to our hardware address or any of the multicast groups.
if !eth_frame.dst_addr().is_broadcast()
&& !eth_frame.dst_addr().is_multicast()
&& HardwareAddress::Ethernet(eth_frame.dst_addr()) != self.hardware_addr
{
return None;
}
#[cfg(feature = "proto-vlan")]
if let Some(vlan_config) = &self.vlan_config {
// Drop all frames without VLAN header
match vlan_config.outer_vlan_id {
Some(_) if eth_frame.ethertype() != EthernetProtocol::VlanOuter => return None,
None if eth_frame.ethertype() != EthernetProtocol::VlanInner => return None,
_ => (),
}
}
self.handle_ethertype(
sockets,
meta,
eth_frame.payload(),
eth_frame.ethertype(),
fragments,
)
}
fn handle_ethertype<'frame>(
&mut self,
sockets: &mut SocketSet,
meta: crate::phy::PacketMeta,
payload: &'frame [u8],
ethertype: EthernetProtocol,
fragments: &'frame mut FragmentsBuffer,
) -> Option<EthernetPacket<'frame>> {
match ethertype {
#[cfg(feature = "proto-ipv4")]
EthernetProtocol::Arp => self.process_arp(self.now, payload),
#[cfg(feature = "proto-ipv4")]
EthernetProtocol::Ipv4 => {
let ipv4_packet = check!(Ipv4Packet::new_checked(payload));
self.process_ipv4(sockets, meta, &ipv4_packet, fragments)
.map(EthernetPacket::Ip)
}
#[cfg(feature = "proto-ipv6")]
EthernetProtocol::Ipv6 => {
let ipv6_packet = check!(Ipv6Packet::new_checked(payload));
self.process_ipv6(sockets, meta, &ipv6_packet)
.map(EthernetPacket::Ip)
}
#[cfg(feature = "proto-vlan")]
EthernetProtocol::VlanInner | EthernetProtocol::VlanOuter => match &self.vlan_config {
Some(vlan_config) => {
let vlan_packet = check!(VlanPacket::new_checked(payload));
if ethertype == EthernetProtocol::VlanOuter
&& (vlan_config.outer_vlan_id.is_none()
|| !matches!(
vlan_config.outer_vlan_id,
Some(vid) if vid == vlan_packet.vlan_identifier()
)
|| vlan_packet.ethertype() != EthernetProtocol::VlanInner)
{
return None;
}
if ethertype == EthernetProtocol::VlanInner
&& (vlan_packet.ethertype() == EthernetProtocol::VlanInner
|| vlan_packet.ethertype() == EthernetProtocol::VlanOuter
|| vlan_packet.vlan_identifier() != vlan_config.inner_vlan_id)
{
return None;
}
return self.handle_ethertype(
sockets,
meta,
&payload[VlanPacket::<&[u8]>::header_len()..],
vlan_packet.ethertype(),
fragments,
);
}
None => None,
},
// Drop all other traffic.
_ => None,
}
}
pub(super) fn dispatch_ethernet<Tx, F>(
&mut self,
tx_token: Tx,
buffer_len: usize,
f: F,
) -> Result<(), DispatchError>
where
Tx: TxToken,
F: FnOnce(EthernetFrame<&mut [u8]>),
{
let tx_len = EthernetFrame::<&[u8]>::buffer_len(buffer_len);
tx_token.consume(tx_len, |tx_buffer| {
debug_assert!(tx_buffer.as_ref().len() == tx_len);
let mut frame = EthernetFrame::new_unchecked(tx_buffer);
let src_addr = self.hardware_addr.ethernet_or_panic();
frame.set_src_addr(src_addr);
f(frame);
Ok(())
})
}
}