1 #[cfg(feature = "std")] 2 use crate::err::{ipv4_exts, ipv6_exts, ValueTooBigError}; 3 4 /// Error while writing packet 5 #[cfg(feature = "std")] 6 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 7 #[derive(Debug)] 8 pub enum BuildWriteError { 9 /// IO error while writing packet. 10 Io(std::io::Error), 11 12 /// Error if the length of the payload is too 13 /// big to be representable by the length fields. 14 PayloadLen(ValueTooBigError<usize>), 15 16 /// Error if the IPv4 extensions can not be serialized 17 /// because of internal consistency errors (i.e. a header 18 /// is never). 19 Ipv4Exts(ipv4_exts::ExtsWalkError), 20 21 /// Error if the IPv6 extensions can not be serialized 22 /// because of internal consistency errors. 23 Ipv6Exts(ipv6_exts::ExtsWalkError), 24 25 /// Error if ICMPv6 is packaged in an IPv4 packet (it is undefined 26 /// how to calculate the checksum). 27 Icmpv6InIpv4, 28 29 /// address size defined in the ARP header does not match the actual size 30 ArpHeaderNotMatch, 31 } 32 33 #[cfg(feature = "std")] 34 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 35 impl BuildWriteError { 36 /// Returns the [`std::io::Error`] value if the `BuildWriteError` is an `Io`. 37 /// Otherwise `None` is returned. io(&self) -> Option<&std::io::Error>38 pub fn io(&self) -> Option<&std::io::Error> { 39 match self { 40 BuildWriteError::Io(err) => Some(err), 41 _ => None, 42 } 43 } 44 45 /// Returns the [`crate::err::ValueTooBigError`] value if the 46 /// `BuildWriteError` is a `PayloadLen`. Otherwise `None` is returned. payload_len(&self) -> Option<&ValueTooBigError<usize>>47 pub fn payload_len(&self) -> Option<&ValueTooBigError<usize>> { 48 match self { 49 BuildWriteError::PayloadLen(err) => Some(err), 50 _ => None, 51 } 52 } 53 54 /// Returns the [`crate::err::ipv4_exts::ExtsWalkError`] value if the 55 /// `BuildWriteError` is a `Ipv4Exts`. Otherwise `None` is returned. ipv4_exts(&self) -> Option<&ipv4_exts::ExtsWalkError>56 pub fn ipv4_exts(&self) -> Option<&ipv4_exts::ExtsWalkError> { 57 match self { 58 BuildWriteError::Ipv4Exts(err) => Some(err), 59 _ => None, 60 } 61 } 62 63 /// Returns the [`crate::err::ipv6_exts::ExtsWalkError`] value if the 64 /// `BuildWriteError` is a `Ipv6Exts`. Otherwise `None` is returned. ipv6_exts(&self) -> Option<&ipv6_exts::ExtsWalkError>65 pub fn ipv6_exts(&self) -> Option<&ipv6_exts::ExtsWalkError> { 66 match self { 67 BuildWriteError::Ipv6Exts(err) => Some(err), 68 _ => None, 69 } 70 } 71 72 /// Returns true if the `BuildWriteError` is a `Icmpv6InIpv4`. is_icmpv6_in_ipv4(&self) -> bool73 pub fn is_icmpv6_in_ipv4(&self) -> bool { 74 matches!(self, BuildWriteError::Icmpv6InIpv4) 75 } 76 } 77 78 #[cfg(feature = "std")] 79 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 80 impl core::fmt::Display for BuildWriteError { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result81 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 82 use BuildWriteError::*; 83 match self { 84 Io(err) => err.fmt(f), 85 PayloadLen(err) => err.fmt(f), 86 Ipv4Exts(err) => err.fmt(f), 87 Ipv6Exts(err) => err.fmt(f), 88 ArpHeaderNotMatch => write!(f, "address size defined in the ARP header does not match the actual size"), 89 Icmpv6InIpv4 => write!(f, "Error: ICMPv6 can not be combined with an IPv4 headers (checksum can not be calculated)."), 90 } 91 } 92 } 93 94 #[cfg(feature = "std")] 95 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 96 impl std::error::Error for BuildWriteError { source(&self) -> Option<&(dyn std::error::Error + 'static)>97 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 98 use BuildWriteError::*; 99 match self { 100 Io(ref err) => Some(err), 101 PayloadLen(ref err) => Some(err), 102 Ipv4Exts(err) => Some(err), 103 Ipv6Exts(err) => Some(err), 104 Icmpv6InIpv4 => None, 105 ArpHeaderNotMatch => None, 106 } 107 } 108 } 109 110 #[cfg(test)] 111 mod tests { 112 use super::{BuildWriteError::*, *}; 113 use crate::{err::ValueType, *}; 114 use alloc::format; 115 use std::error::Error; 116 117 #[test] io()118 fn io() { 119 assert!(Io(std::io::Error::new( 120 std::io::ErrorKind::UnexpectedEof, 121 "failed to fill whole buffer", 122 )) 123 .io() 124 .is_some()); 125 assert!(Ipv4Exts(ipv4_exts::ExtsWalkError::ExtNotReferenced { 126 missing_ext: IpNumber::AUTHENTICATION_HEADER, 127 }) 128 .io() 129 .is_none()); 130 } 131 132 #[test] payload_len()133 fn payload_len() { 134 { 135 let err = ValueTooBigError { 136 actual: 3, 137 max_allowed: 2, 138 value_type: ValueType::Ipv4PayloadLength, 139 }; 140 assert_eq!(Some(&err), PayloadLen(err.clone()).payload_len()); 141 } 142 { 143 let err = ipv4_exts::ExtsWalkError::ExtNotReferenced { 144 missing_ext: IpNumber::AUTHENTICATION_HEADER, 145 }; 146 assert_eq!(None, Ipv4Exts(err.clone()).payload_len()); 147 } 148 } 149 150 #[test] ipv4_exts()151 fn ipv4_exts() { 152 assert!(Io(std::io::Error::new( 153 std::io::ErrorKind::UnexpectedEof, 154 "failed to fill whole buffer", 155 )) 156 .ipv4_exts() 157 .is_none()); 158 { 159 let err = ipv4_exts::ExtsWalkError::ExtNotReferenced { 160 missing_ext: IpNumber::AUTHENTICATION_HEADER, 161 }; 162 assert_eq!(Some(&err), Ipv4Exts(err.clone()).ipv4_exts()); 163 } 164 } 165 166 #[test] ipv6_exts()167 fn ipv6_exts() { 168 assert!(Io(std::io::Error::new( 169 std::io::ErrorKind::UnexpectedEof, 170 "failed to fill whole buffer", 171 )) 172 .ipv6_exts() 173 .is_none()); 174 { 175 let err = ipv6_exts::ExtsWalkError::ExtNotReferenced { 176 missing_ext: IpNumber::AUTHENTICATION_HEADER, 177 }; 178 assert_eq!(Some(&err), Ipv6Exts(err.clone()).ipv6_exts()); 179 } 180 } 181 182 #[test] is_icmpv6_in_ipv4()183 fn is_icmpv6_in_ipv4() { 184 assert_eq!( 185 false, 186 Io(std::io::Error::new( 187 std::io::ErrorKind::UnexpectedEof, 188 "failed to fill whole buffer", 189 )) 190 .is_icmpv6_in_ipv4() 191 ); 192 assert!(Icmpv6InIpv4.is_icmpv6_in_ipv4()); 193 } 194 195 #[test] debug()196 fn debug() { 197 let err = ipv4_exts::ExtsWalkError::ExtNotReferenced { 198 missing_ext: IpNumber::AUTHENTICATION_HEADER, 199 }; 200 assert_eq!( 201 format!("Ipv4Exts({:?})", err.clone()), 202 format!("{:?}", Ipv4Exts(err)) 203 ); 204 } 205 206 #[test] fmt()207 fn fmt() { 208 { 209 let err = std::io::Error::new( 210 std::io::ErrorKind::UnexpectedEof, 211 "failed to fill whole buffer", 212 ); 213 assert_eq!(format!("{}", err), format!("{}", Io(err))); 214 } 215 { 216 let err = ValueTooBigError { 217 actual: 3, 218 max_allowed: 2, 219 value_type: ValueType::Ipv4PayloadLength, 220 }; 221 assert_eq!(format!("{}", err), format!("{}", PayloadLen(err.clone()))); 222 } 223 { 224 let err = ipv4_exts::ExtsWalkError::ExtNotReferenced { 225 missing_ext: IpNumber::AUTHENTICATION_HEADER, 226 }; 227 assert_eq!(format!("{}", err), format!("{}", Ipv4Exts(err.clone()))); 228 } 229 { 230 let err = ipv6_exts::ExtsWalkError::ExtNotReferenced { 231 missing_ext: IpNumber::AUTHENTICATION_HEADER, 232 }; 233 assert_eq!(format!("{}", err), format!("{}", Ipv6Exts(err.clone()))); 234 } 235 assert_eq!( 236 "Error: ICMPv6 can not be combined with an IPv4 headers (checksum can not be calculated).", 237 format!("{}", Icmpv6InIpv4) 238 ); 239 } 240 241 #[cfg(feature = "std")] 242 #[test] source()243 fn source() { 244 assert!(Io(std::io::Error::new( 245 std::io::ErrorKind::UnexpectedEof, 246 "failed to fill whole buffer", 247 )) 248 .source() 249 .is_some()); 250 assert!(PayloadLen(ValueTooBigError { 251 actual: 3, 252 max_allowed: 2, 253 value_type: ValueType::Ipv4PayloadLength, 254 }) 255 .source() 256 .is_some()); 257 assert!(Ipv4Exts(ipv4_exts::ExtsWalkError::ExtNotReferenced { 258 missing_ext: IpNumber::AUTHENTICATION_HEADER, 259 }) 260 .source() 261 .is_some()); 262 assert!(Ipv6Exts(ipv6_exts::ExtsWalkError::ExtNotReferenced { 263 missing_ext: IpNumber::AUTHENTICATION_HEADER, 264 }) 265 .source() 266 .is_some()); 267 assert!(Icmpv6InIpv4.source().is_none()); 268 } 269 } 270