1use bytes::{BufMut, Bytes, BytesMut};
2use thiserror::Error;
3
4use crate::notification::NotificationCode;
5
6#[derive(Error, Debug, Clone, PartialEq, Eq)]
8pub enum DecodeError {
9 #[error("incomplete message: need {needed} bytes, have {available}")]
11 Incomplete {
12 needed: usize,
14 available: usize,
16 },
17
18 #[error("invalid header marker")]
20 InvalidMarker,
21
22 #[error("invalid message length {length} (must be 19..=4096)")]
24 InvalidLength {
25 length: u16,
27 },
28
29 #[error("unknown message type {0}")]
31 UnknownMessageType(
32 u8,
34 ),
35
36 #[error("unsupported BGP version {version} (expected 4)")]
38 UnsupportedVersion {
39 version: u8,
41 },
42
43 #[error("invalid keepalive length {length} (expected 19)")]
45 InvalidKeepaliveLength {
46 length: u16,
48 },
49
50 #[error("{message_type}: {detail}")]
52 MalformedField {
53 message_type: &'static str,
55 detail: String,
57 },
58
59 #[error("malformed optional parameter at offset {offset}: {detail}")]
61 MalformedOptionalParameter {
62 offset: usize,
64 detail: String,
66 },
67
68 #[error("UPDATE length mismatch: {detail}")]
70 UpdateLengthMismatch {
71 detail: String,
73 },
74
75 #[error("UPDATE attribute error (subcode {subcode}): {detail}")]
77 UpdateAttributeError {
78 subcode: u8,
80 data: Vec<u8>,
82 detail: String,
84 },
85
86 #[error("UPDATE invalid network field: {detail}")]
88 InvalidNetworkField {
89 detail: String,
91 data: Vec<u8>,
93 },
94}
95
96#[derive(Error, Debug, Clone, PartialEq, Eq)]
98pub enum EncodeError {
99 #[error("message exceeds maximum size: {size} bytes (max 4096)")]
101 MessageTooLong {
102 size: usize,
104 },
105
106 #[error("{field}: value {value} out of range")]
108 ValueOutOfRange {
109 field: &'static str,
111 value: String,
113 },
114}
115
116impl DecodeError {
117 #[must_use]
120 pub fn to_notification(&self) -> (NotificationCode, u8, Bytes) {
121 match self {
122 Self::InvalidMarker => (
123 NotificationCode::MessageHeader,
124 1, Bytes::new(),
126 ),
127 Self::InvalidLength { length } => {
128 let mut data = BytesMut::with_capacity(2);
129 data.put_u16(*length);
130 (
131 NotificationCode::MessageHeader,
132 2, data.freeze(),
134 )
135 }
136 Self::UnknownMessageType(t) => (
137 NotificationCode::MessageHeader,
138 3, Bytes::copy_from_slice(&[*t]),
140 ),
141 Self::UnsupportedVersion { .. } => {
142 let mut data = BytesMut::with_capacity(2);
143 data.put_u16(4); (
145 NotificationCode::OpenMessage,
146 1, data.freeze(),
148 )
149 }
150 Self::InvalidKeepaliveLength { .. } | Self::Incomplete { .. } => (
151 NotificationCode::MessageHeader,
152 2, Bytes::new(),
154 ),
155 Self::MalformedField { message_type, .. } if *message_type == "UPDATE" => (
156 NotificationCode::UpdateMessage,
157 1, Bytes::new(),
159 ),
160 Self::MalformedField { .. } | Self::MalformedOptionalParameter { .. } => {
161 (NotificationCode::OpenMessage, 0, Bytes::new())
162 }
163 Self::UpdateLengthMismatch { .. } => (
164 NotificationCode::UpdateMessage,
165 1, Bytes::new(),
167 ),
168 Self::UpdateAttributeError { subcode, data, .. } => (
169 NotificationCode::UpdateMessage,
170 *subcode,
171 Bytes::from(data.clone()),
172 ),
173 Self::InvalidNetworkField { data, .. } => (
174 NotificationCode::UpdateMessage,
175 10, Bytes::from(data.clone()),
177 ),
178 }
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn invalid_marker_maps_to_header_error() {
188 let (code, subcode, _) = DecodeError::InvalidMarker.to_notification();
189 assert_eq!(code, NotificationCode::MessageHeader);
190 assert_eq!(subcode, 1);
191 }
192
193 #[test]
194 fn invalid_length_maps_to_bad_message_length() {
195 let err = DecodeError::InvalidLength { length: 5000 };
196 let (code, subcode, data) = err.to_notification();
197 assert_eq!(code, NotificationCode::MessageHeader);
198 assert_eq!(subcode, 2);
199 assert_eq!(data.as_ref(), &5000u16.to_be_bytes());
200 }
201
202 #[test]
203 fn unknown_type_maps_to_bad_message_type() {
204 let err = DecodeError::UnknownMessageType(99);
205 let (code, subcode, data) = err.to_notification();
206 assert_eq!(code, NotificationCode::MessageHeader);
207 assert_eq!(subcode, 3);
208 assert_eq!(data.as_ref(), &[99]);
209 }
210
211 #[test]
212 fn unsupported_version_maps_to_open_error() {
213 let err = DecodeError::UnsupportedVersion { version: 3 };
214 let (code, subcode, data) = err.to_notification();
215 assert_eq!(code, NotificationCode::OpenMessage);
216 assert_eq!(subcode, 1);
217 assert_eq!(data.as_ref(), &4u16.to_be_bytes());
218 }
219
220 #[test]
221 fn update_length_mismatch_maps_to_update_error() {
222 let err = DecodeError::UpdateLengthMismatch {
223 detail: "test".into(),
224 };
225 let (code, subcode, _) = err.to_notification();
226 assert_eq!(code, NotificationCode::UpdateMessage);
227 assert_eq!(subcode, 1);
228 }
229
230 #[test]
231 fn update_malformed_field_maps_to_update_error() {
232 let err = DecodeError::MalformedField {
233 message_type: "UPDATE",
234 detail: "invalid ORIGIN value 5".into(),
235 };
236 let (code, subcode, _) = err.to_notification();
237 assert_eq!(code, NotificationCode::UpdateMessage);
238 assert_eq!(subcode, 1);
239 }
240
241 #[test]
242 fn update_attribute_error_maps_correctly() {
243 let err = DecodeError::UpdateAttributeError {
244 subcode: 6,
245 data: vec![0x40, 0x01, 0x01, 0x05],
246 detail: "invalid ORIGIN value 5".into(),
247 };
248 let (code, subcode, data) = err.to_notification();
249 assert_eq!(code, NotificationCode::UpdateMessage);
250 assert_eq!(subcode, 6);
251 assert_eq!(data.as_ref(), &[0x40, 0x01, 0x01, 0x05]);
252 }
253
254 #[test]
255 fn invalid_network_field_maps_to_subcode_10() {
256 let err = DecodeError::InvalidNetworkField {
257 detail: "NLRI prefix length 33 exceeds 32".into(),
258 data: vec![33, 10, 0, 0, 0],
259 };
260 let (code, subcode, data) = err.to_notification();
261 assert_eq!(code, NotificationCode::UpdateMessage);
262 assert_eq!(subcode, 10);
263 assert_eq!(data.as_ref(), &[33, 10, 0, 0, 0]);
265 }
266
267 #[test]
268 fn open_malformed_field_maps_to_open_error() {
269 let err = DecodeError::MalformedField {
270 message_type: "OPEN",
271 detail: "test".into(),
272 };
273 let (code, subcode, _) = err.to_notification();
274 assert_eq!(code, NotificationCode::OpenMessage);
275 assert_eq!(subcode, 0);
276 }
277}