atmos/kernel/net/
udp_queue.rs1pub const UDP_RX_MAX_PAYLOAD: usize = 1024;
10
11#[derive(Copy, Clone)]
12pub struct UdpRxEntry {
13 pub valid: bool,
14 pub src_ip: [u8; 4],
15 pub src_port: u16,
16 pub dst_port: u16,
17 pub payload_len: usize,
18 pub payload: [u8; UDP_RX_MAX_PAYLOAD],
19 pub age: u32,
21}
22
23impl UdpRxEntry {
24 pub const fn empty() -> Self {
25 Self {
26 valid: false,
27 src_ip: [0; 4],
28 src_port: 0,
29 dst_port: 0,
30 payload_len: 0,
31 payload: [0; UDP_RX_MAX_PAYLOAD],
32 age: 0,
33 }
34 }
35
36 pub fn payload(&self) -> &[u8] {
37 &self.payload[..self.payload_len]
38 }
39}
40
41#[derive(Copy, Clone, PartialEq, Eq, Debug)]
42pub enum PushOutcome {
43 Stored,
45 Evicted,
47 Dropped,
49}
50
51pub fn push(
56 queue: &mut [UdpRxEntry],
57 src_ip: [u8; 4],
58 src_port: u16,
59 dst_port: u16,
60 payload: &[u8],
61 age: u32,
62) -> PushOutcome {
63 if queue.is_empty() {
64 return PushOutcome::Dropped;
65 }
66
67 let copy_len = payload.len().min(UDP_RX_MAX_PAYLOAD);
68 let mut entry = UdpRxEntry {
69 valid: true,
70 src_ip,
71 src_port,
72 dst_port,
73 payload_len: copy_len,
74 payload: [0; UDP_RX_MAX_PAYLOAD],
75 age,
76 };
77 entry.payload[..copy_len].copy_from_slice(&payload[..copy_len]);
78
79 for slot in queue.iter_mut() {
80 if !slot.valid {
81 *slot = entry;
82 return PushOutcome::Stored;
83 }
84 }
85
86 let mut oldest_idx = 0usize;
87 let mut oldest_age = queue[0].age;
88 for (i, e) in queue.iter().enumerate().skip(1) {
89 if e.age < oldest_age {
90 oldest_age = e.age;
91 oldest_idx = i;
92 }
93 }
94 queue[oldest_idx] = entry;
95 PushOutcome::Evicted
96}
97
98pub fn find_matching(
104 queue: &[UdpRxEntry],
105 dst_port: u16,
106 pred: impl Fn(&UdpRxEntry) -> bool,
107) -> Option<usize> {
108 let mut best: Option<(usize, u32)> = None;
109 for (i, e) in queue.iter().enumerate() {
110 if !e.valid || e.dst_port != dst_port {
111 continue;
112 }
113 if !pred(e) {
114 continue;
115 }
116 match best {
117 None => best = Some((i, e.age)),
118 Some((_, best_age)) if e.age < best_age => best = Some((i, e.age)),
119 _ => {}
120 }
121 }
122 best.map(|(i, _)| i)
123}
124
125pub fn purge_port(queue: &mut [UdpRxEntry], dst_port: u16) -> usize {
136 let mut n = 0;
137 for e in queue.iter_mut() {
138 if e.valid && e.dst_port == dst_port {
139 *e = UdpRxEntry::empty();
140 n += 1;
141 }
142 }
143 n
144}