Repo of no-std crates for my personal embedded projects
at main 6.0 kB view raw
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}