1 //! SNMP Parser (v1 and v2c)
2 //!
3 //! SNMP is defined in the following RFCs:
4 //! - [RFC1157](https://tools.ietf.org/html/rfc1157): SNMP v1
5 //! - [RFC1442](https://tools.ietf.org/html/rfc1442): Structure of Management Information for version 2 of the Simple Network Management Protocol (SNMPv2)
6 //! - [RFC1902](https://tools.ietf.org/html/rfc1902): SNMP v2 SMI
7 //! - [RFC2578](https://tools.ietf.org/html/rfc2578): Structure of Management Information Version 2 (SMIv2)
8 //! - [RFC3416](https://tools.ietf.org/html/rfc3416): SNMP v2
9 //! - [RFC2570](https://tools.ietf.org/html/rfc2570): Introduction to SNMP v3
10
11 use crate::error::SnmpError;
12 use std::{fmt,str};
13 use std::net::Ipv4Addr;
14 use std::slice::Iter;
15 use nom::{Err, IResult};
16 use der_parser::ber::*;
17 use der_parser::error::*;
18 use der_parser::oid::Oid;
19
20 #[derive(Clone, Copy, Eq, PartialEq)]
21 pub struct PduType(pub u32);
22
23 #[allow(non_upper_case_globals)]
24 impl PduType {
25 pub const GetRequest : PduType = PduType(0);
26 pub const GetNextRequest : PduType = PduType(1);
27 pub const Response : PduType = PduType(2);
28 pub const SetRequest : PduType = PduType(3);
29 pub const TrapV1 : PduType = PduType(4); // Obsolete, was the old Trap-PDU in SNMPv1
30 pub const GetBulkRequest : PduType = PduType(5);
31 pub const InformRequest : PduType = PduType(6);
32 pub const TrapV2 : PduType = PduType(7);
33 pub const Report : PduType = PduType(8);
34 }
35
36 impl fmt::Debug for PduType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result37 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38 match self.0 {
39 0 => f.write_str("GetRequest"),
40 1 => f.write_str("GetNextRequest"),
41 2 => f.write_str("Response"),
42 3 => f.write_str("SetRequest"),
43 4 => f.write_str("TrapV1"),
44 5 => f.write_str("GetBulkRequest"),
45 6 => f.write_str("InformRequest"),
46 7 => f.write_str("TrapV2"),
47 8 => f.write_str("Report"),
48 n => f.debug_tuple("PduType").field(&n).finish(),
49 }
50 }
51 }
52
53 #[derive(Clone, Copy, Eq, PartialEq)]
54 pub struct TrapType(pub u8);
55
56 impl TrapType {
57 pub const COLD_START : TrapType = TrapType(0);
58 pub const WARM_START : TrapType = TrapType(1);
59 pub const LINK_DOWN : TrapType = TrapType(2);
60 pub const LINK_UP : TrapType = TrapType(3);
61 pub const AUTHENTICATION_FAILURE : TrapType = TrapType(4);
62 pub const EGP_NEIGHBOR_LOSS : TrapType = TrapType(5);
63 pub const ENTERPRISE_SPECIFIC : TrapType = TrapType(6);
64 }
65
66 impl fmt::Debug for TrapType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result67 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 match self.0 {
69 0 => f.write_str("coldStart"),
70 1 => f.write_str("warmStart"),
71 2 => f.write_str("linkDown"),
72 3 => f.write_str("linkUp"),
73 4 => f.write_str("authenticationFailure"),
74 5 => f.write_str("egpNeighborLoss"),
75 6 => f.write_str("enterpriseSpecific"),
76 n => f.debug_tuple("TrapType").field(&n).finish(),
77 }
78 }
79 }
80
81 /// This CHOICE represents an address from one of possibly several
82 /// protocol families. Currently, only one protocol family, the Internet
83 /// family, is present in this CHOICE.
84 #[derive(Copy, Clone, Debug, PartialEq)]
85 pub enum NetworkAddress {
86 IPv4(Ipv4Addr),
87 }
88
89 /// This application-wide type represents a non-negative integer which
90 /// monotonically increases until it reaches a maximum value, when it
91 /// wraps around and starts increasing again from zero. This memo
92 /// specifies a maximum value of 2^32-1 (4294967295 decimal) for
93 /// counters.
94 pub type Counter = u32;
95
96 /// This application-wide type represents a non-negative integer, which
97 /// may increase or decrease, but which latches at a maximum value. This
98 /// memo specifies a maximum value of 2^32-1 (4294967295 decimal) for
99 /// gauges.
100 pub type Gauge = u32;
101
102 /// This application-wide type represents a non-negative integer which
103 /// counts the time in hundredths of a second since some epoch. When
104 /// object types are defined in the MIB which use this ASN.1 type, the
105 /// description of the object type identifies the reference epoch.
106 pub type TimeTicks = u32;
107
108 #[derive(Clone, Copy, Eq, PartialEq)]
109 pub struct ErrorStatus(pub u32);
110
111 #[allow(non_upper_case_globals)]
112 impl ErrorStatus {
113 pub const NoError : ErrorStatus = ErrorStatus(0);
114 pub const TooBig : ErrorStatus = ErrorStatus(1);
115 pub const NoSuchName : ErrorStatus = ErrorStatus(2);
116 pub const BadValue : ErrorStatus = ErrorStatus(3);
117 pub const ReadOnly : ErrorStatus = ErrorStatus(4);
118 pub const GenErr : ErrorStatus = ErrorStatus(5);
119 }
120
121 impl fmt::Debug for ErrorStatus {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 match self.0 {
124 0 => f.write_str("NoError"),
125 1 => f.write_str("TooBig"),
126 2 => f.write_str("NoSuchName"),
127 3 => f.write_str("BadValue"),
128 4 => f.write_str("ReadOnly"),
129 5 => f.write_str("GenErr"),
130 n => f.debug_tuple("ErrorStatus").field(&n).finish(),
131 }
132 }
133 }
134
135 #[derive(Debug,PartialEq)]
136 pub struct SnmpGenericPdu<'a> {
137 pub pdu_type: PduType,
138 pub req_id: u32,
139 pub err: ErrorStatus,
140 pub err_index: u32,
141 pub var: Vec<SnmpVariable<'a>>,
142 }
143
144 #[derive(Debug,PartialEq)]
145 pub struct SnmpBulkPdu<'a> {
146 pub req_id: u32,
147 pub non_repeaters: u32,
148 pub max_repetitions: u32,
149 pub var: Vec<SnmpVariable<'a>>,
150 }
151
152 #[derive(Debug,PartialEq)]
153 pub struct SnmpTrapPdu<'a> {
154 pub enterprise: Oid<'a>,
155 pub agent_addr: NetworkAddress,
156 pub generic_trap: TrapType,
157 pub specific_trap: u32,
158 pub timestamp: TimeTicks,
159 pub var: Vec<SnmpVariable<'a>>,
160 }
161
162 #[derive(Debug,PartialEq)]
163 pub enum SnmpPdu<'a> {
164 Generic(SnmpGenericPdu<'a>),
165 Bulk(SnmpBulkPdu<'a>),
166 TrapV1(SnmpTrapPdu<'a>),
167 }
168
169 /// An SNMPv1 or SNMPv2c message
170 #[derive(Debug,PartialEq)]
171 pub struct SnmpMessage<'a> {
172 /// Version, as raw-encoded: 0 for SNMPv1, 1 for SNMPv2c
173 pub version: u32,
174 pub community: String,
175 pub pdu: SnmpPdu<'a>,
176 }
177
178 impl<'a> SnmpGenericPdu<'a> {
vars_iter(&'a self) -> Iter<SnmpVariable>179 pub fn vars_iter(&'a self) -> Iter<SnmpVariable> {
180 self.var.iter()
181 }
182 }
183
184 impl<'a> SnmpTrapPdu<'a> {
vars_iter(&'a self) -> Iter<SnmpVariable>185 pub fn vars_iter(&'a self) -> Iter<SnmpVariable> {
186 self.var.iter()
187 }
188 }
189
190 impl<'a> SnmpPdu<'a> {
pdu_type(&self) -> PduType191 pub fn pdu_type(&self) -> PduType {
192 match *self {
193 SnmpPdu::Generic(ref pdu) => pdu.pdu_type,
194 SnmpPdu::Bulk(_) => PduType::GetBulkRequest,
195 SnmpPdu::TrapV1(_) => PduType::TrapV1,
196 }
197 }
198
vars_iter(&'a self) -> Iter<SnmpVariable>199 pub fn vars_iter(&'a self) -> Iter<SnmpVariable> {
200 match *self {
201 SnmpPdu::Generic(ref pdu) => pdu.var.iter(),
202 SnmpPdu::Bulk(ref pdu) => pdu.var.iter(),
203 SnmpPdu::TrapV1(ref pdu) => pdu.var.iter(),
204 }
205 }
206 }
207
208 impl<'a> SnmpMessage<'a> {
pdu_type(&self) -> PduType209 pub fn pdu_type(&self) -> PduType {
210 self.pdu.pdu_type()
211 }
212
vars_iter(&'a self) -> Iter<SnmpVariable>213 pub fn vars_iter(&'a self) -> Iter<SnmpVariable> {
214 self.pdu.vars_iter()
215 }
216 }
217
218 #[derive(Debug,PartialEq)]
219 pub struct SnmpVariable<'a> {
220 pub oid: Oid<'a>,
221 pub val: ObjectSyntax<'a>
222 }
223
224 #[derive(Debug,PartialEq)]
225 pub enum ObjectSyntax<'a> {
226 Number(BerObject<'a>),
227 String(&'a[u8]),
228 Object(Oid<'a>),
229 BitString(u8, BitStringObject<'a>),
230 Empty,
231 UnknownSimple(BerObject<'a>),
232 IpAddress(NetworkAddress),
233 Counter32(Counter),
234 Gauge32(Gauge),
235 TimeTicks(TimeTicks),
236 Opaque(&'a[u8]),
237 NsapAddress(&'a[u8]),
238 Counter64(u64),
239 UInteger32(u32),
240 UnknownApplication(u32, &'a[u8]),
241 }
242
parse_ber_octetstring_as_slice(i:&[u8]) -> IResult<&[u8], &[u8], BerError>243 pub(crate) fn parse_ber_octetstring_as_slice(i:&[u8]) -> IResult<&[u8], &[u8], BerError> {
244 match parse_ber_octetstring(i) {
245 Ok((rem,ref obj)) => {
246 match obj.content {
247 BerObjectContent::OctetString(s) => {
248 Ok((rem, s))
249 }
250 _ => Err(Err::Error(BerError::InvalidTag)),
251 }
252 }
253 Err(e) => Err(e)
254 }
255 }
256
257 // Defined in RFC1442 and RFC2578
parse_objectsyntax<'a>(i:&'a[u8]) -> IResult<&'a[u8], ObjectSyntax, BerError>258 fn parse_objectsyntax<'a>(i:&'a[u8]) -> IResult<&'a[u8], ObjectSyntax, BerError> {
259 match ber_read_element_header(i) {
260 Ok((rem,hdr)) => {
261 if hdr.is_application() {
262 match hdr.tag.0 {
263 0 => {
264 map_res!(
265 rem,
266 call!(ber_read_element_content_as, BerTag::OctetString, hdr.len as usize, hdr.is_constructed(), 0),
267 |x:BerObjectContent| {
268 match x {
269 BerObjectContent::OctetString(s) if s.len() == 4 => {
270 Ok(ObjectSyntax::IpAddress(NetworkAddress::IPv4(Ipv4Addr::new(s[0],s[1],s[2],s[3]))))
271 },
272 _ => Err(BerError::InvalidTag),
273 }
274 }
275 )
276 },
277 1 ..= 3 => {
278 map_res!(
279 rem,
280 call!(ber_read_element_content_as, BerTag::Integer, hdr.len as usize, hdr.is_constructed(), 0),
281 |x:BerObjectContent| {
282 x.as_u32().map(|x| {
283 match hdr.tag.0 {
284 1 => ObjectSyntax::Counter32(x),
285 2 => ObjectSyntax::Gauge32(x),
286 3 => ObjectSyntax::TimeTicks(x),
287 _ => unreachable!(),
288 }
289 })
290 }
291 )
292 },
293 4 => {
294 map!(rem, take!(hdr.len as usize), ObjectSyntax::Opaque)
295 },
296 5 => {
297 map!(rem, take!(hdr.len as usize), ObjectSyntax::NsapAddress)
298 },
299 6 => {
300 map_res!(
301 rem,
302 call!(ber_read_element_content_as, BerTag::Integer, hdr.len as usize, hdr.is_constructed(), 0),
303 |x:BerObjectContent| {
304 x.as_u64().map(ObjectSyntax::Counter64)
305 }
306 )
307 },
308 7 => {
309 map_res!(
310 rem,
311 call!(ber_read_element_content_as, BerTag::Integer, hdr.len as usize, hdr.is_constructed(), 0),
312 |x:BerObjectContent| {
313 x.as_u32().map(ObjectSyntax::UInteger32)
314 }
315 )
316 },
317 _ => {
318 map!(rem, take!(hdr.len as usize), |x| ObjectSyntax::UnknownApplication(hdr.tag.0,x))
319 },
320 }
321 } else {
322 if hdr.len == 0 { return Ok((rem, ObjectSyntax::Empty)); }
323 map_res!(
324 rem,
325 call!(ber_read_element_content_as, hdr.tag, hdr.len as usize, hdr.is_constructed(), 0),
326 |x:BerObjectContent<'a>| {
327 match x {
328 BerObjectContent::Integer(_) => Ok(ObjectSyntax::Number(BerObject::from_obj(x))),
329 BerObjectContent::OctetString(s) => Ok(ObjectSyntax::String(s)),
330 BerObjectContent::OID(o) => Ok(ObjectSyntax::Object(o)),
331 BerObjectContent::BitString(a,s) => Ok(ObjectSyntax::BitString(a,s)),
332 BerObjectContent::Null => Ok(ObjectSyntax::Empty),
333 _ => Ok(ObjectSyntax::UnknownSimple(BerObject::from_obj(x))) as Result<_,u32>,
334 }
335 }
336 )
337 }
338 },
339 Err(e) => Err(e)
340 }
341 }
342
343 #[inline]
parse_varbind<'a>(i:&'a [u8]) -> IResult<&'a [u8], SnmpVariable, BerError>344 fn parse_varbind<'a>(i:&'a [u8]) -> IResult<&'a [u8], SnmpVariable, BerError> {
345 parse_der_struct!(
346 i,
347 TAG BerTag::Sequence,
348 oid: map_res!(parse_ber_oid, |x:BerObject<'a>| x.as_oid_val()) >>
349 val: parse_objectsyntax >>
350 // eof!() >>
351 (
352 SnmpVariable{ oid, val }
353 )
354 ).map(|(rem,x)| (rem,x.1))
355 }
356
357 #[inline]
parse_varbind_list(i:&[u8]) -> IResult<&[u8], Vec<SnmpVariable>, BerError>358 fn parse_varbind_list(i:&[u8]) -> IResult<&[u8], Vec<SnmpVariable>, BerError> {
359 parse_der_struct!(
360 i,
361 TAG BerTag::Sequence,
362 l: many0!(complete!(parse_varbind)) >>
363 // eof!() >>
364 ( l )
365 ).map(|(rem,x)| (rem,x.1))
366 }
367
368 /// <pre>
369 /// NetworkAddress ::=
370 /// CHOICE {
371 /// internet
372 /// IpAddress
373 /// }
374 /// IpAddress ::=
375 /// [APPLICATION 0] -- in network-byte order
376 /// IMPLICIT OCTET STRING (SIZE (4))
377 /// </pre>
parse_networkaddress(i:&[u8]) -> IResult<&[u8], NetworkAddress, BerError>378 fn parse_networkaddress(i:&[u8]) -> IResult<&[u8], NetworkAddress, BerError> {
379 match parse_ber(i) {
380 Ok((rem,obj)) => {
381 if obj.header.tag != BerTag::EndOfContent || obj.header.class != BerClass::Application {
382 return Err(Err::Error(BerError::InvalidTag));
383 }
384 match obj.content {
385 BerObjectContent::Unknown(_,s) if s.len() == 4 => {
386 Ok((rem, NetworkAddress::IPv4(Ipv4Addr::new(s[0],s[1],s[2],s[3]))))
387 },
388 _ => Err(Err::Error(BerError::InvalidTag)),
389 }
390 },
391 Err(e) => Err(e)
392 }
393 }
394
395 /// <pre>
396 /// TimeTicks ::=
397 /// [APPLICATION 3]
398 /// IMPLICIT INTEGER (0..4294967295)
399 /// </pre>
parse_timeticks(i:&[u8]) -> IResult<&[u8], TimeTicks, BerError>400 fn parse_timeticks(i:&[u8]) -> IResult<&[u8], TimeTicks, BerError> {
401 fn ber_read_integer_content(i:&[u8], _tag:BerTag, len: usize) -> IResult<&[u8], BerObjectContent, BerError> {
402 ber_read_element_content_as(i, BerTag::Integer, len, false, 0)
403 }
404 map_res!(i, call!(parse_ber_implicit, BerTag(3), ber_read_integer_content), |x: BerObject| {
405 match x.as_context_specific() {
406 Ok((_,Some(x))) => x.as_u32(),
407 _ => Err(BerError::BerTypeError),
408 }
409 })
410 }
411
412
413
414
parse_snmp_v1_generic_pdu(pdu: &[u8], tag:PduType) -> IResult<&[u8], SnmpPdu, BerError>415 fn parse_snmp_v1_generic_pdu(pdu: &[u8], tag:PduType) -> IResult<&[u8], SnmpPdu, BerError> {
416 do_parse! {
417 pdu,
418 req_id: parse_ber_u32 >>
419 err: parse_ber_u32 >>
420 err_index: parse_ber_u32 >>
421 var_bindings: parse_varbind_list >>
422 (
423 SnmpPdu::Generic(
424 SnmpGenericPdu {
425 pdu_type: tag,
426 req_id,
427 err: ErrorStatus(err),
428 err_index,
429 var: var_bindings
430 }
431 )
432 )
433 }
434 }
435
parse_snmp_v1_bulk_pdu(pdu: &[u8]) -> IResult<&[u8], SnmpPdu, BerError>436 fn parse_snmp_v1_bulk_pdu(pdu: &[u8]) -> IResult<&[u8], SnmpPdu, BerError> {
437 do_parse! {
438 pdu,
439 req_id: parse_ber_u32 >>
440 non_repeaters: parse_ber_u32 >>
441 max_repetitions: parse_ber_u32 >>
442 var_bindings: parse_varbind_list >>
443 (
444 SnmpPdu::Bulk(
445 SnmpBulkPdu {
446 req_id,
447 non_repeaters,
448 max_repetitions,
449 var: var_bindings
450 }
451 )
452 )
453 }
454 }
455
parse_snmp_v1_trap_pdu<'a>(pdu: &'a [u8]) -> IResult<&'a [u8], SnmpPdu, BerError>456 fn parse_snmp_v1_trap_pdu<'a>(pdu: &'a [u8]) -> IResult<&'a [u8], SnmpPdu, BerError> {
457 do_parse! {
458 pdu,
459 enterprise: map_res!(parse_ber_oid, |x: BerObject<'a>| x.as_oid_val()) >>
460 agent_addr: parse_networkaddress >>
461 generic_trap: parse_ber_u32 >>
462 specific_trap: parse_ber_u32 >>
463 timestamp: parse_timeticks >>
464 var: parse_varbind_list >>
465 (
466 SnmpPdu::TrapV1(
467 SnmpTrapPdu {
468 enterprise,
469 agent_addr,
470 generic_trap: TrapType(generic_trap as u8),
471 specific_trap,
472 timestamp,
473 var,
474 }
475 )
476 )
477 }
478 }
479
480 /// Parse a SNMP v1 message.
481 ///
482 /// Top-level message
483 ///
484 /// <pre>
485 /// Message ::=
486 /// SEQUENCE {
487 /// version -- version-1 for this RFC
488 /// INTEGER {
489 /// version-1(0)
490 /// },
491 ///
492 /// community -- community name
493 /// OCTET STRING,
494 ///
495 /// data -- e.g., PDUs if trivial
496 /// ANY -- authentication is being used
497 /// }
498 /// </pre>
499 ///
500 /// Example:
501 ///
502 /// ```rust
503 /// # extern crate nom;
504 /// # #[macro_use] extern crate snmp_parser;
505 /// use snmp_parser::parse_snmp_v1;
506 ///
507 /// static SNMPV1_REQ: &'static [u8] = include_bytes!("../assets/snmpv1_req.bin");
508 ///
509 /// # fn main() {
510 /// match parse_snmp_v1(&SNMPV1_REQ) {
511 /// Ok((_, ref r)) => {
512 /// assert!(r.version == 0);
513 /// assert!(r.community == String::from("public"));
514 /// assert!(r.vars_iter().count() == 1);
515 /// },
516 /// Err(e) => panic!(e),
517 /// }
518 /// # }
519 /// ```
parse_snmp_v1(i:&[u8]) -> IResult<&[u8], SnmpMessage, SnmpError>520 pub fn parse_snmp_v1(i:&[u8]) -> IResult<&[u8], SnmpMessage, SnmpError> {
521 upgrade_error! {
522 parse_der_struct!(
523 i,
524 TAG BerTag::Sequence,
525 version: map_res!(parse_ber_integer, |o:BerObject| o.as_u32()) >>
526 custom_check!(version != 0, BerError::BerValueError) >>
527 community: map_res!(
528 parse_ber_octetstring_as_slice,
529 |s| str::from_utf8(s)
530 ) >>
531 pdu: parse_snmp_v1_pdu >>
532 (
533 SnmpMessage{
534 version,
535 community: community.to_string(),
536 pdu
537 }
538 )
539 ).map(|(rem,x)| (rem,x.1))
540 }
541 }
542
parse_snmp_v1_pdu(i:&[u8]) -> IResult<&[u8], SnmpPdu, BerError>543 pub(crate) fn parse_snmp_v1_pdu(i:&[u8]) -> IResult<&[u8], SnmpPdu, BerError> {
544 match ber_read_element_header(i) {
545 Ok((rem,hdr)) => {
546 match PduType(hdr.tag.0) {
547 PduType::GetRequest |
548 PduType::GetNextRequest |
549 PduType::Response |
550 PduType::SetRequest => parse_snmp_v1_generic_pdu(rem, PduType(hdr.tag.0)),
551 PduType::TrapV1 => parse_snmp_v1_trap_pdu(rem),
552 _ => Err(Err::Error(BerError::BerValueError)),
553 // _ => { return IResult::Error(error_code!(ErrorKind::Custom(SnmpError::InvalidPdu))); },
554 }
555 },
556 Err(e) => Err(e)
557 // IResult::Incomplete(i) => IResult::Incomplete(i),
558 // IResult::Error(_) => IResult::Error(error_code!(ErrorKind::Custom(129))),
559 // // IResult::Error(_) => IResult::Error(error_code!(ErrorKind::Custom(SnmpError::InvalidScopedPduData))),
560 }
561 }
562
563 /// Parse a SNMP v2c message.
564 ///
565 /// Top-level message
566 ///
567 /// <pre>
568 /// Message ::=
569 /// SEQUENCE {
570 /// version
571 /// INTEGER {
572 /// version(1) -- modified from RFC 1157
573 /// },
574 ///
575 /// community -- community name
576 /// OCTET STRING,
577 ///
578 /// data -- PDUs as defined in [4]
579 /// ANY
580 /// }
581 /// </pre>
parse_snmp_v2c(i:&[u8]) -> IResult<&[u8], SnmpMessage, SnmpError>582 pub fn parse_snmp_v2c(i:&[u8]) -> IResult<&[u8], SnmpMessage, SnmpError> {
583 upgrade_error! {
584 parse_der_struct!(
585 i,
586 TAG BerTag::Sequence,
587 version: parse_ber_u32 >>
588 custom_check!(version != 1, BerError::BerValueError) >>
589 community: map_res!(
590 parse_ber_octetstring_as_slice,
591 |s| str::from_utf8(s)
592 ) >>
593 pdu: parse_snmp_v2c_pdu >>
594 (
595 SnmpMessage{
596 version,
597 community: community.to_string(),
598 pdu
599 }
600 )
601 ).map(|(rem,x)| (rem,x.1))
602 }
603 }
604
parse_snmp_v2c_pdu(i:&[u8]) -> IResult<&[u8], SnmpPdu, BerError>605 pub(crate) fn parse_snmp_v2c_pdu(i:&[u8]) -> IResult<&[u8], SnmpPdu, BerError> {
606 match ber_read_element_header(i) {
607 Ok((rem,hdr)) => {
608 match PduType(hdr.tag.0) {
609 PduType::GetRequest |
610 PduType::GetNextRequest |
611 PduType::Response |
612 PduType::SetRequest |
613 PduType::InformRequest |
614 PduType::TrapV2 |
615 PduType::Report => parse_snmp_v1_generic_pdu(rem, PduType(hdr.tag.0)),
616 PduType::GetBulkRequest => parse_snmp_v1_bulk_pdu(rem),
617 PduType::TrapV1 => parse_snmp_v1_trap_pdu(rem),
618 _ => Err(Err::Error(BerError::BerValueError)),
619 // _ => { return IResult::Error(error_code!(ErrorKind::Custom(SnmpError::InvalidPdu))); },
620 }
621 },
622 Err(e) => Err(e)
623 // IResult::Incomplete(i) => IResult::Incomplete(i),
624 // IResult::Error(_) => IResult::Error(error_code!(ErrorKind::Custom(129))),
625 // // IResult::Error(_) => IResult::Error(error_code!(ErrorKind::Custom(SnmpError::InvalidScopedPduData))),
626 }
627 }
628