1use netstack3_base::{AnyDevice, DeviceIdContext, FrameDestination};
8use packet_formats::ipv6::ext_hdrs::{
9 DestinationOptionData, ExtensionHeaderOption, FragmentData, HopByHopOptionData,
10 Ipv6ExtensionHeaderData,
11};
12use packet_formats::ipv6::Ipv6Packet;
13use zerocopy::SplitByteSlice;
14
15#[derive(Debug, PartialEq, Eq)]
17pub(crate) enum Ipv6PacketAction {
18 _Discard,
20
21 Continue,
27
28 ProcessFragment,
32}
33
34pub(crate) fn handle_extension_headers<CC: DeviceIdContext<AnyDevice>, B: SplitByteSlice>(
42 core_ctx: &mut CC,
43 device: &CC::DeviceId,
44 frame_dst: Option<FrameDestination>,
45 packet: &Ipv6Packet<B>,
46 at_destination: bool,
47) -> Ipv6PacketAction {
48 let mut action = Ipv6PacketAction::Continue;
53 let mut iter = packet.iter_extension_hdrs();
54
55 if at_destination {
56 while action == Ipv6PacketAction::Continue {
59 let ext_hdr = match iter.next() {
60 None => break,
61 Some(x) => x,
62 };
63
64 match ext_hdr.data() {
65 Ipv6ExtensionHeaderData::HopByHopOptions { options } => {
66 action = handle_hop_by_hop_options_ext_hdr(
67 core_ctx,
68 device,
69 frame_dst,
70 packet,
71 options.iter(),
72 );
73 }
74 Ipv6ExtensionHeaderData::Fragment { fragment_data } => {
75 action =
76 handle_fragment_ext_hdr(core_ctx, device, frame_dst, packet, fragment_data);
77 }
78 Ipv6ExtensionHeaderData::DestinationOptions { options } => {
79 action = handle_destination_options_ext_hdr(
80 core_ctx,
81 device,
82 frame_dst,
83 packet,
84 options.iter(),
85 );
86 }
87 }
88 }
89 } else {
90 if let Some(ext_hdr) = iter.next() {
94 if let Ipv6ExtensionHeaderData::HopByHopOptions { options } = ext_hdr.data() {
95 action = handle_hop_by_hop_options_ext_hdr(
96 core_ctx,
97 device,
98 frame_dst,
99 packet,
100 options.iter(),
101 );
102 }
103 }
104 }
105
106 action
107}
108
109fn handle_hop_by_hop_options_ext_hdr<
115 'a,
116 CC: DeviceIdContext<AnyDevice>,
117 B: SplitByteSlice,
118 I: Iterator<Item = ExtensionHeaderOption<HopByHopOptionData<'a>>>,
119>(
120 _bindings_ctx: &mut CC,
121 _device: &CC::DeviceId,
122 _frame_dst: Option<FrameDestination>,
123 _packet: &Ipv6Packet<B>,
124 options: I,
125) -> Ipv6PacketAction {
126 for option in options {
127 match option.data {
128 HopByHopOptionData::Unrecognized { .. } => {}
132 HopByHopOptionData::RouterAlert { .. } => {}
135 }
136 }
137
138 Ipv6PacketAction::Continue
139}
140
141fn handle_fragment_ext_hdr<'a, CC: DeviceIdContext<AnyDevice>, B: SplitByteSlice>(
143 _bindings_ctx: &mut CC,
144 _device: &CC::DeviceId,
145 _frame_dst: Option<FrameDestination>,
146 _packet: &Ipv6Packet<B>,
147 _fragment_data: &FragmentData<'a>,
148) -> Ipv6PacketAction {
149 Ipv6PacketAction::ProcessFragment
150}
151
152fn handle_destination_options_ext_hdr<
158 'a,
159 CC: DeviceIdContext<AnyDevice>,
160 B: SplitByteSlice,
161 I: Iterator<Item = ExtensionHeaderOption<DestinationOptionData<'a>>>,
162>(
163 _bindings_ctx: &mut CC,
164 _device: &CC::DeviceId,
165 _frame_dst: Option<FrameDestination>,
166 _packet: &Ipv6Packet<B>,
167 options: I,
168) -> Ipv6PacketAction {
169 for option in options {
170 match option.data {
171 DestinationOptionData::Unrecognized { .. } => {}
175 }
176 }
177
178 Ipv6PacketAction::Continue
179}
180
181#[cfg(test)]
182mod tests {
183 use alloc::vec;
184
185 use netstack3_base::testutil::{FakeDeviceId, TEST_ADDRS_V6};
186 use packet::serialize::{Buf, Serializer};
187 use packet::ParseBuffer;
188 use packet_formats::ip::IpProto;
189 use packet_formats::ipv6::Ipv6PacketBuilder;
190
191 use super::*;
192
193 type FakeCoreCtx = netstack3_base::testutil::FakeCoreCtx<(), (), FakeDeviceId>;
194
195 #[test]
196 fn test_no_extension_headers() {
197 let mut core_ctx = FakeCoreCtx::default();
199 let builder = Ipv6PacketBuilder::new(
200 TEST_ADDRS_V6.remote_ip,
201 TEST_ADDRS_V6.local_ip,
202 10,
203 IpProto::Tcp.into(),
204 );
205 let frame_dst = FrameDestination::Individual { local: true };
206 let mut buffer =
207 Buf::new(vec![1, 2, 3, 4, 5], ..).encapsulate(builder).serialize_vec_outer().unwrap();
208 let packet = buffer.parse::<Ipv6Packet<_>>().unwrap();
209
210 assert_eq!(
211 handle_extension_headers(&mut core_ctx, &FakeDeviceId, Some(frame_dst), &packet, false),
212 Ipv6PacketAction::Continue
213 );
214 }
215}