1use crate::{
2 err::{ipv6, ipv6_exts},
3 *,
4};
5
6#[derive(Clone, Debug, Eq, PartialEq)]
21pub struct LaxIpv6Slice<'a> {
22 pub(crate) header: Ipv6HeaderSlice<'a>,
23 pub(crate) exts: Ipv6ExtensionsSlice<'a>,
24 pub(crate) payload: LaxIpPayloadSlice<'a>,
25}
26
27impl<'a> LaxIpv6Slice<'a> {
28 pub fn from_slice(
70 slice: &'a [u8],
71 ) -> Result<
72 (
73 LaxIpv6Slice<'a>,
74 Option<(ipv6_exts::HeaderSliceError, err::Layer)>,
75 ),
76 ipv6::HeaderSliceError,
77 > {
78 let header = Ipv6HeaderSlice::from_slice(slice)?;
80
81 let (header_payload, len_source, incomplete) =
83 if 0 == header.payload_length() && slice.len() > Ipv6Header::LEN {
84 (
90 unsafe {
91 core::slice::from_raw_parts(
92 slice.as_ptr().add(Ipv6Header::LEN),
93 slice.len() - Ipv6Header::LEN,
94 )
95 },
96 LenSource::Slice,
97 false,
98 )
99 } else {
100 let payload_len = usize::from(header.payload_length());
101 let expected_len = Ipv6Header::LEN + payload_len;
102 if slice.len() < expected_len {
103 (
104 unsafe {
105 core::slice::from_raw_parts(
106 slice.as_ptr().add(Ipv6Header::LEN),
107 slice.len() - Ipv6Header::LEN,
108 )
109 },
110 LenSource::Slice,
111 true,
112 )
113 } else {
114 (
115 unsafe {
116 core::slice::from_raw_parts(
117 slice.as_ptr().add(Ipv6Header::LEN),
118 payload_len,
119 )
120 },
121 LenSource::Ipv6HeaderPayloadLen,
122 false,
123 )
124 }
125 };
126
127 let (exts, payload_ip_number, payload, mut ext_stop_err) =
129 Ipv6ExtensionsSlice::from_slice_lax(header.next_header(), header_payload);
130
131 if let Some((ipv6_exts::HeaderSliceError::Len(err), _)) = &mut ext_stop_err {
133 err.len_source = len_source;
134 err.layer_start_offset += Ipv6Header::LEN;
135 };
136
137 let fragmented = exts.is_fragmenting_payload();
138 Ok((
139 LaxIpv6Slice {
140 header,
141 exts,
142 payload: LaxIpPayloadSlice {
143 incomplete,
144 ip_number: payload_ip_number,
145 fragmented,
146 len_source,
147 payload,
148 },
149 },
150 ext_stop_err,
151 ))
152 }
153
154 #[inline]
156 pub fn header(&self) -> Ipv6HeaderSlice<'a> {
157 self.header
158 }
159
160 #[inline]
162 pub fn extensions(&self) -> &Ipv6ExtensionsSlice<'a> {
163 &self.exts
164 }
165
166 #[inline]
169 pub fn payload(&self) -> &LaxIpPayloadSlice<'a> {
170 &self.payload
171 }
172
173 #[inline]
175 pub fn is_payload_fragmented(&self) -> bool {
176 self.payload.fragmented
177 }
178}
179
180#[cfg(test)]
181mod test {
182 use super::*;
183 use crate::{
184 err::{Layer, LenError},
185 ip_number::{AUTH, IGMP, UDP},
186 test_gens::*,
187 };
188 use alloc::{format, vec::Vec};
189 use proptest::prelude::*;
190
191 proptest! {
192 #[test]
193 fn debug_clone_eq(
194 ipv6_base in ipv6_any(),
195 auth_base in ip_auth_any()
196 ) {
197 let mut auth = auth_base.clone();
198 auth.next_header = IGMP;
199 let payload: [u8;4] = [1,2,3,4];
200 let mut data = Vec::with_capacity(
201 ipv6_base.header_len() +
202 auth.header_len() +
203 payload.len()
204 );
205 let mut ipv6 = ipv6_base.clone();
206 ipv6.next_header = AUTH;
207 ipv6.payload_length = (auth.header_len() + payload.len()) as u16;
208 data.extend_from_slice(&ipv6.to_bytes());
209 data.extend_from_slice(&auth.to_bytes());
210 data.extend_from_slice(&payload);
211
212 let (slice, _) = LaxIpv6Slice::from_slice(&data).unwrap();
214
215 prop_assert_eq!(
217 format!("{:?}", slice),
218 format!(
219 "LaxIpv6Slice {{ header: {:?}, exts: {:?}, payload: {:?} }}",
220 slice.header(),
221 slice.extensions(),
222 slice.payload()
223 )
224 );
225 prop_assert_eq!(slice.clone(), slice);
226 }
227 }
228
229 proptest! {
230 #[test]
231 fn from_slice(
232 ipv6_base in ipv6_any(),
233 auth_base in ip_auth_any()
234 ) {
235 let payload: [u8;6] = [1,2,3,4,5,6];
236
237 let data_without_ext = {
239 let mut data = Vec::with_capacity(
240 ipv6_base.header_len() +
241 payload.len() +
242 4
243 );
244 let mut ipv6 = ipv6_base.clone();
245 ipv6.payload_length = (payload.len()) as u16;
246 ipv6.next_header = UDP;
247 data.extend_from_slice(&ipv6.to_bytes());
248 data.extend_from_slice(&payload);
249 data.extend_from_slice(&[0,0,0,0]);
250 data
251 };
252 let data_with_ext = {
253 let payload: [u8;6] = [1,2,3,4,5,6];
254 let mut data = Vec::with_capacity(
255 ipv6_base.header_len() +
256 auth_base.header_len() +
257 payload.len() +
258 4
259 );
260 let mut ipv6 = ipv6_base.clone();
261 ipv6.payload_length = (auth_base.header_len() + payload.len()) as u16;
262 ipv6.next_header = AUTH;
263 let mut auth = auth_base.clone();
264 auth.next_header = UDP;
265 data.extend_from_slice(&ipv6.to_bytes());
266 data.extend_from_slice(&auth.to_bytes());
267 data.extend_from_slice(&payload);
268 data.extend_from_slice(&[0,0,0,0]);
269 data
270 };
271
272 {
274 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data_without_ext).unwrap();
275 prop_assert_eq!(None, actual_stop_err);
276 prop_assert_eq!(actual.header().slice(), &data_without_ext[..ipv6_base.header_len()]);
277 prop_assert!(actual.extensions().first_header().is_none());
278 prop_assert_eq!(
279 actual.payload(),
280 &LaxIpPayloadSlice{
281 incomplete: false,
282 ip_number: UDP.into(),
283 fragmented: false,
284 len_source: LenSource::Ipv6HeaderPayloadLen,
285 payload: &payload,
286 }
287 );
288 }
289
290 {
292 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data_with_ext).unwrap();
293 prop_assert_eq!(None, actual_stop_err);
294 prop_assert_eq!(actual.header().slice(), &data_with_ext[..ipv6_base.header_len()]);
295 let (expected, _, _) = Ipv6ExtensionsSlice::from_slice(AUTH, &data_with_ext[ipv6_base.header_len()..]).unwrap();
296 prop_assert_eq!(
297 actual.extensions(),
298 &expected
299 );
300 prop_assert_eq!(
301 actual.payload(),
302 &LaxIpPayloadSlice{
303 incomplete: false,
304 ip_number: UDP.into(),
305 fragmented: false,
306 len_source: LenSource::Ipv6HeaderPayloadLen,
307 payload: &payload,
308 }
309 );
310 }
311
312 {
314 let mut data = data_without_ext.clone();
316 data[4] = 0;
317 data[5] = 0;
318 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data).unwrap();
319 prop_assert_eq!(None, actual_stop_err);
320 prop_assert_eq!(actual.header().slice(), &data[..ipv6_base.header_len()]);
321 prop_assert!(actual.extensions().first_header().is_none());
322 prop_assert_eq!(
323 actual.payload(),
324 &LaxIpPayloadSlice{
325 incomplete: false,
326 ip_number: UDP.into(),
327 fragmented: false,
328 len_source: LenSource::Slice,
329 payload: &data[ipv6_base.header_len()..],
330 }
331 );
332 }
333
334 {
336 let mut data = data_with_ext.clone();
338 data[4] = 0;
339 data[5] = 0;
340 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data).unwrap();
341 prop_assert_eq!(None, actual_stop_err);
342 prop_assert_eq!(actual.header().slice(), &data[..ipv6_base.header_len()]);
343 let (expected, _, _) = Ipv6ExtensionsSlice::from_slice(AUTH, &data[ipv6_base.header_len()..]).unwrap();
344 prop_assert_eq!(
345 actual.extensions(),
346 &expected
347 );
348 prop_assert_eq!(
349 actual.payload(),
350 &LaxIpPayloadSlice{
351 incomplete: false,
352 ip_number: UDP.into(),
353 fragmented: false,
354 len_source: LenSource::Slice,
355 payload: &data[ipv6_base.header_len() + auth_base.header_len()..],
356 }
357 );
358 }
359
360 {
362 use crate::err::ipv6::HeaderError;
363 let mut data = data_without_ext.clone();
365 data[0] = data[0] & 0x0f; prop_assert_eq!(
367 LaxIpv6Slice::from_slice(&data).unwrap_err(),
368 ipv6::HeaderSliceError::Content(
369 HeaderError::UnexpectedVersion{ version_number: 0 }
370 )
371 );
372 }
373
374 for len in 0..Ipv6Header::LEN {
376 prop_assert_eq!(
377 LaxIpv6Slice::from_slice(&data_without_ext[..len]).unwrap_err(),
378 ipv6::HeaderSliceError::Len(
379 LenError{
380 required_len: Ipv6Header::LEN,
381 len,
382 len_source: LenSource::Slice,
383 layer: Layer::Ipv6Header,
384 layer_start_offset: 0
385 }
386 )
387 );
388 }
389
390 {
392 let len = ipv6_base.header_len() + payload.len() - 1;
393 let (actual , actual_stop_err) = LaxIpv6Slice::from_slice(&data_without_ext[..len]).unwrap();
394 prop_assert_eq!(actual_stop_err, None);
395 prop_assert_eq!(actual.header().slice(), &data_without_ext[..ipv6_base.header_len()]);
396 prop_assert_eq!(
397 0,
398 actual.extensions().slice().len()
399 );
400 prop_assert_eq!(
401 actual.payload(),
402 &LaxIpPayloadSlice{
403 incomplete: true,
404 ip_number: UDP.into(),
405 fragmented: false,
406 len_source: LenSource::Slice,
407 payload: &data_without_ext[ipv6_base.header_len()..len],
408 }
409 );
410 }
411
412 {
414 use crate::err::{LenError, Layer};
415
416 let required_len = ipv6_base.header_len() + auth_base.header_len();
417 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data_with_ext[..required_len - 1]).unwrap();
418 prop_assert_eq!(
419 actual_stop_err.unwrap(),
420 (
421 ipv6_exts::HeaderSliceError::Len(LenError{
422 required_len: required_len - Ipv6Header::LEN,
423 len: required_len - Ipv6Header::LEN - 1,
424 len_source: LenSource::Slice,
425 layer: Layer::IpAuthHeader,
426 layer_start_offset: Ipv6Header::LEN,
427 }),
428 err::Layer::IpAuthHeader
429 )
430 );
431 prop_assert_eq!(actual.header().slice(), &data_with_ext[..ipv6_base.header_len()]);
432 prop_assert_eq!(
433 actual.payload(),
434 &LaxIpPayloadSlice{
435 incomplete: true,
436 ip_number: AUTH,
437 fragmented: false,
438 len_source: LenSource::Slice,
439 payload: &data_with_ext[ipv6_base.header_len()..required_len - 1],
440 }
441 );
442 }
443
444 {
446 use crate::err::{LenError, Layer};
447
448 let mut data = data_with_ext.clone();
450 let payload_len_too_small = auth_base.header_len() - 1;
451 {
452 let plts = (payload_len_too_small as u16).to_be_bytes();
453 data[4] = plts[0];
454 data[5] = plts[1];
455 }
456
457 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data).unwrap();
458 prop_assert_eq!(
459 actual_stop_err.unwrap(),
460 (
461 ipv6_exts::HeaderSliceError::Len(
462 LenError{
463 required_len: auth_base.header_len(),
464 len: auth_base.header_len() - 1,
465 len_source: LenSource::Ipv6HeaderPayloadLen,
466 layer: Layer::IpAuthHeader,
467 layer_start_offset: ipv6_base.header_len(),
468 }
469 ),
470 err::Layer::IpAuthHeader
471 )
472 );
473 prop_assert_eq!(actual.header().slice(), &data[..ipv6_base.header_len()]);
474 prop_assert_eq!(
475 actual.payload(),
476 &LaxIpPayloadSlice{
477 incomplete: false,
478 ip_number: AUTH,
479 fragmented: false,
480 len_source: LenSource::Ipv6HeaderPayloadLen,
481 payload: &data[ipv6_base.header_len()..ipv6_base.header_len() + payload_len_too_small],
482 }
483 );
484 }
485
486 {
488 use crate::err::{ip_auth, ipv6_exts};
489
490 let mut data = data_with_ext.clone();
492 data[ipv6_base.header_len() + 1] = 0;
493
494 let (actual, actual_stop_error) = LaxIpv6Slice::from_slice(&data).unwrap();
495
496 prop_assert_eq!(
497 actual_stop_error.unwrap(),
498 (
499 ipv6_exts::HeaderSliceError::Content(ipv6_exts::HeaderError::IpAuth(
500 ip_auth::HeaderError::ZeroPayloadLen
501 )),
502 err::Layer::IpAuthHeader
503 )
504 );
505 prop_assert_eq!(
506 actual.header().slice(),
507 &data[..ipv6_base.header_len()]
508 );
509 prop_assert_eq!(
510 actual.payload(),
511 &LaxIpPayloadSlice{
512 incomplete: false,
513 ip_number: AUTH,
514 fragmented: false,
515 len_source: LenSource::Ipv6HeaderPayloadLen,
516 payload: &data[ipv6_base.header_len()..ipv6_base.header_len() + auth_base.header_len() + payload.len()],
517 }
518 );
519 }
520 }
521 }
522
523 #[test]
524 fn is_payload_fragmented() {
525 use crate::ip_number::{IPV6_FRAG, UDP};
526
527 {
529 let data = Ipv6Header {
530 traffic_class: 0,
531 flow_label: 1.try_into().unwrap(),
532 payload_length: 0,
533 next_header: UDP,
534 hop_limit: 4,
535 source: [0; 16],
536 destination: [0; 16],
537 }
538 .to_bytes();
539 assert_eq!(
540 false,
541 LaxIpv6Slice::from_slice(&data)
542 .unwrap()
543 .0
544 .is_payload_fragmented()
545 );
546 }
547
548 {
550 let ipv6_frag = Ipv6FragmentHeader {
551 next_header: UDP,
552 fragment_offset: 0.try_into().unwrap(),
553 more_fragments: true,
554 identification: 0,
555 };
556 let ipv6 = Ipv6Header {
557 traffic_class: 0,
558 flow_label: 1.try_into().unwrap(),
559 payload_length: ipv6_frag.header_len() as u16,
560 next_header: IPV6_FRAG,
561 hop_limit: 4,
562 source: [0; 16],
563 destination: [0; 16],
564 };
565
566 let mut data = Vec::with_capacity(ipv6.header_len() + ipv6_frag.header_len());
567 data.extend_from_slice(&ipv6.to_bytes());
568 data.extend_from_slice(&ipv6_frag.to_bytes());
569 assert!(Ipv6Slice::from_slice(&data)
570 .unwrap()
571 .is_payload_fragmented());
572 }
573 }
574}