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
124
125
126
127
128
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! This file contains the structs and methods associated with the UDP header.
//! This includes getters and setters for the various header fields, as well
//! as the standard encode/decode functionality required for serializing
//! the struct for transmission.

use crate::net::stream::decode_u16;
use crate::net::stream::encode_u16;
use crate::net::stream::SResult;

// Note: All UDP Header fields are stored in network byte order

/// The `UDPHeader` struct follows the layout for the UDP packet header.
/// Note that the implementation of this struct provides getters and setters
/// for the various fields of the header, to avoid confusion with endian-ness.
#[derive(Copy, Clone, Debug)]
pub struct UDPHeader {
    src_port: u16,
    dst_port: u16,
    len: u16,
    cksum: u16,
}

impl Default for UDPHeader {
    fn default() -> UDPHeader {
        UDPHeader {
            src_port: 0,
            dst_port: 0,
            len: 8,
            cksum: 0,
        }
    }
}

impl UDPHeader {
    pub fn new() -> UDPHeader {
        UDPHeader::default()
    }
    // TODO: Always returns size of UDP header
    pub fn get_offset(&self) -> usize {
        8
    }

    pub fn set_dst_port(&mut self, port: u16) {
        self.dst_port = port.to_be();
    }
    pub fn set_src_port(&mut self, port: u16) {
        self.src_port = port.to_be();
    }

    pub fn set_len(&mut self, len: u16) {
        self.len = len.to_be();
    }

    pub fn set_cksum(&mut self, cksum: u16) {
        self.cksum = cksum.to_be();
    }

    pub fn get_src_port(&self) -> u16 {
        u16::from_be(self.src_port)
    }

    pub fn get_dst_port(&self) -> u16 {
        u16::from_be(self.dst_port)
    }

    pub fn get_len(&self) -> u16 {
        u16::from_be(self.len)
    }

    pub fn get_cksum(&self) -> u16 {
        u16::from_be(self.cksum)
    }

    pub fn get_hdr_size(&self) -> usize {
        // TODO
        8
    }

    /// This function serializes the `UDPHeader` into the provided buffer.
    ///
    /// # Arguments
    ///
    /// `buf` - A mutable buffer to serialize the `UDPHeader` into
    /// `offset` - The current offset into the provided buffer
    ///
    /// # Return Value
    ///
    /// This function returns the new offset into the buffer wrapped in an
    /// SResult.
    pub fn encode(&self, buf: &mut [u8], offset: usize) -> SResult<usize> {
        stream_len_cond!(buf, self.get_hdr_size() + offset);

        let mut off = offset;
        off = enc_consume!(buf, off; encode_u16, self.src_port);
        off = enc_consume!(buf, off; encode_u16, self.dst_port);
        off = enc_consume!(buf, off; encode_u16, self.len);
        off = enc_consume!(buf, off; encode_u16, self.cksum);
        stream_done!(off, off);
    }

    /// This function deserializes the `UDPHeader` from the provided buffer.
    ///
    /// # Arguments
    ///
    /// `buf` - The byte array corresponding to a serialized `UDPHeader`
    ///
    /// # Return Value
    ///
    /// This function returns a `UDPHeader` struct wrapped in an SResult
    pub fn decode(buf: &[u8]) -> SResult<UDPHeader> {
        stream_len_cond!(buf, 8);
        let mut udp_header = Self::new();
        let off = 0;
        let (off, src_port) = dec_try!(buf, off; decode_u16);
        udp_header.src_port = u16::from_be(src_port);
        let (off, dst_port) = dec_try!(buf, off; decode_u16);
        udp_header.dst_port = u16::from_be(dst_port);
        let (off, len) = dec_try!(buf, off; decode_u16);
        udp_header.len = u16::from_be(len);
        let (off, cksum) = dec_try!(buf, off; decode_u16);
        udp_header.cksum = u16::from_be(cksum);
        stream_done!(off, udp_header);
    }
}