1use crate::mac;
6
7pub fn derive_tid(ether_type: u16, payload: &[u8]) -> Option<u8> {
12    if ether_type == mac::ETHER_TYPE_IPV4 || ether_type == mac::ETHER_TYPE_IPV6 {
13        return get_ds_field(ether_type, payload).map(|ds| dscp_to_up(ds >> 2));
15    }
16    None
17}
18
19pub fn dscp_to_up(dscp: u8) -> u8 {
23    match dscp {
24        0b110000 | 0b111000 => 7,
26        0b101110 => 6,
28        0b101100 => 6,
30        0b101000 => 5,
32        0b100010 | 0b100100 | 0b100110 => 4,
34        0b100000 => 4,
36        0b011010 | 0b011100 | 0b011110 => 4,
38        0b011000 => 4,
40        0b010010 | 0b010100 | 0b010110 => 3,
42        0b001000 => 1,
44        _ => 0,
46    }
47}
48
49fn get_ds_field(ether_type: u16, payload: &[u8]) -> Option<u8> {
50    if payload.len() < 2 {
51        return None;
52    }
53    match ether_type {
54        mac::ETHER_TYPE_IPV4 => Some(payload[1]),
55        mac::ETHER_TYPE_IPV6 => Some(((payload[0] & 0x0f) << 4) | ((payload[1] & 0xf0) >> 4)),
56        _ => None,
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_derive_tid_ipv4() {
66        let tid = derive_tid(mac::ETHER_TYPE_IPV4, &[0xff, 0b10110000]);
67        assert_eq!(tid, Some(6));
68    }
69
70    #[test]
71    fn test_derive_tid_ipv6() {
72        let tid = derive_tid(mac::ETHER_TYPE_IPV6, &[0b11110101, 0b10000000]);
73        assert_eq!(tid, Some(3));
74    }
75
76    #[test]
77    fn test_derive_tid_payload_too_short() {
78        assert!(derive_tid(mac::ETHER_TYPE_IPV4, &[0xff]).is_none());
79    }
80
81    #[test]
82    fn test_dscp_to_up() {
83        assert_eq!(dscp_to_up(0b110000), 7);
84        assert_eq!(dscp_to_up(0b010000), 0);
86        assert_eq!(dscp_to_up(0b001010), 0);
87        assert_eq!(dscp_to_up(0b001100), 0);
88        assert_eq!(dscp_to_up(0b001110), 0);
89        assert_eq!(dscp_to_up(0b001110), 0);
90        assert_eq!(dscp_to_up(0b000000), 0);
91
92        assert_eq!(dscp_to_up(0b111110), 0);
94    }
95}