• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{
2     err::{ValueTooBigError, ValueType},
3     *,
4 };
5 
6 /// Slice containing the TCP header & payload.
7 #[derive(Clone, Eq, PartialEq)]
8 pub struct TcpSlice<'a> {
9     header_len: usize,
10     slice: &'a [u8],
11 }
12 
13 impl<'a> TcpSlice<'a> {
14     /// Try creating a [`TcpSlice`] from a slice containing the
15     /// TCP header and the TCP payload.
from_slice(slice: &'a [u8]) -> Result<TcpSlice<'a>, err::tcp::HeaderSliceError>16     pub fn from_slice(slice: &'a [u8]) -> Result<TcpSlice<'a>, err::tcp::HeaderSliceError> {
17         use err::tcp::{HeaderError::*, HeaderSliceError::*};
18 
19         // check length
20         if slice.len() < TcpHeader::MIN_LEN {
21             return Err(Len(err::LenError {
22                 required_len: TcpHeader::MIN_LEN,
23                 len: slice.len(),
24                 len_source: LenSource::Slice,
25                 layer: err::Layer::TcpHeader,
26                 layer_start_offset: 0,
27             }));
28         }
29 
30         // SAFETY:
31         // Safe as it is checked at the start of the function that the
32         // length of the slice is at least TcpHeader::MIN_LEN (20).
33         let header_len = unsafe {
34             // The length of the TCP header can be determined via
35             // the data offset field of the TCP header. "data offset"
36             // stores the offset in 4 byte steps from the start of the
37             // header to the payload of the header.
38             //
39             // "data offset" is stored in the upper 4 bits
40             // (aka 0b1111_0000) of byte 12. To get to total length
41             // in bytes of the header data offset has to be multiplied
42             // by 4. So the naive version to get the length of
43             // the header would be:
44             //
45             // ```
46             // let data_offset = (*slice.get_unchecked(12) & 0xf0) >> 4;
47             // let len = data_offset * 4;
48             // ```
49             //
50             // But a multiplication by 4 can be replaced by 2
51             // left shift:
52             //
53             // ```
54             // let data_offset = (*slice.get_unchecked(12) & 0xf0) >> 4;
55             // let len = data_offset << 2;
56             // ```
57             //
58             // And finally the shifts can be combined to one:
59             //
60             // ```
61             // let len = (*slice.get_unchecked(12) & 0xf0) >> 2;
62             // ```
63             usize::from((*slice.get_unchecked(12) & 0xf0) >> 2)
64         };
65 
66         if header_len < TcpHeader::MIN_LEN {
67             Err(Content(DataOffsetTooSmall {
68                 data_offset: (header_len >> 2) as u8,
69             }))
70         } else if slice.len() < header_len {
71             Err(Len(err::LenError {
72                 required_len: header_len,
73                 len: slice.len(),
74                 len_source: LenSource::Slice,
75                 layer: err::Layer::TcpHeader,
76                 layer_start_offset: 0,
77             }))
78         } else {
79             //done
80             Ok(TcpSlice::<'a> { header_len, slice })
81         }
82     }
83 
84     /// Returns the slice containing the TCP header and payload.
85     #[inline]
slice(&self) -> &'a [u8]86     pub fn slice(&self) -> &'a [u8] {
87         self.slice
88     }
89 
90     /// Returns the slice containing the TCP header
91     /// (including options).
92     #[inline]
header_slice(&self) -> &'a [u8]93     pub fn header_slice(&self) -> &'a [u8] {
94         unsafe {
95             // SAFETY: Safe as the slice was verified
96             // to be at least header_len long.
97             core::slice::from_raw_parts(self.slice.as_ptr(), self.header_len)
98         }
99     }
100 
101     /// Returns the slice containing the TCP payload.
102     #[inline]
payload(&self) -> &'a [u8]103     pub fn payload(&self) -> &'a [u8] {
104         unsafe {
105             // SAFETY: Safe as the slice was verified
106             // to be at least header_len long.
107             core::slice::from_raw_parts(
108                 self.slice.as_ptr().add(self.header_len),
109                 self.slice.len() - self.header_len,
110             )
111         }
112     }
113 
114     /// Length of the TCP header (including TCP options).
115     #[inline]
header_len(&self) -> usize116     pub const fn header_len(&self) -> usize {
117         self.header_len
118     }
119 
120     /// Read the destination port number in the TCP header.
121     #[inline]
source_port(&self) -> u16122     pub fn source_port(&self) -> u16 {
123         // SAFETY:
124         // Constructor checks that the slice has at least the length
125         // of 20.
126         unsafe { get_unchecked_be_u16(self.slice.as_ptr()) }
127     }
128 
129     /// Read the destination port number in the TCP header.
130     #[inline]
destination_port(&self) -> u16131     pub fn destination_port(&self) -> u16 {
132         // SAFETY:
133         // Constructor checks that the slice has at least the length
134         // of 20.
135         unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(2)) }
136     }
137 
138     /// Read the sequence number in the TCP header.
139     ///
140     /// If SYN is present the sequence number is the initial sequence number (ISN)
141     /// and the first data octet is ISN+1.
142     /// \[copied from RFC 793, page 16\]
143     #[inline]
sequence_number(&self) -> u32144     pub fn sequence_number(&self) -> u32 {
145         // SAFETY:
146         // Constructor checks that the slice has at least the length
147         // of 20.
148         unsafe { get_unchecked_be_u32(self.slice.as_ptr().add(4)) }
149     }
150 
151     /// Reads the acknowledgment number in the TCP header.
152     ///
153     /// If the ACK control bit is set this field contains the value of the
154     /// next sequence number the sender of the segment is expecting to
155     /// receive.
156     ///
157     /// Once a connection is established this is always sent.
158     #[inline]
acknowledgment_number(&self) -> u32159     pub fn acknowledgment_number(&self) -> u32 {
160         // SAFETY:
161         // Constructor checks that the slice has at least the length
162         // of 20.
163         unsafe { get_unchecked_be_u32(self.slice.as_ptr().add(8)) }
164     }
165 
166     /// Read the number of 32 bit words in the TCP Header.
167     ///
168     /// This indicates where the payload begins. The TCP header
169     /// (even one including options) is an integral number of 32
170     /// bits long.
171     #[inline]
data_offset(&self) -> u8172     pub fn data_offset(&self) -> u8 {
173         // SAFETY:
174         // Constructor checks that the slice has at least the length
175         // of 20.
176         unsafe { (*self.slice.get_unchecked(12) & 0b1111_0000) >> 4 }
177     }
178 
179     /// ECN-nonce - concealment protection (experimental: see RFC 3540)
180     #[inline]
ns(&self) -> bool181     pub fn ns(&self) -> bool {
182         // SAFETY:
183         // Constructor checks that the slice has at least the length
184         // of 20.
185         unsafe { 0 != (*self.slice.get_unchecked(12) & 0b0000_0001) }
186     }
187 
188     /// Read the fin flag (no more data from sender).
189     #[inline]
fin(&self) -> bool190     pub fn fin(&self) -> bool {
191         // SAFETY:
192         // Constructor checks that the slice has at least the length
193         // of 20.
194         unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_0001) }
195     }
196 
197     /// Reads the syn flag (synchronize sequence numbers).
198     #[inline]
syn(&self) -> bool199     pub fn syn(&self) -> bool {
200         // SAFETY:
201         // Constructor checks that the slice has at least the length
202         // of 20.
203         unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_0010) }
204     }
205 
206     /// Reads the rst flag (reset the connection).
207     #[inline]
rst(&self) -> bool208     pub fn rst(&self) -> bool {
209         // SAFETY:
210         // Constructor checks that the slice has at least the length
211         // of 20.
212         unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_0100) }
213     }
214 
215     /// Reads the psh flag (push function).
216     #[inline]
psh(&self) -> bool217     pub fn psh(&self) -> bool {
218         // SAFETY:
219         // Constructor checks that the slice has at least the length
220         // of 20.
221         unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_1000) }
222     }
223 
224     /// Reads the ack flag (acknowledgment field significant).
225     #[inline]
ack(&self) -> bool226     pub fn ack(&self) -> bool {
227         // SAFETY:
228         // Constructor checks that the slice has at least the length
229         // of 20.
230         unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0001_0000) }
231     }
232 
233     /// Reads the urg flag (Urgent Pointer field significant).
234     #[inline]
urg(&self) -> bool235     pub fn urg(&self) -> bool {
236         // SAFETY:
237         // Constructor checks that the slice has at least the length
238         // of 20.
239         unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0010_0000) }
240     }
241 
242     /// Read the ECN-Echo flag (RFC 3168).
243     #[inline]
ece(&self) -> bool244     pub fn ece(&self) -> bool {
245         // SAFETY:
246         // Constructor checks that the slice has at least the length
247         // of 20.
248         unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0100_0000) }
249     }
250 
251     /// Reads the cwr flag (Congestion Window Reduced).
252     ///
253     /// This flag is set by the sending host to indicate that it received a TCP
254     /// segment with the ECE flag set and had responded in congestion control
255     /// mechanism (added to header by RFC 3168).
256     #[inline]
cwr(&self) -> bool257     pub fn cwr(&self) -> bool {
258         // SAFETY:
259         // Constructor checks that the slice has at least the length
260         // of 20.
261         unsafe { 0 != (*self.slice.get_unchecked(13) & 0b1000_0000) }
262     }
263 
264     /// The number of data octets beginning with the one indicated in the
265     /// acknowledgment field which the sender of this segment is willing to
266     /// accept.
267     #[inline]
window_size(&self) -> u16268     pub fn window_size(&self) -> u16 {
269         u16::from_be_bytes(
270             // SAFETY:
271             // Constructor checks that the slice has at least the length
272             // of 20.
273             unsafe { [*self.slice.get_unchecked(14), *self.slice.get_unchecked(15)] },
274         )
275     }
276 
277     /// Checksum (16 bit one's complement) of the pseudo ip header, this tcp header and the payload.
278     #[inline]
checksum(&self) -> u16279     pub fn checksum(&self) -> u16 {
280         u16::from_be_bytes(
281             // SAFETY:
282             // Constructor checks that the slice has at least the length
283             // of 20.
284             unsafe { [*self.slice.get_unchecked(16), *self.slice.get_unchecked(17)] },
285         )
286     }
287 
288     /// This field communicates the current value of the urgent pointer as a
289     /// positive offset from the sequence number in this segment.
290     ///
291     /// The urgent pointer points to the sequence number of the octet following
292     /// the urgent data.  This field is only be interpreted in segments with
293     /// the URG control bit set.
294     #[inline]
urgent_pointer(&self) -> u16295     pub fn urgent_pointer(&self) -> u16 {
296         u16::from_be_bytes(
297             // SAFETY:
298             // Constructor checks that the slice has at least the length
299             // of 20.
300             unsafe { [*self.slice.get_unchecked(18), *self.slice.get_unchecked(19)] },
301         )
302     }
303 
304     /// Options of the header
305     #[inline]
options(&self) -> &[u8]306     pub fn options(&self) -> &[u8] {
307         &self.slice[TcpHeader::MIN_LEN..self.header_len]
308     }
309 
310     /// Returns an iterator that allows to iterate through all known TCP header options.
311     #[inline]
options_iterator(&self) -> TcpOptionsIterator312     pub fn options_iterator(&self) -> TcpOptionsIterator {
313         TcpOptionsIterator::from_slice(self.options())
314     }
315 
316     /// Decode all the fields and copy the results to a
317     /// [`crate::TcpHeader`]` struct.
to_header(&self) -> TcpHeader318     pub fn to_header(&self) -> TcpHeader {
319         TcpHeader {
320             source_port: self.source_port(),
321             destination_port: self.destination_port(),
322             sequence_number: self.sequence_number(),
323             acknowledgment_number: self.acknowledgment_number(),
324             ns: self.ns(),
325             fin: self.fin(),
326             syn: self.syn(),
327             rst: self.rst(),
328             psh: self.psh(),
329             ack: self.ack(),
330             ece: self.ece(),
331             urg: self.urg(),
332             cwr: self.cwr(),
333             window_size: self.window_size(),
334             checksum: self.checksum(),
335             urgent_pointer: self.urgent_pointer(),
336             options: {
337                 let options_slice = self.options();
338                 let mut options = TcpOptions {
339                     len: options_slice.len() as u8,
340                     buf: [0; 40],
341                 };
342                 options.buf[..options_slice.len()].clone_from_slice(options_slice);
343                 options
344             },
345         }
346     }
347 
348     /// Calculates the checksum for the current header in ipv4 mode and
349     /// returns the result. This does NOT set the checksum.
calc_checksum_ipv4( &self, source_ip: [u8; 4], destination_ip: [u8; 4], ) -> Result<u16, ValueTooBigError<usize>>350     pub fn calc_checksum_ipv4(
351         &self,
352         source_ip: [u8; 4],
353         destination_ip: [u8; 4],
354     ) -> Result<u16, ValueTooBigError<usize>> {
355         // check that the total length fits into the field
356         if usize::from(u16::MAX) < self.slice.len() {
357             return Err(ValueTooBigError {
358                 actual: self.slice.len(),
359                 max_allowed: usize::from(u16::MAX),
360                 value_type: ValueType::TcpPayloadLengthIpv4,
361             });
362         }
363 
364         // calculate the checksum
365         Ok(self.calc_checksum_post_ip(
366             checksum::Sum16BitWords::new()
367                 .add_4bytes(source_ip)
368                 .add_4bytes(destination_ip)
369                 .add_2bytes([0, ip_number::TCP.0])
370                 .add_2bytes((self.slice.len() as u16).to_be_bytes()),
371         ))
372     }
373 
374     /// Calculates the checksum for the current header in ipv6 mode and
375     /// returns the result. This does NOT set the checksum.
calc_checksum_ipv6( &self, source: [u8; 16], destination: [u8; 16], ) -> Result<u16, ValueTooBigError<usize>>376     pub fn calc_checksum_ipv6(
377         &self,
378         source: [u8; 16],
379         destination: [u8; 16],
380     ) -> Result<u16, ValueTooBigError<usize>> {
381         // check that the total length fits into the field
382         #[cfg(not(any(target_pointer_width = "16", target_pointer_width = "32")))]
383         if (u32::MAX as usize) < self.slice.len() {
384             return Err(ValueTooBigError {
385                 actual: self.slice.len(),
386                 max_allowed: (u32::MAX as usize),
387                 value_type: ValueType::TcpPayloadLengthIpv6,
388             });
389         }
390 
391         // calculate the checksum
392         Ok(self.calc_checksum_post_ip(
393             checksum::Sum16BitWords::new()
394                 .add_16bytes(source)
395                 .add_16bytes(destination)
396                 .add_2bytes([0, ip_number::TCP.0])
397                 .add_4bytes((self.slice.len() as u32).to_be_bytes()),
398         ))
399     }
400 
401     /// This method takes the sum of the pseudo ip header and calculates the rest of the checksum.
calc_checksum_post_ip(&self, ip_pseudo_header_sum: checksum::Sum16BitWords) -> u16402     fn calc_checksum_post_ip(&self, ip_pseudo_header_sum: checksum::Sum16BitWords) -> u16 {
403         ip_pseudo_header_sum
404             .add_slice(&self.slice[..16]) //until checksum
405             .add_slice(&self.slice[18..])
406             .ones_complement()
407             .to_be()
408     }
409 }
410 
411 impl core::fmt::Debug for TcpSlice<'_> {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result412     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
413         f.debug_struct("TcpSlice")
414             .field("header", &self.to_header())
415             .field("payload", &self.payload())
416             .finish()
417     }
418 }
419 
420 #[cfg(test)]
421 mod test {
422     use super::*;
423     use crate::test_gens::*;
424     use alloc::{format, vec::Vec};
425     use proptest::prelude::*;
426 
427     proptest! {
428         #[test]
429         fn debug_clone_eq(
430             tcp in tcp_any()
431         ) {
432             let payload: [u8;4] = [1,2,3,4];
433             let mut data = Vec::with_capacity(
434                 tcp.header_len() as usize +
435                 payload.len()
436             );
437             data.extend_from_slice(&tcp.to_bytes());
438             data.extend_from_slice(&payload);
439 
440             // decode packet
441             let slice = TcpSlice::from_slice(&data).unwrap();
442 
443             // check debug output
444             prop_assert_eq!(
445                 format!("{:?}", slice),
446                 format!(
447                     "TcpSlice {{ header: {:?}, payload: {:?} }}",
448                     &tcp,
449                     &payload[..]
450                 )
451             );
452             prop_assert_eq!(slice.clone(), slice);
453         }
454     }
455 
456     proptest! {
457         #[test]
458         fn from_slice(
459             tcp in tcp_any()
460         ) {
461             use err::tcp::{HeaderError::*, HeaderSliceError::*};
462 
463             let payload: [u8;4] = [1,2,3,4];
464             let data = {
465                 let mut data = Vec::with_capacity(
466                     tcp.header_len() as usize +
467                     payload.len()
468                 );
469                 data.extend_from_slice(&tcp.to_bytes());
470                 data.extend_from_slice(&payload);
471                 data
472             };
473 
474             // normal decode
475             {
476                 let slice = TcpSlice::from_slice(&data).unwrap();
477                 assert_eq!(&slice.to_header(), &tcp);
478                 assert_eq!(slice.payload(), &payload);
479             }
480 
481             // too little data to even decode the header
482             for len in 0..(tcp.header_len() as usize) {
483                 assert_eq!(
484                     TcpSlice::from_slice(&data[..len]).unwrap_err(),
485                     Len(err::LenError {
486                         required_len: if len < TcpHeader::MIN_LEN {
487                             TcpHeader::MIN_LEN
488                         } else {
489                             tcp.header_len()
490                         },
491                         len,
492                         len_source: LenSource::Slice,
493                         layer: err::Layer::TcpHeader,
494                         layer_start_offset: 0,
495                     })
496                 );
497             }
498 
499             // data offset smaller then minimum header size
500             {
501                 let mut broken_data = data.clone();
502                 for data_offset in 0..TcpHeader::MIN_DATA_OFFSET {
503                     // inject a bad data offset
504                     broken_data[12] = data_offset << 4 | ( broken_data[12] & 0b0000_1111);
505                     assert_eq!(
506                         TcpSlice::from_slice(&broken_data).unwrap_err(),
507                         Content(DataOffsetTooSmall { data_offset })
508                     );
509                 }
510             }
511         }
512     }
513 
514     proptest! {
515         #[test]
516         fn getters(
517             tcp in tcp_any()
518         ) {
519             let payload: [u8;4] = [1,2,3,4];
520             let data = {
521                 let mut data = Vec::with_capacity(
522                     tcp.header_len() as usize +
523                     payload.len()
524                 );
525                 data.extend_from_slice(&tcp.to_bytes());
526                 data.extend_from_slice(&payload);
527                 data
528             };
529             let slice = TcpSlice::from_slice(&data).unwrap();
530             assert_eq!(slice.slice(), &data);
531             assert_eq!(slice.header_slice(), &data[..tcp.header_len()]);
532             assert_eq!(slice.payload(), &data[tcp.header_len()..]);
533             assert_eq!(slice.header_len(), tcp.header_len());
534             assert_eq!(slice.source_port(), tcp.source_port);
535             assert_eq!(slice.destination_port(), tcp.destination_port);
536             assert_eq!(slice.sequence_number(), tcp.sequence_number);
537             assert_eq!(slice.acknowledgment_number(), tcp.acknowledgment_number);
538             assert_eq!(slice.data_offset(), tcp.data_offset());
539             assert_eq!(slice.ns(), tcp.ns);
540             assert_eq!(slice.fin(), tcp.fin);
541             assert_eq!(slice.syn(), tcp.syn);
542             assert_eq!(slice.rst(), tcp.rst);
543             assert_eq!(slice.psh(), tcp.psh);
544             assert_eq!(slice.ack(), tcp.ack);
545             assert_eq!(slice.urg(), tcp.urg);
546             assert_eq!(slice.ece(), tcp.ece);
547             assert_eq!(slice.cwr(), tcp.cwr);
548             assert_eq!(slice.window_size(), tcp.window_size);
549             assert_eq!(slice.checksum(), tcp.checksum);
550             assert_eq!(slice.urgent_pointer(), tcp.urgent_pointer);
551             assert_eq!(slice.options(), tcp.options.as_slice());
552             assert_eq!(slice.options_iterator(), tcp.options_iterator());
553             assert_eq!(slice.to_header(), tcp);
554         }
555     }
556 
557     #[test]
calc_checksum_ipv4()558     fn calc_checksum_ipv4() {
559         use TcpOptionElement::*;
560 
561         // checksum == 0xf (no carries) (aka sum == 0xffff)
562         {
563             let payload = [1, 2, 3, 4, 5, 6, 7, 8];
564             let tcp = TcpHeader::new(0, 0, 40905, 0);
565 
566             let mut data = Vec::with_capacity(tcp.header_len() + payload.len());
567             data.extend_from_slice(&tcp.to_bytes());
568             data.extend_from_slice(&payload);
569 
570             let tcp_slice = TcpSlice::from_slice(&data).unwrap();
571             assert_eq!(Ok(0x0), tcp_slice.calc_checksum_ipv4([0; 4], [0; 4]));
572         }
573 
574         // a header with options
575         {
576             let payload = [1, 2, 3, 4, 5, 6, 7, 8];
577             let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653);
578             tcp.urgent_pointer = 0xE26E;
579             tcp.ns = true;
580             tcp.fin = true;
581             tcp.syn = true;
582             tcp.rst = true;
583             tcp.psh = true;
584             tcp.ack = true;
585             tcp.ece = true;
586             tcp.urg = true;
587             tcp.cwr = true;
588             tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)])
589                 .unwrap();
590 
591             let mut data = Vec::with_capacity(tcp.header_len() + payload.len());
592             data.extend_from_slice(&tcp.to_bytes());
593             data.extend_from_slice(&payload);
594 
595             let tcp_slice = TcpSlice::from_slice(&data).unwrap();
596 
597             assert_eq!(
598                 Ok(0xdeeb),
599                 tcp_slice.calc_checksum_ipv4([192, 168, 1, 42], [192, 168, 1, 1])
600             );
601         }
602 
603         //a header with an uneven number of options
604         {
605             let payload = [1, 2, 3, 4, 5, 6, 7, 8, 9];
606             let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653);
607             tcp.urgent_pointer = 0xE26E;
608             tcp.ns = true;
609             tcp.fin = true;
610             tcp.syn = true;
611             tcp.rst = true;
612             tcp.psh = true;
613             tcp.ack = true;
614             tcp.ece = true;
615             tcp.urg = true;
616             tcp.cwr = true;
617             tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)])
618                 .unwrap();
619 
620             let mut data = Vec::with_capacity(tcp.header_len() + payload.len());
621             data.extend_from_slice(&tcp.to_bytes());
622             data.extend_from_slice(&payload);
623 
624             let slice = TcpSlice::from_slice(&data[..]).unwrap();
625 
626             assert_eq!(
627                 Ok(0xd5ea),
628                 slice.calc_checksum_ipv4([192, 168, 1, 42], [192, 168, 1, 1])
629             );
630         }
631 
632         // value error
633         {
634             // write the tcp header
635             let tcp: TcpHeader = Default::default();
636             let mut data = Vec::with_capacity(usize::from(core::u16::MAX) + 1);
637             data.extend_from_slice(&tcp.to_bytes());
638             data.resize(usize::from(core::u16::MAX) + 1, 0); // payload
639 
640             let slice = TcpSlice::from_slice(&data).unwrap();
641 
642             assert_eq!(
643                 slice.calc_checksum_ipv4([0; 4], [0; 4]),
644                 Err(ValueTooBigError {
645                     actual: data.len(),
646                     max_allowed: usize::from(core::u16::MAX),
647                     value_type: ValueType::TcpPayloadLengthIpv4,
648                 })
649             );
650         }
651     }
652 
653     #[test]
calc_checksum_ipv6()654     fn calc_checksum_ipv6() {
655         use crate::TcpOptionElement::*;
656 
657         // ok case
658         {
659             let payload = [51, 52, 53, 54, 55, 56, 57, 58];
660             let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653);
661             tcp.urgent_pointer = 0xE26E;
662             tcp.ns = true;
663             tcp.fin = true;
664             tcp.syn = true;
665             tcp.rst = true;
666             tcp.psh = true;
667             tcp.ack = true;
668             tcp.ece = true;
669             tcp.urg = true;
670             tcp.cwr = true;
671             tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)])
672                 .unwrap();
673 
674             let mut data = Vec::with_capacity(tcp.header_len() + payload.len());
675             data.extend_from_slice(&tcp.to_bytes());
676             data.extend_from_slice(&payload);
677 
678             let slice = TcpSlice::from_slice(&data).unwrap();
679             assert_eq!(
680                 Ok(0x786e),
681                 slice.calc_checksum_ipv6(
682                     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
683                     [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,],
684                 )
685             );
686         }
687 
688         // error
689         #[cfg(target_pointer_width = "64")]
690         {
691             let slice = TcpSlice {
692                 header_len: TcpHeader::MIN_LEN,
693                 // lets create a slice of that size that points to zero
694                 // (as most systems can not allocate blocks of the size of u32::MAX)
695                 slice: unsafe {
696                     //NOTE: The pointer must be initialized with a non null value
697                     //      otherwise a key constraint of slices is not fulfilled
698                     //      which can lead to crashes in release mode.
699                     use core::ptr::NonNull;
700                     core::slice::from_raw_parts(
701                         NonNull::<u8>::dangling().as_ptr(),
702                         (core::u32::MAX as usize) + 1,
703                     )
704                 },
705             };
706 
707             // expect an length error
708             assert_eq!(
709                 slice.calc_checksum_ipv6(
710                     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
711                     [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,],
712                 ),
713                 Err(ValueTooBigError {
714                     actual: (core::u32::MAX as usize) + 1,
715                     max_allowed: core::u32::MAX as usize,
716                     value_type: ValueType::TcpPayloadLengthIpv6,
717                 })
718             );
719         }
720     }
721 }
722