wlan_common/
wmm.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::mac;
6
7/// Given an ethernet payload, extract DS field and map it to User Priority if it's an IP packet.
8/// Otherwise, return None.
9/// Note that this function does not check that the payload is a valid IP packet. It only requires
10/// that the payload is long enough to contain the DS field.
11pub 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        // DSCP is the 6 most significant bits of the DS field
14        return get_ds_field(ether_type, payload).map(|ds| dscp_to_up(ds >> 2));
15    }
16    None
17}
18
19/// Given the 6-bit DSCP from IPv4 or IPv6 header, convert it to User Priority
20/// This follows RFC 8325 - https://tools.ietf.org/html/rfc8325#section-4.3
21/// For list of DSCP, see https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml
22pub fn dscp_to_up(dscp: u8) -> u8 {
23    match dscp {
24        // Network Control - CS6, CS7
25        0b110000 | 0b111000 => 7,
26        // Telephony - EF
27        0b101110 => 6,
28        // VOICE-ADMIT - VA
29        0b101100 => 6,
30        // Signaling - CS5
31        0b101000 => 5,
32        // Multimedia Conferencing - AF41, AF42, AF43
33        0b100010 | 0b100100 | 0b100110 => 4,
34        // Real-Time Interactive - CS4
35        0b100000 => 4,
36        // Multimedia Streaming - AF31, AF32, AF33
37        0b011010 | 0b011100 | 0b011110 => 4,
38        // Broadcast Video - CS3
39        0b011000 => 4,
40        // Low-Latency Data - AF21, AF22, AF23
41        0b010010 | 0b010100 | 0b010110 => 3,
42        // Low-Priority Data - CS1
43        0b001000 => 1,
44        // OAM, High-Throughput Data, Standard, and unused code points
45        _ => 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        // [OAM] CS2; [High-Throughput Data] AF11, AF12, AF13; [Standard] DF (i.e. CS0)
85        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        // Unused code point
93        assert_eq!(dscp_to_up(0b111110), 0);
94    }
95}