etherparse/transport/
tcp_header_slice.rs

1use crate::{
2    err::{ValueTooBigError, ValueType},
3    *,
4};
5
6/// A slice containing an tcp header of a network package.
7#[derive(Clone, Debug, Eq, PartialEq)]
8pub struct TcpHeaderSlice<'a> {
9    pub(crate) slice: &'a [u8],
10}
11
12impl<'a> TcpHeaderSlice<'a> {
13    /// Creates a slice containing an tcp header.
14    pub fn from_slice(slice: &'a [u8]) -> Result<TcpHeaderSlice<'a>, err::tcp::HeaderSliceError> {
15        use err::tcp::{HeaderError::*, HeaderSliceError::*};
16
17        //check length
18        if slice.len() < TcpHeader::MIN_LEN {
19            return Err(Len(err::LenError {
20                required_len: TcpHeader::MIN_LEN,
21                len: slice.len(),
22                len_source: LenSource::Slice,
23                layer: err::Layer::TcpHeader,
24                layer_start_offset: 0,
25            }));
26        }
27
28        // SAFETY:
29        // Safe as it is checked at the start of the function that the
30        // length of the slice is at least TcpHeader::MIN_LEN (20).
31        let header_len = unsafe {
32            // The length of the TCP header can be determined via
33            // the data offset field of the TCP header. "data offset"
34            // stores the offset in 4 byte steps from the start of the
35            // header to the payload of the header.
36            //
37            // "data offset" is stored in the upper 4 bits
38            // (aka 0b1111_0000) of byte 12. To get to total length
39            // in bytes of the header data offset has to be multiplied
40            // by 4. So the naive version to get the length of
41            // the header would be:
42            //
43            // ```
44            // let data_offset = (*slice.get_unchecked(12) & 0xf0) >> 4;
45            // let len = data_offset * 4;
46            // ```
47            //
48            // But a multiplication by 4 can be replaced by 2
49            // left shift:
50            //
51            // ```
52            // let data_offset = (*slice.get_unchecked(12) & 0xf0) >> 4;
53            // let len = data_offset << 2;
54            // ```
55            //
56            // And finally the shifts can be combined to one:
57            //
58            // ```
59            // let len = (*slice.get_unchecked(12) & 0xf0) >> 2;
60            // ```
61            usize::from((*slice.get_unchecked(12) & 0xf0) >> 2)
62        };
63
64        if header_len < TcpHeader::MIN_LEN {
65            Err(Content(DataOffsetTooSmall {
66                data_offset: (header_len >> 2) as u8,
67            }))
68        } else if slice.len() < header_len {
69            Err(Len(err::LenError {
70                required_len: header_len,
71                len: slice.len(),
72                len_source: LenSource::Slice,
73                layer: err::Layer::TcpHeader,
74                layer_start_offset: 0,
75            }))
76        } else {
77            //done
78            Ok(TcpHeaderSlice::<'a> {
79                // SAFETY:
80                // Safe as there is a check above that the slice length
81                // is at least len.
82                slice: unsafe { core::slice::from_raw_parts(slice.as_ptr(), header_len) },
83            })
84        }
85    }
86
87    /// Returns the slice containing the tcp header
88    #[inline]
89    pub fn slice(&self) -> &'a [u8] {
90        self.slice
91    }
92
93    /// Read the source port number.
94    #[inline]
95    pub fn source_port(&self) -> u16 {
96        // SAFETY:
97        // Constructor checks that the slice has at least the length
98        // of 20.
99        unsafe { get_unchecked_be_u16(self.slice.as_ptr()) }
100    }
101
102    /// Read the destination port number.
103    #[inline]
104    pub fn destination_port(&self) -> u16 {
105        // SAFETY:
106        // Constructor checks that the slice has at least the length
107        // of 20.
108        unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(2)) }
109    }
110
111    /// Read the sequence number of the first data octet in this segment (except when SYN is present).
112    ///
113    /// If SYN is present the sequence number is the initial sequence number (ISN)
114    /// and the first data octet is ISN+1.
115    /// \[copied from RFC 793, page 16\]
116    #[inline]
117    pub fn sequence_number(&self) -> u32 {
118        // SAFETY:
119        // Constructor checks that the slice has at least the length
120        // of 20.
121        unsafe { get_unchecked_be_u32(self.slice.as_ptr().add(4)) }
122    }
123
124    /// Reads the acknowledgment number.
125    ///
126    /// If the ACK control bit is set this field contains the value of the
127    /// next sequence number the sender of the segment is expecting to
128    /// receive.
129    ///
130    /// Once a connection is established this is always sent.
131    #[inline]
132    pub fn acknowledgment_number(&self) -> u32 {
133        // SAFETY:
134        // Constructor checks that the slice has at least the length
135        // of 20.
136        unsafe { get_unchecked_be_u32(self.slice.as_ptr().add(8)) }
137    }
138
139    /// Read the number of 32 bit words in the TCP Header.
140    ///
141    /// This indicates where the data begins.  The TCP header (even one including options) is an
142    /// integral number of 32 bits long.
143    #[inline]
144    pub fn data_offset(&self) -> u8 {
145        // SAFETY:
146        // Constructor checks that the slice has at least the length
147        // of 20.
148        unsafe { (*self.slice.get_unchecked(12) & 0b1111_0000) >> 4 }
149    }
150
151    /// ECN-nonce - concealment protection (experimental: see RFC 3540)
152    #[inline]
153    pub fn ns(&self) -> bool {
154        // SAFETY:
155        // Constructor checks that the slice has at least the length
156        // of 20.
157        unsafe { 0 != (*self.slice.get_unchecked(12) & 0b0000_0001) }
158    }
159
160    /// Read the fin flag (no more data from sender).
161    #[inline]
162    pub fn fin(&self) -> bool {
163        // SAFETY:
164        // Constructor checks that the slice has at least the length
165        // of 20.
166        unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_0001) }
167    }
168
169    /// Reads the syn flag (synchronize sequence numbers).
170    #[inline]
171    pub fn syn(&self) -> bool {
172        // SAFETY:
173        // Constructor checks that the slice has at least the length
174        // of 20.
175        unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_0010) }
176    }
177
178    /// Reads the rst flag (reset the connection).
179    #[inline]
180    pub fn rst(&self) -> bool {
181        // SAFETY:
182        // Constructor checks that the slice has at least the length
183        // of 20.
184        unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_0100) }
185    }
186
187    /// Reads the psh flag (push function).
188    #[inline]
189    pub fn psh(&self) -> bool {
190        // SAFETY:
191        // Constructor checks that the slice has at least the length
192        // of 20.
193        unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_1000) }
194    }
195
196    /// Reads the ack flag (acknowledgment field significant).
197    #[inline]
198    pub fn ack(&self) -> bool {
199        // SAFETY:
200        // Constructor checks that the slice has at least the length
201        // of 20.
202        unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0001_0000) }
203    }
204
205    /// Reads the urg flag (Urgent Pointer field significant).
206    #[inline]
207    pub fn urg(&self) -> bool {
208        // SAFETY:
209        // Constructor checks that the slice has at least the length
210        // of 20.
211        unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0010_0000) }
212    }
213
214    /// Read the ECN-Echo flag (RFC 3168).
215    #[inline]
216    pub fn ece(&self) -> bool {
217        // SAFETY:
218        // Constructor checks that the slice has at least the length
219        // of 20.
220        unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0100_0000) }
221    }
222
223    /// Reads the cwr flag (Congestion Window Reduced).
224    ///
225    /// This flag is set by the sending host to indicate that it received a TCP
226    /// segment with the ECE flag set and had responded in congestion control
227    /// mechanism (added to header by RFC 3168).
228    #[inline]
229    pub fn cwr(&self) -> bool {
230        // SAFETY:
231        // Constructor checks that the slice has at least the length
232        // of 20.
233        unsafe { 0 != (*self.slice.get_unchecked(13) & 0b1000_0000) }
234    }
235
236    /// The number of data octets beginning with the one indicated in the
237    /// acknowledgment field which the sender of this segment is willing to
238    /// accept.
239    #[inline]
240    pub fn window_size(&self) -> u16 {
241        u16::from_be_bytes(
242            // SAFETY:
243            // Constructor checks that the slice has at least the length
244            // of 20.
245            unsafe { [*self.slice.get_unchecked(14), *self.slice.get_unchecked(15)] },
246        )
247    }
248
249    /// Checksum (16 bit one's complement) of the pseudo ip header, this tcp header and the payload.
250    #[inline]
251    pub fn checksum(&self) -> u16 {
252        u16::from_be_bytes(
253            // SAFETY:
254            // Constructor checks that the slice has at least the length
255            // of 20.
256            unsafe { [*self.slice.get_unchecked(16), *self.slice.get_unchecked(17)] },
257        )
258    }
259
260    /// This field communicates the current value of the urgent pointer as a
261    /// positive offset from the sequence number in this segment.
262    ///
263    /// The urgent pointer points to the sequence number of the octet following
264    /// the urgent data.  This field is only be interpreted in segments with
265    /// the URG control bit set.
266    #[inline]
267    pub fn urgent_pointer(&self) -> u16 {
268        u16::from_be_bytes(
269            // SAFETY:
270            // Constructor checks that the slice has at least the length
271            // of 20.
272            unsafe { [*self.slice.get_unchecked(18), *self.slice.get_unchecked(19)] },
273        )
274    }
275
276    /// Options of the header
277    #[inline]
278    pub fn options(&self) -> &[u8] {
279        &self.slice[TcpHeader::MIN_LEN..self.data_offset() as usize * 4]
280    }
281
282    /// Returns an iterator that allows to iterate through all known TCP header options.
283    #[inline]
284    pub fn options_iterator(&self) -> TcpOptionsIterator {
285        TcpOptionsIterator::from_slice(self.options())
286    }
287
288    /// Decode all the fields and copy the results to a TcpHeader struct
289    pub fn to_header(&self) -> TcpHeader {
290        TcpHeader {
291            source_port: self.source_port(),
292            destination_port: self.destination_port(),
293            sequence_number: self.sequence_number(),
294            acknowledgment_number: self.acknowledgment_number(),
295            ns: self.ns(),
296            fin: self.fin(),
297            syn: self.syn(),
298            rst: self.rst(),
299            psh: self.psh(),
300            ack: self.ack(),
301            ece: self.ece(),
302            urg: self.urg(),
303            cwr: self.cwr(),
304            window_size: self.window_size(),
305            checksum: self.checksum(),
306            urgent_pointer: self.urgent_pointer(),
307            options: {
308                let options_slice = self.options();
309                let mut options = TcpOptions {
310                    len: options_slice.len() as u8,
311                    buf: [0; 40],
312                };
313                options.buf[..options_slice.len()].clone_from_slice(options_slice);
314                options
315            },
316        }
317    }
318
319    /// Calculates the TCP header checksum based on a ipv4 header and returns the result. This does NOT set the checksum.
320    pub fn calc_checksum_ipv4(
321        &self,
322        ip_header: &Ipv4HeaderSlice,
323        payload: &[u8],
324    ) -> Result<u16, ValueTooBigError<usize>> {
325        self.calc_checksum_ipv4_raw(ip_header.source(), ip_header.destination(), payload)
326    }
327
328    /// Calculates the checksum for the current header in ipv4 mode and returns the result. This does NOT set the checksum.
329    pub fn calc_checksum_ipv4_raw(
330        &self,
331        source_ip: [u8; 4],
332        destination_ip: [u8; 4],
333        payload: &[u8],
334    ) -> Result<u16, ValueTooBigError<usize>> {
335        // check that the total length fits into the field
336        let header_len = self.slice.len() as u16;
337        let max_payload = usize::from(u16::MAX) - usize::from(header_len);
338        if max_payload < payload.len() {
339            return Err(ValueTooBigError {
340                actual: payload.len(),
341                max_allowed: max_payload,
342                value_type: ValueType::TcpPayloadLengthIpv4,
343            });
344        }
345
346        // calculate the checksum
347        let tcp_len = header_len + (payload.len() as u16);
348        Ok(self.calc_checksum_post_ip(
349            checksum::Sum16BitWords::new()
350                .add_4bytes(source_ip)
351                .add_4bytes(destination_ip)
352                .add_2bytes([0, ip_number::TCP.0])
353                .add_2bytes((tcp_len).to_be_bytes()),
354            payload,
355        ))
356    }
357
358    /// Calculates the TCP header checksum based on a ipv6 header and returns the result. This does NOT set the checksum..
359    pub fn calc_checksum_ipv6(
360        &self,
361        ip_header: &Ipv6HeaderSlice,
362        payload: &[u8],
363    ) -> Result<u16, ValueTooBigError<usize>> {
364        self.calc_checksum_ipv6_raw(ip_header.source(), ip_header.destination(), payload)
365    }
366
367    /// Calculates the checksum for the current header in ipv6 mode and returns the result. This does NOT set the checksum.
368    pub fn calc_checksum_ipv6_raw(
369        &self,
370        source: [u8; 16],
371        destination: [u8; 16],
372        payload: &[u8],
373    ) -> Result<u16, ValueTooBigError<usize>> {
374        // check that the total length fits into the field
375        let header_len = self.slice.len() as u32;
376        let max_payload = (u32::MAX as usize) - (header_len as usize);
377        if max_payload < payload.len() {
378            return Err(ValueTooBigError {
379                actual: payload.len(),
380                max_allowed: max_payload,
381                value_type: ValueType::TcpPayloadLengthIpv6,
382            });
383        }
384
385        // calculate the checksum
386        let tcp_len = header_len + (payload.len() as u32);
387        Ok(self.calc_checksum_post_ip(
388            checksum::Sum16BitWords::new()
389                .add_16bytes(source)
390                .add_16bytes(destination)
391                .add_2bytes([0, ip_number::TCP.0])
392                .add_4bytes((tcp_len).to_be_bytes()),
393            payload,
394        ))
395    }
396
397    /// This method takes the sum of the pseudo ip header and calculates the rest of the checksum.
398    fn calc_checksum_post_ip(
399        &self,
400        ip_pseudo_header_sum: checksum::Sum16BitWords,
401        payload: &[u8],
402    ) -> u16 {
403        ip_pseudo_header_sum
404            .add_slice(&self.slice[..16]) //until checksum
405            .add_slice(&self.slice[18..self.slice.len()])
406            .add_slice(payload)
407            .ones_complement()
408            .to_be()
409    }
410}
411
412#[cfg(test)]
413mod test {
414    use crate::{
415        err::{
416            tcp::{HeaderError::*, HeaderSliceError::*},
417            ValueTooBigError, ValueType,
418        },
419        test_gens::*,
420        TcpOptionElement::*,
421        *,
422    };
423    use alloc::{format, vec::Vec};
424    use proptest::prelude::*;
425
426    proptest! {
427        #[test]
428        fn debug(header in tcp_any()) {
429            let buffer = header.to_bytes();
430            let slice = TcpHeaderSlice::from_slice(&buffer).unwrap();
431            assert_eq!(
432                format!("{:?}", slice),
433                format!("TcpHeaderSlice {{ slice: {:?} }}", slice.slice())
434            );
435        }
436    }
437
438    proptest! {
439        #[test]
440        fn clone_eq(header in tcp_any()) {
441            let bytes = header.to_bytes();
442            let slice = TcpHeaderSlice::from_slice(&bytes).unwrap();
443            assert_eq!(slice.clone(), slice);
444        }
445    }
446
447    proptest! {
448        #[test]
449        fn from_slice(header in tcp_any()) {
450            // ok case
451            {
452                let bytes = {
453                    let mut bytes = header.to_bytes();
454                    bytes.try_extend_from_slice(
455                        &([0u8;TcpHeader::MAX_LEN])[..bytes.remaining_capacity()]
456                    ).unwrap();
457                    bytes
458                };
459
460                let slice = TcpHeaderSlice::from_slice(&bytes[..]).unwrap();
461                assert_eq!(slice.slice(), &bytes[..header.header_len() as usize]);
462                assert_eq!(slice.to_header(), header);
463            }
464
465            // data offset error
466            for data_offset in 0..TcpHeader::MIN_DATA_OFFSET {
467                let bytes = {
468                    let mut bytes = header.to_bytes();
469                    bytes[12] = (bytes[12] & 0xf) | ((data_offset << 4) & 0xf0);
470                    bytes
471                };
472                assert_eq!(
473                    TcpHeaderSlice::from_slice(&bytes[..]),
474                    Err(Content(DataOffsetTooSmall{ data_offset }))
475                );
476            }
477
478            // length error
479            {
480                let bytes = header.to_bytes();
481                for len in 0..(header.header_len() as usize) {
482                    assert_eq!(
483                        TcpHeaderSlice::from_slice(&bytes[..len])
484                            .unwrap_err(),
485                        Len(err::LenError {
486                            required_len: if len < TcpHeader::MIN_LEN {
487                                TcpHeader::MIN_LEN
488                            } else {
489                                header.header_len() as usize
490                            },
491                            len: len,
492                            len_source: LenSource::Slice,
493                            layer: err::Layer::TcpHeader,
494                            layer_start_offset: 0,
495                        })
496                    );
497                }
498            }
499        }
500    }
501
502    proptest! {
503        #[test]
504        fn getters(header in tcp_any()) {
505            let bytes = header.to_bytes();
506            let slice = TcpHeaderSlice::from_slice(&bytes).unwrap();
507
508            assert_eq!(header.source_port, slice.source_port());
509            assert_eq!(header.destination_port, slice.destination_port());
510            assert_eq!(header.sequence_number, slice.sequence_number());
511            assert_eq!(header.acknowledgment_number, slice.acknowledgment_number());
512            assert_eq!(header.data_offset(), slice.data_offset());
513            assert_eq!(header.ns, slice.ns());
514            assert_eq!(header.fin, slice.fin());
515            assert_eq!(header.syn, slice.syn());
516            assert_eq!(header.rst, slice.rst());
517            assert_eq!(header.psh, slice.psh());
518            assert_eq!(header.ack, slice.ack());
519            assert_eq!(header.urg, slice.urg());
520            assert_eq!(header.ece, slice.ece());
521            assert_eq!(header.cwr, slice.cwr());
522            assert_eq!(header.window_size, slice.window_size());
523            assert_eq!(header.checksum, slice.checksum());
524            assert_eq!(header.urgent_pointer, slice.urgent_pointer());
525            assert_eq!(header.options.as_slice(), slice.options());
526        }
527    }
528
529    proptest! {
530        #[test]
531        fn options_iterator(header in tcp_any()) {
532            let bytes = header.to_bytes();
533            let slice = TcpHeaderSlice::from_slice(&bytes).unwrap();
534            assert_eq!(
535                TcpOptionsIterator::from_slice(header.options.as_slice()),
536                slice.options_iterator()
537            );
538        }
539    }
540
541    proptest! {
542        #[test]
543        fn to_header(header in tcp_any()) {
544            let bytes = header.to_bytes();
545            let slice = TcpHeaderSlice::from_slice(&bytes).unwrap();
546            assert_eq!(header, slice.to_header());
547        }
548    }
549
550    #[test]
551    fn calc_checksum_ipv4() {
552        // checksum == 0xf (no carries) (aka sum == 0xffff)
553        {
554            let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8];
555
556            // setup headers
557            let tcp = TcpHeader::new(0, 0, 40905, 0);
558            let ip_header = Ipv4Header::new(
559                //payload length
560                tcp.header_len_u16() + (tcp_payload.len() as u16),
561                //time to live
562                0,
563                ip_number::TCP,
564                //source ip address
565                [0; 4],
566                //destination ip address
567                [0; 4],
568            )
569            .unwrap();
570
571            // setup slices
572            let ip_bytes = ip_header.to_bytes();
573            let ip_slice = Ipv4HeaderSlice::from_slice(&ip_bytes).unwrap();
574
575            let tcp_bytes = tcp.to_bytes();
576            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_bytes).unwrap();
577
578            assert_eq!(
579                Ok(0x0),
580                tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload)
581            );
582        }
583
584        //a header with options
585        {
586            let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8];
587
588            let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653);
589            tcp.urgent_pointer = 0xE26E;
590            tcp.ns = true;
591            tcp.fin = true;
592            tcp.syn = true;
593            tcp.rst = true;
594            tcp.psh = true;
595            tcp.ack = true;
596            tcp.ece = true;
597            tcp.urg = true;
598            tcp.cwr = true;
599
600            tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)])
601                .unwrap();
602
603            let ip_header = Ipv4Header::new(
604                //payload length
605                tcp.header_len_u16() + (tcp_payload.len() as u16),
606                //time to live
607                20,
608                ip_number::TCP,
609                //source ip address
610                [192, 168, 1, 42],
611                //destination ip address
612                [192, 168, 1, 1],
613            )
614            .unwrap();
615
616            // setup slices
617            let ip_buffer = ip_header.to_bytes();
618            let ip_slice = Ipv4HeaderSlice::from_slice(&ip_buffer).unwrap();
619
620            let tcp_buffer = tcp.to_bytes();
621            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer).unwrap();
622
623            assert_eq!(
624                Ok(0xdeeb),
625                tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload)
626            );
627        }
628
629        //a header with an uneven number of options
630        {
631            let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8, 9];
632
633            let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653);
634            tcp.urgent_pointer = 0xE26E;
635            tcp.ns = true;
636            tcp.fin = true;
637            tcp.syn = true;
638            tcp.rst = true;
639            tcp.psh = true;
640            tcp.ack = true;
641            tcp.ece = true;
642            tcp.urg = true;
643            tcp.cwr = true;
644
645            tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)])
646                .unwrap();
647
648            let ip_header = Ipv4Header::new(
649                //payload length
650                tcp.header_len_u16() + (tcp_payload.len() as u16),
651                //time to live
652                20,
653                ip_number::TCP,
654                //source ip address
655                [192, 168, 1, 42],
656                //destination ip address
657                [192, 168, 1, 1],
658            )
659            .unwrap();
660
661            // setup slices
662            let ip_buffer = ip_header.to_bytes();
663            let ip_slice = Ipv4HeaderSlice::from_slice(&ip_buffer[..]).unwrap();
664
665            let tcp_buffer = tcp.to_bytes();
666            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap();
667
668            assert_eq!(
669                Ok(0xd5ea),
670                tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload)
671            );
672        }
673
674        // value error
675        {
676            // write the tcp header
677            let tcp: TcpHeader = Default::default();
678            let len = (core::u16::MAX - tcp.header_len_u16()) as usize + 1;
679            let mut tcp_payload = Vec::with_capacity(len);
680            tcp_payload.resize(len, 0);
681            let ip_header = Ipv4Header::new(0, 0, ip_number::TCP, [0; 4], [0; 4]).unwrap();
682
683            // setup slices
684            let ip_buffer = ip_header.to_bytes();
685            let ip_slice = Ipv4HeaderSlice::from_slice(&ip_buffer).unwrap();
686
687            let tcp_buffer = tcp.to_bytes();
688            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer).unwrap();
689
690            assert_eq!(
691                tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload),
692                Err(ValueTooBigError {
693                    actual: len,
694                    max_allowed: usize::from(core::u16::MAX - tcp.header_len_u16()),
695                    value_type: ValueType::TcpPayloadLengthIpv4,
696                })
697            );
698        }
699    }
700
701    #[test]
702    fn calc_checksum_ipv4_raw() {
703        // checksum == 0xf (no carries) (aka sum == 0xffff)
704        {
705            let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8];
706
707            // setup headers
708            let tcp = TcpHeader::new(0, 0, 40905, 0);
709
710            // setup slices
711            let tcp_bytes = tcp.to_bytes();
712            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_bytes).unwrap();
713
714            assert_eq!(
715                Ok(0x0),
716                tcp_slice.calc_checksum_ipv4_raw([0; 4], [0; 4], &tcp_payload)
717            );
718        }
719
720        //a header with options
721        {
722            let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8];
723
724            let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653);
725            tcp.urgent_pointer = 0xE26E;
726            tcp.ns = true;
727            tcp.fin = true;
728            tcp.syn = true;
729            tcp.rst = true;
730            tcp.psh = true;
731            tcp.ack = true;
732            tcp.ece = true;
733            tcp.urg = true;
734            tcp.cwr = true;
735
736            tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)])
737                .unwrap();
738
739            // setup slices
740            let tcp_buffer = tcp.to_bytes();
741            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer).unwrap();
742
743            assert_eq!(
744                Ok(0xdeeb),
745                tcp_slice.calc_checksum_ipv4_raw([192, 168, 1, 42], [192, 168, 1, 1], &tcp_payload)
746            );
747        }
748
749        //a header with an uneven number of options
750        {
751            let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8, 9];
752
753            let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653);
754            tcp.urgent_pointer = 0xE26E;
755            tcp.ns = true;
756            tcp.fin = true;
757            tcp.syn = true;
758            tcp.rst = true;
759            tcp.psh = true;
760            tcp.ack = true;
761            tcp.ece = true;
762            tcp.urg = true;
763            tcp.cwr = true;
764
765            tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)])
766                .unwrap();
767
768            // setup slices
769            let tcp_buffer = tcp.to_bytes();
770            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap();
771
772            assert_eq!(
773                Ok(0xd5ea),
774                tcp_slice.calc_checksum_ipv4_raw([192, 168, 1, 42], [192, 168, 1, 1], &tcp_payload)
775            );
776        }
777
778        // value error
779        {
780            // write the tcp header
781            let tcp: TcpHeader = Default::default();
782            let len = (core::u16::MAX - tcp.header_len_u16()) as usize + 1;
783            let mut tcp_payload = Vec::with_capacity(len);
784            tcp_payload.resize(len, 0);
785
786            // setup slices
787            let tcp_buffer = tcp.to_bytes();
788            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer).unwrap();
789
790            assert_eq!(
791                tcp_slice.calc_checksum_ipv4_raw([0; 4], [0; 4], &tcp_payload),
792                Err(ValueTooBigError {
793                    actual: len,
794                    max_allowed: usize::from(core::u16::MAX - tcp.header_len_u16()),
795                    value_type: ValueType::TcpPayloadLengthIpv4,
796                })
797            );
798        }
799    }
800
801    #[test]
802    fn calc_checksum_ipv6() {
803        // ok case
804        {
805            let tcp_payload = [51, 52, 53, 54, 55, 56, 57, 58];
806
807            // setup tcp header
808            let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653);
809            tcp.urgent_pointer = 0xE26E;
810
811            tcp.ns = true;
812            tcp.fin = true;
813            tcp.syn = true;
814            tcp.rst = true;
815            tcp.psh = true;
816            tcp.ack = true;
817            tcp.ece = true;
818            tcp.urg = true;
819            tcp.cwr = true;
820
821            use crate::TcpOptionElement::*;
822            tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)])
823                .unwrap();
824
825            // setup ip header
826            let ip_header = Ipv6Header {
827                traffic_class: 1,
828                flow_label: 0x81806.try_into().unwrap(),
829                payload_length: tcp_payload.len() as u16 + tcp.header_len_u16(),
830                next_header: ip_number::TCP,
831                hop_limit: 40,
832                source: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
833                destination: [
834                    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
835                ],
836            };
837
838            // setup slices
839            let ip_buffer = ip_header.to_bytes();
840            let ip_slice = Ipv6HeaderSlice::from_slice(&ip_buffer[..]).unwrap();
841
842            let tcp_bytes = tcp.to_bytes();
843            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_bytes).unwrap();
844
845            // verify checksum
846            assert_eq!(
847                Ok(0x786e),
848                tcp_slice.calc_checksum_ipv6(&ip_slice, &tcp_payload)
849            );
850        }
851
852        // error
853        #[cfg(target_pointer_width = "64")]
854        {
855            //write the udp header
856            let tcp: TcpHeader = Default::default();
857            let len = (core::u32::MAX - tcp.header_len() as u32) as usize + 1;
858
859            //lets create a slice of that size that points to zero
860            //(as most systems can not allocate blocks of the size of u32::MAX)
861            let tcp_payload = unsafe {
862                //NOTE: The pointer must be initialized with a non null value
863                //      otherwise a key constraint of slices is not fulfilled
864                //      which can lead to crashes in release mode.
865                use core::ptr::NonNull;
866                core::slice::from_raw_parts(NonNull::<u8>::dangling().as_ptr(), len)
867            };
868            let ip_header = Ipv6Header {
869                traffic_class: 1,
870                flow_label: 0x81806.try_into().unwrap(),
871                payload_length: 0, //lets assume jumbograms behavior (set to 0, as bigger then u16)
872                next_header: ip_number::TCP,
873                hop_limit: 40,
874                source: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
875                destination: [
876                    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
877                ],
878            };
879
880            // setup slices
881            let mut ip_buffer = Vec::new();
882            ip_header.write(&mut ip_buffer).unwrap();
883            let ip_slice = Ipv6HeaderSlice::from_slice(&ip_buffer[..]).unwrap();
884
885            let mut tcp_buffer = Vec::new();
886            tcp.write(&mut tcp_buffer).unwrap();
887            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap();
888
889            // check for an error during checksum calc
890            assert_eq!(
891                tcp_slice.calc_checksum_ipv6(&ip_slice, &tcp_payload),
892                Err(ValueTooBigError {
893                    actual: len,
894                    max_allowed: core::u32::MAX as usize - tcp.header_len() as usize,
895                    value_type: ValueType::TcpPayloadLengthIpv6,
896                })
897            );
898        }
899    }
900
901    #[test]
902    fn calc_checksum_ipv6_raw() {
903        // ok case
904        {
905            let tcp_payload = [51, 52, 53, 54, 55, 56, 57, 58];
906
907            //write the tcp header
908            let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653);
909            tcp.urgent_pointer = 0xE26E;
910
911            tcp.ns = true;
912            tcp.fin = true;
913            tcp.syn = true;
914            tcp.rst = true;
915            tcp.psh = true;
916            tcp.ack = true;
917            tcp.ece = true;
918            tcp.urg = true;
919            tcp.cwr = true;
920
921            use crate::TcpOptionElement::*;
922            tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)])
923                .unwrap();
924
925            // setup slice
926            let tcp_buffer = tcp.to_bytes();
927            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap();
928
929            // verify checksum
930            assert_eq!(
931                Ok(0x786e),
932                tcp_slice.calc_checksum_ipv6_raw(
933                    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
934                    [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,],
935                    &tcp_payload
936                )
937            );
938        }
939
940        // error
941        #[cfg(target_pointer_width = "64")]
942        {
943            //write the udp header
944            let tcp: TcpHeader = Default::default();
945            let len = (core::u32::MAX - tcp.header_len() as u32) as usize + 1;
946
947            //lets create a slice of that size that points to zero
948            //(as most systems can not allocate blocks of the size of u32::MAX)
949            let tcp_payload = unsafe {
950                //NOTE: The pointer must be initialized with a non null value
951                //      otherwise a key constraint of slices is not fulfilled
952                //      which can lead to crashes in release mode.
953                use core::ptr::NonNull;
954                core::slice::from_raw_parts(NonNull::<u8>::dangling().as_ptr(), len)
955            };
956
957            // setup slice
958            let tcp_buffer = tcp.to_bytes();
959            let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer).unwrap();
960
961            // expect an length error
962            assert_eq!(
963                tcp_slice.calc_checksum_ipv6_raw(
964                    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
965                    [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,],
966                    &tcp_payload
967                ),
968                Err(ValueTooBigError {
969                    actual: len,
970                    max_allowed: core::u32::MAX as usize - tcp.header_len() as usize,
971                    value_type: ValueType::TcpPayloadLengthIpv6,
972                })
973            );
974        }
975    }
976}