1use bytes::Bytes;
23
24use crate::ber::{Decoder, EncodeBuf};
25use crate::error::internal::DecodeErrorKind;
26use crate::error::{Error, Result, UNKNOWN_TARGET};
27use crate::pdu::Pdu;
28
29const MSG_MAX_SIZE_MINIMUM: i32 = 484;
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34#[repr(i32)]
35pub enum SecurityModel {
36 Usm = 3,
38}
39
40impl SecurityModel {
41 #[must_use]
43 pub fn from_i32(value: i32) -> Option<Self> {
44 match value {
45 3 => Some(Self::Usm),
46 _ => None,
47 }
48 }
49
50 #[must_use]
52 pub fn as_i32(self) -> i32 {
53 self as i32
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
62pub enum SecurityLevel {
63 NoAuthNoPriv,
65 AuthNoPriv,
67 AuthPriv,
69}
70
71impl SecurityLevel {
72 #[must_use]
74 pub fn from_flags(flags: u8) -> Option<Self> {
75 let auth = flags & 0x01 != 0;
76 let priv_ = flags & 0x02 != 0;
77
78 match (auth, priv_) {
79 (false, false) => Some(Self::NoAuthNoPriv),
80 (true, false) => Some(Self::AuthNoPriv),
81 (true, true) => Some(Self::AuthPriv),
82 (false, true) => None, }
84 }
85
86 #[must_use]
88 pub fn to_flags(self) -> u8 {
89 match self {
90 Self::NoAuthNoPriv => 0x00,
91 Self::AuthNoPriv => 0x01,
92 Self::AuthPriv => 0x03,
93 }
94 }
95
96 #[must_use]
98 pub fn requires_auth(self) -> bool {
99 matches!(self, Self::AuthNoPriv | Self::AuthPriv)
100 }
101
102 #[must_use]
104 pub fn requires_priv(self) -> bool {
105 matches!(self, Self::AuthPriv)
106 }
107}
108
109impl TryFrom<u8> for SecurityLevel {
110 type Error = u8;
111
112 fn try_from(flags: u8) -> std::result::Result<Self, u8> {
113 Self::from_flags(flags).ok_or(flags)
114 }
115}
116
117impl From<SecurityLevel> for u8 {
118 fn from(level: SecurityLevel) -> u8 {
119 level.to_flags()
120 }
121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq)]
125pub struct MsgFlags {
126 pub security_level: SecurityLevel,
128 pub reportable: bool,
130}
131
132impl MsgFlags {
133 #[must_use]
135 pub fn new(security_level: SecurityLevel, reportable: bool) -> Self {
136 Self {
137 security_level,
138 reportable,
139 }
140 }
141
142 pub fn from_byte(byte: u8) -> Result<Self> {
144 let security_level = SecurityLevel::from_flags(byte).ok_or_else(|| {
145 tracing::debug!(target: "async_snmp::v3", { byte, kind = %DecodeErrorKind::InvalidMsgFlags }, "decode error");
146 Error::MalformedResponse {
147 target: UNKNOWN_TARGET,
148 }
149 .boxed()
150 })?;
151 let reportable = byte & 0x04 != 0;
152 Ok(Self {
153 security_level,
154 reportable,
155 })
156 }
157
158 #[must_use]
160 pub fn to_byte(self) -> u8 {
161 let mut flags = self.security_level.to_flags();
162 if self.reportable {
163 flags |= 0x04;
164 }
165 flags
166 }
167}
168
169#[derive(Debug, Clone, PartialEq, Eq)]
171pub struct MsgGlobalData {
172 pub msg_id: i32,
174 pub msg_max_size: i32,
176 pub msg_flags: MsgFlags,
178 pub msg_security_model: SecurityModel,
180}
181
182impl MsgGlobalData {
183 #[must_use]
185 pub fn new(msg_id: i32, msg_max_size: i32, msg_flags: MsgFlags) -> Self {
186 Self {
187 msg_id,
188 msg_max_size,
189 msg_flags,
190 msg_security_model: SecurityModel::Usm,
191 }
192 }
193
194 pub fn encode(&self, buf: &mut EncodeBuf) {
196 buf.push_sequence(|buf| {
197 buf.push_integer(self.msg_security_model.as_i32());
198 buf.push_octet_string(&[self.msg_flags.to_byte()]);
200 buf.push_integer(self.msg_max_size);
201 buf.push_integer(self.msg_id);
202 });
203 }
204
205 pub fn decode(decoder: &mut Decoder) -> Result<Self> {
212 let mut seq = decoder.read_sequence()?;
213
214 let msg_id = seq.read_integer()?;
215 let msg_max_size = seq.read_integer()?;
216
217 if msg_id < 0 {
219 tracing::debug!(target: "async_snmp::v3", { offset = seq.offset(), value = msg_id, kind = %DecodeErrorKind::InvalidMsgId { value: msg_id } }, "decode error");
220 return Err(Error::MalformedResponse {
221 target: UNKNOWN_TARGET,
222 }
223 .boxed());
224 }
225
226 if msg_max_size < 0 {
229 tracing::debug!(target: "async_snmp::v3", { offset = seq.offset(), value = msg_max_size, kind = %DecodeErrorKind::MsgMaxSizeTooLarge { value: msg_max_size } }, "decode error");
230 return Err(Error::MalformedResponse {
231 target: UNKNOWN_TARGET,
232 }
233 .boxed());
234 }
235
236 if msg_max_size < MSG_MAX_SIZE_MINIMUM {
237 tracing::debug!(target: "async_snmp::v3", { offset = seq.offset(), value = msg_max_size, minimum = MSG_MAX_SIZE_MINIMUM, kind = %DecodeErrorKind::MsgMaxSizeTooSmall { value: msg_max_size, minimum: MSG_MAX_SIZE_MINIMUM } }, "decode error");
238 return Err(Error::MalformedResponse {
239 target: UNKNOWN_TARGET,
240 }
241 .boxed());
242 }
243
244 let flags_bytes = seq.read_octet_string()?;
245 if flags_bytes.len() != 1 {
246 tracing::debug!(target: "async_snmp::v3", { offset = seq.offset(), expected = 1, actual = flags_bytes.len() }, "invalid msgFlags length");
247 return Err(Error::MalformedResponse {
248 target: UNKNOWN_TARGET,
249 }
250 .boxed());
251 }
252 let msg_flags = MsgFlags::from_byte(flags_bytes[0])?;
253
254 let msg_security_model_raw = seq.read_integer()?;
255 let msg_security_model =
257 SecurityModel::from_i32(msg_security_model_raw).ok_or_else(|| {
258 tracing::debug!(target: "async_snmp::v3", { offset = seq.offset(), model = msg_security_model_raw, kind = %DecodeErrorKind::UnknownSecurityModel(msg_security_model_raw) }, "decode error");
259 Error::MalformedResponse {
260 target: UNKNOWN_TARGET,
261 }
262 .boxed()
263 })?;
264
265 Ok(Self {
266 msg_id,
267 msg_max_size,
268 msg_flags,
269 msg_security_model,
270 })
271 }
272}
273
274#[derive(Debug, Clone, PartialEq, Eq)]
276pub struct ScopedPdu {
277 pub context_engine_id: Bytes,
279 pub context_name: Bytes,
281 pub pdu: Pdu,
283}
284
285impl ScopedPdu {
286 pub fn new(
288 context_engine_id: impl Into<Bytes>,
289 context_name: impl Into<Bytes>,
290 pdu: Pdu,
291 ) -> Self {
292 Self {
293 context_engine_id: context_engine_id.into(),
294 context_name: context_name.into(),
295 pdu,
296 }
297 }
298
299 #[must_use]
301 pub fn with_empty_context(pdu: Pdu) -> Self {
302 Self {
303 context_engine_id: Bytes::new(),
304 context_name: Bytes::new(),
305 pdu,
306 }
307 }
308
309 pub fn encode(&self, buf: &mut EncodeBuf) {
311 buf.push_sequence(|buf| {
312 self.pdu.encode(buf);
313 buf.push_octet_string(&self.context_name);
314 buf.push_octet_string(&self.context_engine_id);
315 });
316 }
317
318 pub fn encode_to_bytes(&self) -> Bytes {
320 let mut buf = EncodeBuf::new();
321 self.encode(&mut buf);
322 buf.finish()
323 }
324
325 pub fn decode(decoder: &mut Decoder) -> Result<Self> {
327 let mut seq = decoder.read_sequence()?;
328
329 let context_engine_id = seq.read_octet_string()?;
330 let context_name = seq.read_octet_string()?;
331 let pdu = Pdu::decode(&mut seq)?;
332
333 Ok(Self {
334 context_engine_id,
335 context_name,
336 pdu,
337 })
338 }
339}
340
341#[derive(Debug, Clone, PartialEq, Eq)]
343pub struct V3Message {
344 pub global_data: MsgGlobalData,
346 pub security_params: Bytes,
348 pub data: V3MessageData,
350}
351
352#[derive(Debug, Clone, PartialEq, Eq)]
354pub enum V3MessageData {
355 Plaintext(ScopedPdu),
357 Encrypted(Bytes),
359}
360
361impl V3Message {
362 pub fn new(global_data: MsgGlobalData, security_params: Bytes, scoped_pdu: ScopedPdu) -> Self {
364 Self {
365 global_data,
366 security_params,
367 data: V3MessageData::Plaintext(scoped_pdu),
368 }
369 }
370
371 pub fn new_encrypted(
373 global_data: MsgGlobalData,
374 security_params: Bytes,
375 encrypted: Bytes,
376 ) -> Self {
377 Self {
378 global_data,
379 security_params,
380 data: V3MessageData::Encrypted(encrypted),
381 }
382 }
383
384 pub fn scoped_pdu(&self) -> Option<&ScopedPdu> {
386 match &self.data {
387 V3MessageData::Plaintext(pdu) => Some(pdu),
388 V3MessageData::Encrypted(_) => None,
389 }
390 }
391
392 pub fn into_scoped_pdu(self) -> Option<ScopedPdu> {
394 match self.data {
395 V3MessageData::Plaintext(pdu) => Some(pdu),
396 V3MessageData::Encrypted(_) => None,
397 }
398 }
399
400 pub fn pdu(&self) -> Option<&Pdu> {
402 self.scoped_pdu().map(|s| &s.pdu)
403 }
404
405 pub fn into_pdu(self) -> Option<Pdu> {
407 self.into_scoped_pdu().map(|s| s.pdu)
408 }
409
410 pub fn msg_id(&self) -> i32 {
412 self.global_data.msg_id
413 }
414
415 pub fn security_level(&self) -> SecurityLevel {
417 self.global_data.msg_flags.security_level
418 }
419
420 pub fn encode(&self) -> Bytes {
427 let mut buf = EncodeBuf::new();
428
429 buf.push_sequence(|buf| {
430 match &self.data {
432 V3MessageData::Plaintext(scoped_pdu) => {
433 scoped_pdu.encode(buf);
434 }
435 V3MessageData::Encrypted(ciphertext) => {
436 buf.push_octet_string(ciphertext);
437 }
438 }
439
440 buf.push_octet_string(&self.security_params);
442
443 self.global_data.encode(buf);
445
446 buf.push_integer(3);
448 });
449
450 buf.finish()
451 }
452
453 pub fn decode(data: Bytes) -> Result<Self> {
458 let mut decoder = Decoder::new(data);
459 let mut seq = decoder.read_sequence()?;
460
461 let version = seq.read_integer()?;
463 if version != 3 {
464 tracing::debug!(target: "async_snmp::v3", { offset = seq.offset(), version, kind = %DecodeErrorKind::UnknownVersion(version) }, "decode error");
465 return Err(Error::MalformedResponse {
466 target: UNKNOWN_TARGET,
467 }
468 .boxed());
469 }
470
471 Self::decode_from_sequence(&mut seq)
472 }
473
474 pub(crate) fn decode_from_sequence(seq: &mut Decoder) -> Result<Self> {
476 let global_data = MsgGlobalData::decode(seq)?;
478
479 let security_params = seq.read_octet_string()?;
481
482 let data = if global_data.msg_flags.security_level.requires_priv() {
484 let encrypted = seq.read_octet_string()?;
486 V3MessageData::Encrypted(encrypted)
487 } else {
488 let scoped_pdu = ScopedPdu::decode(seq)?;
490 V3MessageData::Plaintext(scoped_pdu)
491 };
492
493 Ok(Self {
494 global_data,
495 security_params,
496 data,
497 })
498 }
499
500 #[must_use]
505 pub fn discovery_request(msg_id: i32) -> Self {
506 let global_data = MsgGlobalData::new(
507 msg_id,
508 65507, MsgFlags::new(SecurityLevel::NoAuthNoPriv, true),
510 );
511
512 let security_params = crate::v3::UsmSecurityParams::empty().encode();
514
515 let pdu = Pdu::get_request(0, &[]);
517 let scoped_pdu = ScopedPdu::with_empty_context(pdu);
518
519 Self::new(global_data, security_params, scoped_pdu)
520 }
521}
522
523#[derive(Debug, Clone, Copy, PartialEq, Eq)]
526pub(crate) enum MpdFailure {
527 InvalidMsgFlags,
529 UnknownSecurityModel,
531}
532
533pub(crate) fn classify_mpd_failure(data: Bytes) -> Option<MpdFailure> {
539 let mut decoder = Decoder::new(data);
540 let mut seq = decoder.read_sequence().ok()?;
541 if seq.read_integer().ok()? != 3 {
542 return None;
543 }
544 let mut global = seq.read_sequence().ok()?;
545 let msg_id = global.read_integer().ok()?;
552 if msg_id < 0 {
553 return None;
554 }
555 let msg_max_size = global.read_integer().ok()?;
556 if msg_max_size < MSG_MAX_SIZE_MINIMUM {
557 return None;
558 }
559 let flags_bytes = global.read_octet_string().ok()?;
560 if flags_bytes.len() != 1 {
561 return None;
562 }
563 if MsgFlags::from_byte(flags_bytes[0]).is_err() {
564 return Some(MpdFailure::InvalidMsgFlags);
565 }
566 let model = global.read_integer().ok()?;
567 if SecurityModel::from_i32(model).is_none() {
568 return Some(MpdFailure::UnknownSecurityModel);
569 }
570 None
571}
572
573#[cfg(test)]
574mod tests {
575 use super::*;
576 use crate::oid;
577
578 #[test]
579 fn test_security_level_flags() {
580 assert_eq!(SecurityLevel::NoAuthNoPriv.to_flags(), 0x00);
581 assert_eq!(SecurityLevel::AuthNoPriv.to_flags(), 0x01);
582 assert_eq!(SecurityLevel::AuthPriv.to_flags(), 0x03);
583
584 assert_eq!(
585 SecurityLevel::from_flags(0x00),
586 Some(SecurityLevel::NoAuthNoPriv)
587 );
588 assert_eq!(
589 SecurityLevel::from_flags(0x01),
590 Some(SecurityLevel::AuthNoPriv)
591 );
592 assert_eq!(
593 SecurityLevel::from_flags(0x03),
594 Some(SecurityLevel::AuthPriv)
595 );
596 assert_eq!(SecurityLevel::from_flags(0x02), None); }
598
599 #[test]
600 fn security_level_try_from_u8() {
601 assert_eq!(
602 SecurityLevel::try_from(0x00),
603 Ok(SecurityLevel::NoAuthNoPriv)
604 );
605 assert_eq!(SecurityLevel::try_from(0x01), Ok(SecurityLevel::AuthNoPriv));
606 assert_eq!(SecurityLevel::try_from(0x03), Ok(SecurityLevel::AuthPriv));
607 assert_eq!(SecurityLevel::try_from(0x02), Err(0x02));
608 }
609
610 #[test]
611 fn security_level_into_u8() {
612 assert_eq!(u8::from(SecurityLevel::NoAuthNoPriv), 0x00);
613 assert_eq!(u8::from(SecurityLevel::AuthNoPriv), 0x01);
614 assert_eq!(u8::from(SecurityLevel::AuthPriv), 0x03);
615 }
616
617 #[test]
618 fn test_msg_flags_roundtrip() {
619 let flags = MsgFlags::new(SecurityLevel::AuthPriv, true);
620 let byte = flags.to_byte();
621 assert_eq!(byte, 0x07); let decoded = MsgFlags::from_byte(byte).unwrap();
624 assert_eq!(decoded.security_level, SecurityLevel::AuthPriv);
625 assert!(decoded.reportable);
626 }
627
628 #[test]
633 fn classify_mpd_failure_mirrors_decode_fail_fast() {
634 use crate::pdu::Pdu;
635 use crate::v3::UsmSecurityParams;
636
637 let global = MsgGlobalData::new(1, 65507, MsgFlags::new(SecurityLevel::NoAuthNoPriv, true));
640 let usm =
641 UsmSecurityParams::new(Bytes::from_static(b"eid"), 0, 0, Bytes::from_static(b"u"));
642 let scoped = ScopedPdu::new(
643 Bytes::from_static(b"eid"),
644 Bytes::new(),
645 Pdu::get_request(42, &[]),
646 );
647 let base = V3Message::new(global, usm.encode(), scoped).encode();
648
649 let patch = |data: &Bytes, pattern: &[u8], off: usize, val: u8| -> Bytes {
650 let mut b = data.to_vec();
651 let pos = b
652 .windows(pattern.len())
653 .position(|w| w == pattern)
654 .expect("pattern not found");
655 b[pos + off] = val;
656 Bytes::from(b)
657 };
658
659 let model_pattern = [0x04, 0x01, 0x04, 0x02, 0x01, 0x03];
661 let unknown_model = patch(&base, &model_pattern, 5, 99);
662 assert_eq!(
663 classify_mpd_failure(unknown_model),
664 Some(MpdFailure::UnknownSecurityModel)
665 );
666
667 let neg_id = patch(&base, &[0x02, 0x01, 0x01, 0x02, 0x03], 2, 0x81);
670 let neg_id_unknown_model = patch(&neg_id, &model_pattern, 5, 99);
671 assert_eq!(classify_mpd_failure(neg_id_unknown_model), None);
672 }
673
674 #[test]
675 fn test_msg_global_data_roundtrip() {
676 let global =
677 MsgGlobalData::new(12345, 1472, MsgFlags::new(SecurityLevel::AuthNoPriv, true));
678
679 let mut buf = EncodeBuf::new();
680 global.encode(&mut buf);
681 let encoded = buf.finish();
682
683 let mut decoder = Decoder::new(encoded);
684 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
685
686 assert_eq!(decoded.msg_id, 12345);
687 assert_eq!(decoded.msg_max_size, 1472);
688 assert_eq!(decoded.msg_flags.security_level, SecurityLevel::AuthNoPriv);
689 assert!(decoded.msg_flags.reportable);
690 assert_eq!(decoded.msg_security_model, SecurityModel::Usm);
691 }
692
693 #[test]
694 fn test_scoped_pdu_roundtrip() {
695 let pdu = Pdu::get_request(42, &[oid!(1, 3, 6, 1, 2, 1, 1, 1, 0)]);
696 let scoped = ScopedPdu::new(b"engine".as_slice(), b"ctx".as_slice(), pdu);
697
698 let mut buf = EncodeBuf::new();
699 scoped.encode(&mut buf);
700 let encoded = buf.finish();
701
702 let mut decoder = Decoder::new(encoded);
703 let decoded = ScopedPdu::decode(&mut decoder).unwrap();
704
705 assert_eq!(decoded.context_engine_id.as_ref(), b"engine");
706 assert_eq!(decoded.context_name.as_ref(), b"ctx");
707 assert_eq!(decoded.pdu.request_id, 42);
708 }
709
710 #[test]
711 fn test_v3_message_plaintext_roundtrip() {
712 let global =
713 MsgGlobalData::new(100, 1472, MsgFlags::new(SecurityLevel::NoAuthNoPriv, true));
714 let pdu = Pdu::get_request(42, &[oid!(1, 3, 6, 1, 2, 1, 1, 1, 0)]);
715 let scoped = ScopedPdu::with_empty_context(pdu);
716 let msg = V3Message::new(global, Bytes::from_static(b"usm-params"), scoped);
717
718 let encoded = msg.encode();
719 let decoded = V3Message::decode(encoded).unwrap();
720
721 assert_eq!(decoded.global_data.msg_id, 100);
722 assert_eq!(decoded.security_level(), SecurityLevel::NoAuthNoPriv);
723 assert_eq!(decoded.security_params.as_ref(), b"usm-params");
724
725 let scoped_pdu = decoded.scoped_pdu().unwrap();
726 assert_eq!(scoped_pdu.pdu.request_id, 42);
727 }
728
729 #[test]
730 fn test_v3_message_encrypted_roundtrip() {
731 let global = MsgGlobalData::new(200, 1472, MsgFlags::new(SecurityLevel::AuthPriv, false));
732 let msg = V3Message::new_encrypted(
733 global,
734 Bytes::from_static(b"usm-params"),
735 Bytes::from_static(b"encrypted-data"),
736 );
737
738 let encoded = msg.encode();
739 let decoded = V3Message::decode(encoded).unwrap();
740
741 assert_eq!(decoded.global_data.msg_id, 200);
742 assert_eq!(decoded.security_level(), SecurityLevel::AuthPriv);
743
744 match &decoded.data {
745 V3MessageData::Encrypted(data) => {
746 assert_eq!(data.as_ref(), b"encrypted-data");
747 }
748 V3MessageData::Plaintext(_) => panic!("expected encrypted data"),
749 }
750 }
751
752 #[test]
753 fn test_msg_global_data_rejects_msg_max_size_below_minimum() {
754 let global = MsgGlobalData {
756 msg_id: 100,
757 msg_max_size: 400, msg_flags: MsgFlags::new(SecurityLevel::NoAuthNoPriv, true),
759 msg_security_model: SecurityModel::Usm,
760 };
761
762 let mut buf = EncodeBuf::new();
763 global.encode(&mut buf);
764 let encoded = buf.finish();
765
766 let mut decoder = Decoder::new(encoded);
767 let result = MsgGlobalData::decode(&mut decoder);
768
769 assert!(result.is_err());
770 assert!(matches!(
771 *result.unwrap_err(),
772 Error::MalformedResponse { .. }
773 ));
774 }
775
776 #[test]
777 fn test_msg_global_data_accepts_msg_max_size_at_minimum() {
778 let global = MsgGlobalData::new(100, 484, MsgFlags::new(SecurityLevel::NoAuthNoPriv, true));
780
781 let mut buf = EncodeBuf::new();
782 global.encode(&mut buf);
783 let encoded = buf.finish();
784
785 let mut decoder = Decoder::new(encoded);
786 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
787
788 assert_eq!(decoded.msg_max_size, 484);
789 }
790
791 #[test]
792 fn test_msg_global_data_rejects_unknown_security_model() {
793 let mut buf = EncodeBuf::new();
796 buf.push_sequence(|buf| {
797 buf.push_integer(99); buf.push_octet_string(&[0x04]); buf.push_integer(1472); buf.push_integer(100); });
802 let encoded = buf.finish();
803
804 let mut decoder = Decoder::new(encoded);
805 let result = MsgGlobalData::decode(&mut decoder);
806
807 assert!(result.is_err());
808 assert!(matches!(
809 *result.unwrap_err(),
810 Error::MalformedResponse { .. }
811 ));
812 }
813
814 #[test]
815 fn test_msg_global_data_rejects_zero_length_msg_flags() {
816 let mut buf = EncodeBuf::new();
819 buf.push_sequence(|buf| {
820 buf.push_integer(3); buf.push_octet_string(&[]); buf.push_integer(1472); buf.push_integer(100); });
825 let encoded = buf.finish();
826
827 let mut decoder = Decoder::new(encoded);
828 let result = MsgGlobalData::decode(&mut decoder);
829
830 assert!(result.is_err());
831 assert!(matches!(
832 *result.unwrap_err(),
833 Error::MalformedResponse { .. }
834 ));
835 }
836
837 #[test]
838 fn test_msg_global_data_rejects_two_byte_msg_flags() {
839 let mut buf = EncodeBuf::new();
842 buf.push_sequence(|buf| {
843 buf.push_integer(3); buf.push_octet_string(&[0x04, 0x00]); buf.push_integer(1472); buf.push_integer(100); });
848 let encoded = buf.finish();
849
850 let mut decoder = Decoder::new(encoded);
851 let result = MsgGlobalData::decode(&mut decoder);
852
853 assert!(result.is_err());
854 assert!(matches!(
855 *result.unwrap_err(),
856 Error::MalformedResponse { .. }
857 ));
858 }
859
860 #[test]
861 fn test_msg_global_data_accepts_one_byte_msg_flags() {
862 let mut buf = EncodeBuf::new();
865 buf.push_sequence(|buf| {
866 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(1472); buf.push_integer(100); });
871 let encoded = buf.finish();
872
873 let mut decoder = Decoder::new(encoded);
874 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
875
876 assert_eq!(decoded.msg_flags, MsgFlags::from_byte(0x04).unwrap());
877 assert_eq!(decoded.msg_security_model, SecurityModel::Usm);
878 }
879
880 #[test]
881 fn test_msg_global_data_accepts_usm_security_model() {
882 let global =
884 MsgGlobalData::new(100, 1472, MsgFlags::new(SecurityLevel::NoAuthNoPriv, true));
885
886 let mut buf = EncodeBuf::new();
887 global.encode(&mut buf);
888 let encoded = buf.finish();
889
890 let mut decoder = Decoder::new(encoded);
891 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
892
893 assert_eq!(decoded.msg_security_model, SecurityModel::Usm);
894 }
895
896 #[test]
905 fn test_msg_global_data_rejects_negative_msg_id() {
906 let mut buf = EncodeBuf::new();
909 buf.push_sequence(|buf| {
910 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(1472); buf.push_integer(-1); });
915 let encoded = buf.finish();
916
917 let mut decoder = Decoder::new(encoded);
918 let result = MsgGlobalData::decode(&mut decoder);
919
920 assert!(result.is_err());
921 assert!(matches!(
922 *result.unwrap_err(),
923 Error::MalformedResponse { .. }
924 ));
925 }
926
927 #[test]
928 fn test_msg_global_data_rejects_negative_msg_max_size() {
929 let mut buf = EncodeBuf::new();
932 buf.push_sequence(|buf| {
933 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(-1); buf.push_integer(100); });
938 let encoded = buf.finish();
939
940 let mut decoder = Decoder::new(encoded);
941 let result = MsgGlobalData::decode(&mut decoder);
942
943 assert!(result.is_err());
944 assert!(matches!(
945 *result.unwrap_err(),
946 Error::MalformedResponse { .. }
947 ));
948 }
949
950 #[test]
951 fn test_msg_global_data_accepts_msg_id_at_zero() {
952 let mut buf = EncodeBuf::new();
954 buf.push_sequence(|buf| {
955 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(1472); buf.push_integer(0); });
960 let encoded = buf.finish();
961
962 let mut decoder = Decoder::new(encoded);
963 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
964
965 assert_eq!(decoded.msg_id, 0);
966 }
967
968 #[test]
969 fn test_msg_global_data_accepts_msg_id_at_maximum() {
970 let mut buf = EncodeBuf::new();
972 buf.push_sequence(|buf| {
973 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(1472); buf.push_integer(i32::MAX); });
978 let encoded = buf.finish();
979
980 let mut decoder = Decoder::new(encoded);
981 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
982
983 assert_eq!(decoded.msg_id, i32::MAX);
984 }
985
986 #[test]
987 fn test_msg_global_data_accepts_msg_max_size_at_maximum() {
988 let mut buf = EncodeBuf::new();
990 buf.push_sequence(|buf| {
991 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(i32::MAX); buf.push_integer(100); });
996 let encoded = buf.finish();
997
998 let mut decoder = Decoder::new(encoded);
999 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
1000
1001 assert_eq!(decoded.msg_max_size, i32::MAX);
1002 }
1003}