Repo of no-std crates for my personal embedded projects
1#![allow(dead_code)]
2
3use core::{convert::Infallible, fmt};
4use winnow::{ModalResult, Parser, binary::be_u16};
5
6use crate::{
7 dns::traits::{DnsParse, DnsSerialize},
8 encoder::Encoder,
9};
10
11#[derive(Default, Clone, Copy, PartialEq, Eq)]
12pub struct Flags(pub u16);
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[repr(u8)]
16pub enum Opcode {
17 Query = 0,
18 IQuery = 1,
19 Status = 2,
20 Reserved = 3,
21 Notify = 4,
22 Update = 5,
23 // Other values are reserved
24}
25
26impl Opcode {
27 const fn cast(value: u8) -> Self {
28 match value {
29 0 => Opcode::Query,
30 1 => Opcode::IQuery,
31 2 => Opcode::Status,
32 4 => Opcode::Notify,
33 5 => Opcode::Update,
34 _ => Opcode::Reserved,
35 }
36 }
37}
38
39impl From<u8> for Opcode {
40 fn from(value: u8) -> Self {
41 Self::cast(value)
42 }
43}
44
45impl From<Opcode> for u8 {
46 fn from(opcode: Opcode) -> Self {
47 opcode as u8
48 }
49}
50
51impl Flags {
52 const fn new() -> Self {
53 Flags(0)
54 }
55
56 pub const fn standard_request() -> Self {
57 let mut flags = Flags::new();
58 flags.set_query(true);
59 flags.set_opcode(Opcode::Query);
60 flags.set_recursion_desired(true);
61 flags
62 }
63
64 pub const fn standard_response() -> Self {
65 let mut flags = Flags::new();
66 flags.set_query(false);
67 flags.set_opcode(Opcode::Query);
68 flags.set_authoritative(true);
69 flags.set_recursion_available(false);
70 flags
71 }
72
73 // QR: Query/Response Flag
74 pub const fn is_query(&self) -> bool {
75 (self.0 & 0x8000) == 0
76 }
77
78 pub const fn set_query(&mut self, is_query: bool) {
79 if is_query {
80 self.0 &= !0x8000;
81 } else {
82 self.0 |= 0x8000;
83 }
84 }
85
86 // Opcode (bits 1-4)
87 pub const fn get_opcode(&self) -> Opcode {
88 Opcode::cast(((self.0 >> 11) & 0x0F) as u8)
89 }
90
91 pub const fn set_opcode(&mut self, opcode: Opcode) {
92 self.0 = (self.0 & !0x7800) | (((opcode as u8) as u16 & 0x0F) << 11);
93 }
94
95 // AA: Authoritative Answer
96 pub const fn is_authoritative(&self) -> bool {
97 (self.0 & 0x0400) != 0
98 }
99
100 pub const fn set_authoritative(&mut self, authoritative: bool) {
101 if authoritative {
102 self.0 |= 0x0400;
103 } else {
104 self.0 &= !0x0400;
105 }
106 }
107
108 // TC: Truncated
109 pub const fn is_truncated(&self) -> bool {
110 (self.0 & 0x0200) != 0
111 }
112
113 pub const fn set_truncated(&mut self, truncated: bool) {
114 if truncated {
115 self.0 |= 0x0200;
116 } else {
117 self.0 &= !0x0200;
118 }
119 }
120
121 // RD: Recursion Desired
122 pub const fn is_recursion_desired(&self) -> bool {
123 (self.0 & 0x0100) != 0
124 }
125
126 pub const fn set_recursion_desired(&mut self, recursion_desired: bool) {
127 if recursion_desired {
128 self.0 |= 0x0100;
129 } else {
130 self.0 &= !0x0100;
131 }
132 }
133
134 // RA: Recursion Available
135 pub const fn is_recursion_available(&self) -> bool {
136 (self.0 & 0x0080) != 0
137 }
138
139 pub const fn set_recursion_available(&mut self, recursion_available: bool) {
140 if recursion_available {
141 self.0 |= 0x0080;
142 } else {
143 self.0 &= !0x0080;
144 }
145 }
146
147 // Z: Reserved for future use (bits 9-11)
148 pub const fn get_reserved(&self) -> u8 {
149 ((self.0 >> 4) & 0x07) as u8
150 }
151
152 pub const fn set_reserved(&mut self, reserved: u8) {
153 self.0 = (self.0 & !0x0070) | ((reserved as u16 & 0x07) << 4);
154 }
155
156 // RCODE: Response Code (bits 12-15)
157 pub const fn get_rcode(&self) -> u8 {
158 (self.0 & 0x000F) as u8
159 }
160
161 pub const fn set_rcode(&mut self, rcode: u8) {
162 self.0 = (self.0 & !0x000F) | (rcode as u16 & 0x0F);
163 }
164}
165
166impl<'a> DnsParse<'a> for Flags {
167 fn parse(input: &mut &'a [u8], _context: &'a [u8]) -> ModalResult<Self> {
168 be_u16.map(Flags).parse_next(input)
169 }
170}
171
172impl<'a> DnsSerialize<'a> for Flags {
173 type Error = Infallible;
174
175 fn serialize<'b>(&self, encoder: &mut Encoder<'a, 'b>) -> Result<(), Self::Error> {
176 encoder.write(&self.0.to_be_bytes());
177 Ok(())
178 }
179
180 fn size(&self) -> usize {
181 core::mem::size_of::<u16>()
182 }
183}
184
185impl fmt::Debug for Flags {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 f.debug_struct("Flags")
188 .field("query", &self.is_query())
189 .field("opcode", &self.get_opcode())
190 .field("authoritative", &self.is_authoritative())
191 .field("truncated", &self.is_truncated())
192 .field("recursion_desired", &self.is_recursion_desired())
193 .field("recursion_available", &self.is_recursion_available())
194 .field("reserved", &self.get_reserved())
195 .field("rcode", &self.get_rcode())
196 .finish()
197 }
198}
199
200#[cfg(feature = "defmt")]
201impl defmt::Format for Flags {
202 fn format(&self, fmt: defmt::Formatter) {
203 defmt::write!(
204 fmt,
205 "Flags {{ query: {}, opcode: {:?}, authoritative: {}, truncated: {}, recursion_desired: {}, recursion_available: {}, reserved: {}, rcode: {} }}",
206 self.is_query(),
207 self.get_opcode(),
208 self.is_authoritative(),
209 self.is_truncated(),
210 self.is_recursion_desired(),
211 self.is_recursion_available(),
212 self.get_reserved(),
213 self.get_rcode()
214 );
215 }
216}
217
218#[cfg(feature = "defmt")]
219impl defmt::Format for Opcode {
220 fn format(&self, fmt: defmt::Formatter) {
221 let opcode_str = match self {
222 Opcode::Query => "Query",
223 Opcode::IQuery => "IQuery",
224 Opcode::Status => "Status",
225 Opcode::Reserved => "Reserved",
226 Opcode::Notify => "Notify",
227 Opcode::Update => "Update",
228 };
229 defmt::write!(fmt, "Opcode({=str})", opcode_str);
230 }
231}