2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * John Robert LoVerso. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * This implementation has been influenced by the CMU SNMP release,
29 * by Steve Waldbusser. However, this shares no code with that system.
30 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
31 * Earlier forms of this implementation were derived and/or inspired by an
32 * awk script originally written by C. Philip Wood of LANL (but later
33 * heavily modified by John Robert LoVerso). The copyright notice for
34 * that work is preserved below, even though it may not rightly apply
37 * Support for SNMPv2c/SNMPv3 and the ability to link the module against
38 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
40 * This started out as a very simple program, but the incremental decoding
41 * (into the BE structure) complicated things.
43 # Los Alamos National Laboratory
45 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
46 # This software was produced under a U.S. Government contract
47 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
48 # operated by the University of California for the U.S. Department
49 # of Energy. The U.S. Government is licensed to use, reproduce,
50 # and distribute this software. Permission is granted to the
51 # public to copy and use this software without charge, provided
52 # that this Notice and any statement of authorship are reproduced
53 # on all copies. Neither the Government nor the University makes
54 # any warranty, express or implied, or assumes any liability or
55 # responsibility for the use of this software.
56 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
59 #define NETDISSECT_REWORKED
64 #include <tcpdump-stdinc.h>
73 #include "interface.h"
75 #undef OPAQUE /* defined in <wingdi.h> */
77 static const char tstr
[] = "[|snmp]";
80 * Universal ASN.1 types
81 * (we only care about the tag values for those allowed in the Internet SMI)
83 static const char *Universal
[] = {
96 "U-8","U-9","U-10","U-11", /* 8-11 */
97 "U-12","U-13","U-14","U-15", /* 12-15 */
104 * Application-wide ASN.1 types from the Internet SMI and their tags
106 static const char *Application
[] = {
123 * Context-specific ASN.1 types for the SNMP PDUs and their tags
125 static const char *Context
[] = {
146 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
147 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
148 #define WRITE_CLASS(x) (x == SETREQ)
149 #define RESPONSE_CLASS(x) (x == GETRESP)
150 #define INTERNAL_CLASS(x) (x == REPORT)
153 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
155 static const char *Exceptions
[] = {
157 #define NOSUCHOBJECT 0
159 #define NOSUCHINSTANCE 1
161 #define ENDOFMIBVIEW 2
165 * Private ASN.1 types
166 * The Internet SMI does not specify any
168 static const char *Private
[] = {
173 * error-status values for any SNMP PDU
175 static const char *ErrorStatus
[] = {
189 "resourceUnavailable",
192 "authorizationError",
196 #define DECODE_ErrorStatus(e) \
197 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
199 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
202 * generic-trap values in the SNMP Trap-PDU
204 static const char *GenericTrap
[] = {
209 "authenticationFailure",
212 #define GT_ENTERPRISE 6
214 #define DECODE_GenericTrap(t) \
215 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
217 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
220 * ASN.1 type class table
221 * Ties together the preceding Universal, Application, Context, and Private
224 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
225 static const struct {
230 defineCLASS(Universal
),
232 defineCLASS(Application
),
233 #define APPLICATION 1
234 defineCLASS(Context
),
236 defineCLASS(Private
),
238 defineCLASS(Exceptions
),
243 * defined forms for ASN.1 types
245 static const char *Form
[] = {
249 #define CONSTRUCTED 1
253 * A structure for the OID tree for the compiled-in MIB.
254 * This is stored as a general-order tree.
257 const char *desc
; /* name of object */
258 u_char oid
; /* sub-id following parent */
259 u_char type
; /* object type (unused) */
260 struct obj
*child
, *next
; /* child and next sibling pointers */
264 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
265 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
266 * a value for `mibroot'.
268 * In particular, this is gross, as this is including initialized structures,
269 * and by right shouldn't be an "include" file.
274 * This defines a list of OIDs which will be abbreviated on output.
275 * Currently, this includes the prefixes for the Internet MIB, the
276 * private enterprises tree, and the experimental tree.
278 static const struct obj_abrev
{
279 const char *prefix
; /* prefix for this abrev */
280 struct obj
*node
; /* pointer into object table */
281 const char *oid
; /* ASN.1 encoded OID */
282 } obj_abrev_list
[] = {
284 /* .iso.org.dod.internet.mgmt.mib */
285 { "", &_mib_obj
, "\53\6\1\2\1" },
287 #ifndef NO_ABREV_ENTER
288 /* .iso.org.dod.internet.private.enterprises */
289 { "E:", &_enterprises_obj
, "\53\6\1\4\1" },
291 #ifndef NO_ABREV_EXPERI
292 /* .iso.org.dod.internet.experimental */
293 { "X:", &_experimental_obj
, "\53\6\1\3" },
295 #ifndef NO_ABBREV_SNMPMODS
296 /* .iso.org.dod.internet.snmpV2.snmpModules */
297 { "S:", &_snmpModules_obj
, "\53\6\1\6\3" },
303 * This is used in the OID print routine to walk down the object tree
304 * rooted at `mibroot'.
306 #define OBJ_PRINT(o, suppressdot) \
310 if ((o) == objp->oid) \
312 } while ((objp = objp->next) != NULL); \
315 ND_PRINT((ndo, suppressdot?"%s":".%s", objp->desc)); \
316 objp = objp->child; \
318 ND_PRINT((ndo, suppressdot?"%u":".%u", (o))); \
322 * This is the definition for the Any-Data-Type storage used purely for
323 * temporary internal representation while decoding an ASN.1 data stream.
338 u_char form
, class; /* tag info */
349 #define BE_INETADDR 8
352 #define BE_NOSUCHOBJECT 128
353 #define BE_NOSUCHINST 129
354 #define BE_ENDOFMIBVIEW 130
358 * SNMP versions recognized by this module
360 static const char *SnmpVersion
[] = {
362 #define SNMP_VERSION_1 0
364 #define SNMP_VERSION_2 1
366 #define SNMP_VERSION_2U 2
368 #define SNMP_VERSION_3 3
372 * Defaults for SNMP PDU components
374 #define DEF_COMMUNITY "public"
377 * constants for ASN.1 decoding
380 #define ASNLEN_INETADDR 4
383 #define ASN_BIT8 0x80
384 #define ASN_LONGLEN 0x80
386 #define ASN_ID_BITS 0x1f
387 #define ASN_FORM_BITS 0x20
388 #define ASN_FORM_SHIFT 5
389 #define ASN_CLASS_BITS 0xc0
390 #define ASN_CLASS_SHIFT 6
392 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
395 * This decodes the next ASN.1 object in the stream pointed to by "p"
396 * (and of real-length "len") and stores the intermediate data in the
397 * provided BE object.
399 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
400 * O/w, this returns the number of bytes parsed from "p".
403 asn1_parse(netdissect_options
*ndo
,
404 register const u_char
*p
, u_int len
, struct be
*elem
)
406 u_char form
, class, id
;
412 ND_PRINT((ndo
, "[nothing to parse]"));
418 * it would be nice to use a bit field, but you can't depend on them.
419 * +---+---+---+---+---+---+---+---+
421 * +---+---+---+---+---+---+---+---+
424 id
= *p
& ASN_ID_BITS
; /* lower 5 bits, range 00-1f */
426 form
= (*p
& 0xe0) >> 5; /* move upper 3 bits to lower 3 */
427 class = form
>> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
428 form
&= 0x1; /* bit 5 -> bit 0, range 0-1 */
430 form
= (u_char
)(*p
& ASN_FORM_BITS
) >> ASN_FORM_SHIFT
;
431 class = (u_char
)(*p
& ASN_CLASS_BITS
) >> ASN_CLASS_SHIFT
;
437 /* extended tag field */
438 if (id
== ASN_ID_EXT
) {
440 * The ID follows, as a sequence of octets with the
441 * 8th bit set and the remaining 7 bits being
442 * the next 7 bits of the value, terminated with
443 * an octet with the 8th bit not set.
445 * First, assemble all the octets with the 8th
446 * bit set. XXX - this doesn't handle a value
447 * that won't fit in 32 bits.
449 for (id
= 0; *p
& ASN_BIT8
; len
--, hdr
++, p
++) {
451 ND_PRINT((ndo
, "[Xtagfield?]"));
455 id
= (id
<< 7) | (*p
& ~ASN_BIT8
);
458 ND_PRINT((ndo
, "[Xtagfield?]"));
462 elem
->id
= id
= (id
<< 7) | *p
;
468 ND_PRINT((ndo
, "[no asnlen]"));
474 if (elem
->asnlen
& ASN_BIT8
) {
475 u_int32_t noct
= elem
->asnlen
% ASN_BIT8
;
478 ND_PRINT((ndo
, "[asnlen? %d<%d]", len
, noct
));
481 ND_TCHECK2(*p
, noct
);
482 for (; noct
-- > 0; len
--, hdr
++)
483 elem
->asnlen
= (elem
->asnlen
<< ASN_SHIFT8
) | *p
++;
485 if (len
< elem
->asnlen
) {
486 ND_PRINT((ndo
, "[len%d<asnlen%u]", len
, elem
->asnlen
));
489 if (form
>= sizeof(Form
)/sizeof(Form
[0])) {
490 ND_PRINT((ndo
, "[form?%d]", form
));
493 if (class >= sizeof(Class
)/sizeof(Class
[0])) {
494 ND_PRINT((ndo
, "[class?%c/%d]", *Form
[form
], class));
497 if ((int)id
>= Class
[class].numIDs
) {
498 ND_PRINT((ndo
, "[id?%c/%s/%d]", *Form
[form
], Class
[class].name
, id
));
513 register int32_t data
;
517 ND_TCHECK2(*p
, elem
->asnlen
);
518 if (*p
& ASN_BIT8
) /* negative */
520 for (i
= elem
->asnlen
; i
-- > 0; p
++)
521 data
= (data
<< ASN_SHIFT8
) | *p
;
522 elem
->data
.integer
= data
;
528 elem
->data
.raw
= (caddr_t
)p
;
532 elem
->type
= BE_NULL
;
533 elem
->data
.raw
= NULL
;
537 elem
->type
= BE_OCTET
;
538 elem
->data
.raw
= (caddr_t
)p
;
539 ND_PRINT((ndo
, "[P/U/%s]", Class
[class].Id
[id
]));
547 elem
->type
= BE_INETADDR
;
548 elem
->data
.raw
= (caddr_t
)p
;
554 register u_int32_t data
;
555 ND_TCHECK2(*p
, elem
->asnlen
);
558 for (i
= elem
->asnlen
; i
-- > 0; p
++)
559 data
= (data
<< 8) + *p
;
560 elem
->data
.uns
= data
;
565 register u_int32_t high
, low
;
566 ND_TCHECK2(*p
, elem
->asnlen
);
567 elem
->type
= BE_UNS64
;
569 for (i
= elem
->asnlen
; i
-- > 0; p
++) {
571 ((low
& 0xFF000000) >> 24);
572 low
= (low
<< 8) | *p
;
574 elem
->data
.uns64
.high
= high
;
575 elem
->data
.uns64
.low
= low
;
580 elem
->type
= BE_OCTET
;
581 elem
->data
.raw
= (caddr_t
)p
;
582 ND_PRINT((ndo
, "[P/A/%s]",
583 Class
[class].Id
[id
]));
591 elem
->type
= BE_NOSUCHOBJECT
;
592 elem
->data
.raw
= NULL
;
596 elem
->type
= BE_NOSUCHINST
;
597 elem
->data
.raw
= NULL
;
601 elem
->type
= BE_ENDOFMIBVIEW
;
602 elem
->data
.raw
= NULL
;
608 ND_PRINT((ndo
, "[P/%s/%s]", Class
[class].name
, Class
[class].Id
[id
]));
609 ND_TCHECK2(*p
, elem
->asnlen
);
610 elem
->type
= BE_OCTET
;
611 elem
->data
.raw
= (caddr_t
)p
;
622 elem
->data
.raw
= (caddr_t
)p
;
626 elem
->type
= BE_OCTET
;
627 elem
->data
.raw
= (caddr_t
)p
;
628 ND_PRINT((ndo
, "C/U/%s", Class
[class].Id
[id
]));
635 elem
->data
.raw
= (caddr_t
)p
;
639 elem
->type
= BE_OCTET
;
640 elem
->data
.raw
= (caddr_t
)p
;
641 ND_PRINT((ndo
, "C/%s/%s", Class
[class].name
, Class
[class].Id
[id
]));
648 return elem
->asnlen
+ hdr
;
651 ND_PRINT((ndo
, "%s", tstr
));
656 * Display the ASN.1 object represented by the BE object.
657 * This used to be an integral part of asn1_parse() before the intermediate
661 asn1_print(netdissect_options
*ndo
,
664 u_char
*p
= (u_char
*)elem
->data
.raw
;
665 u_int32_t asnlen
= elem
->asnlen
;
668 switch (elem
->type
) {
671 ND_TCHECK2(*p
, asnlen
);
672 for (i
= asnlen
; i
-- > 0; p
++)
673 ND_PRINT((ndo
, "_%.2x", *p
));
680 int o
= 0, first
= -1, i
= asnlen
;
682 if (!ndo
->ndo_sflag
&& !ndo
->ndo_nflag
&& asnlen
> 2) {
683 const struct obj_abrev
*a
= &obj_abrev_list
[0];
684 size_t a_len
= strlen(a
->oid
);
685 for (; a
->node
; a
++) {
686 ND_TCHECK2(*p
, a_len
);
687 if (memcmp(a
->oid
, (char *)p
, a_len
) == 0) {
688 objp
= a
->node
->child
;
691 ND_PRINT((ndo
, "%s", a
->prefix
));
698 for (; !ndo
->ndo_sflag
&& i
-- > 0; p
++) {
700 o
= (o
<< ASN_SHIFT7
) + (*p
& ~ASN_BIT8
);
701 if (*p
& ASN_LONGLEN
)
705 * first subitem encodes two items with 1st*OIDMUX+2nd
706 * (see X.690:1997 clause 8.19 for the details)
727 ND_PRINT((ndo
, "%d", elem
->data
.integer
));
731 ND_PRINT((ndo
, "%u", elem
->data
.uns
));
734 case BE_UNS64
: { /* idea borrowed from by Marshall Rose */
737 char *cpf
, *cpl
, last
[6], first
[30];
738 if (elem
->data
.uns64
.high
== 0) {
739 ND_PRINT((ndo
, "%u", elem
->data
.uns64
.low
));
742 d
= elem
->data
.uns64
.high
* 4294967296.0; /* 2^32 */
743 if (elem
->data
.uns64
.high
<= 0x1fffff) {
744 d
+= elem
->data
.uns64
.low
;
745 #if 0 /*is looks illegal, but what is the intention?*/
746 ND_PRINT((ndo
, "%.f", d
));
748 ND_PRINT((ndo
, "%f", d
));
752 d
+= (elem
->data
.uns64
.low
& 0xfffff000);
753 #if 0 /*is looks illegal, but what is the intention?*/
754 snprintf(first
, sizeof(first
), "%.f", d
);
756 snprintf(first
, sizeof(first
), "%f", d
);
758 snprintf(last
, sizeof(last
), "%5.5d",
759 elem
->data
.uns64
.low
& 0xfff);
760 for (carry
= 0, cpf
= first
+strlen(first
)-1, cpl
= last
+4;
763 j
= carry
+ (*cpf
- '0') + (*cpl
- '0');
772 ND_PRINT((ndo
, "%s", first
));
777 register int printable
= 1, first
= 1;
778 const u_char
*p
= elem
->data
.str
;
779 ND_TCHECK2(*p
, asnlen
);
780 for (i
= asnlen
; printable
&& i
-- > 0; p
++)
781 printable
= ND_ISPRINT(*p
);
784 ND_PRINT((ndo
, "\""));
785 if (fn_printn(ndo
, p
, asnlen
, ndo
->ndo_snapend
)) {
786 ND_PRINT((ndo
, "\""));
789 ND_PRINT((ndo
, "\""));
791 for (i
= asnlen
; i
-- > 0; p
++) {
792 ND_PRINT((ndo
, first
? "%.2x" : "_%.2x", *p
));
799 ND_PRINT((ndo
, "Seq(%u)", elem
->asnlen
));
803 if (asnlen
!= ASNLEN_INETADDR
)
804 ND_PRINT((ndo
, "[inetaddr len!=%d]", ASNLEN_INETADDR
));
805 ND_TCHECK2(*p
, asnlen
);
806 for (i
= asnlen
; i
-- != 0; p
++) {
807 ND_PRINT((ndo
, (i
== asnlen
-1) ? "%u" : ".%u", *p
));
811 case BE_NOSUCHOBJECT
:
813 case BE_ENDOFMIBVIEW
:
814 ND_PRINT((ndo
, "[%s]", Class
[EXCEPTIONS
].Id
[elem
->id
]));
818 ND_PRINT((ndo
, "%s(%u)", Class
[CONTEXT
].Id
[elem
->id
], elem
->asnlen
));
822 ND_PRINT((ndo
, "[BE_ANY!?]"));
826 ND_PRINT((ndo
, "[be!?]"));
832 ND_PRINT((ndo
, "%s", tstr
));
838 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
839 * This will work for any ASN.1 stream, not just an SNMP PDU.
841 * By adding newlines and spaces at the correct places, this would print in
844 * This is not currently used.
847 asn1_decode(u_char
*p
, u_int length
)
852 while (i
>= 0 && length
> 0) {
853 i
= asn1_parse(ndo
, p
, length
, &elem
);
855 ND_PRINT((ndo
, " "));
856 if (asn1_print(ndo
, &elem
) < 0)
858 if (elem
.type
== BE_SEQ
|| elem
.type
== BE_PDU
) {
859 ND_PRINT((ndo
, " {"));
860 asn1_decode(elem
.data
.raw
, elem
.asnlen
);
861 ND_PRINT((ndo
, " }"));
873 SmiBasetype basetype
;
877 static const struct smi2be smi2betab
[] = {
878 { SMI_BASETYPE_INTEGER32
, BE_INT
},
879 { SMI_BASETYPE_OCTETSTRING
, BE_STR
},
880 { SMI_BASETYPE_OCTETSTRING
, BE_INETADDR
},
881 { SMI_BASETYPE_OBJECTIDENTIFIER
, BE_OID
},
882 { SMI_BASETYPE_UNSIGNED32
, BE_UNS
},
883 { SMI_BASETYPE_INTEGER64
, BE_NONE
},
884 { SMI_BASETYPE_UNSIGNED64
, BE_UNS64
},
885 { SMI_BASETYPE_FLOAT32
, BE_NONE
},
886 { SMI_BASETYPE_FLOAT64
, BE_NONE
},
887 { SMI_BASETYPE_FLOAT128
, BE_NONE
},
888 { SMI_BASETYPE_ENUM
, BE_INT
},
889 { SMI_BASETYPE_BITS
, BE_STR
},
890 { SMI_BASETYPE_UNKNOWN
, BE_NONE
}
894 smi_decode_oid(netdissect_options
*ndo
,
895 struct be
*elem
, unsigned int *oid
,
896 unsigned int oidsize
, unsigned int *oidlen
)
898 u_char
*p
= (u_char
*)elem
->data
.raw
;
899 u_int32_t asnlen
= elem
->asnlen
;
900 int o
= 0, first
= -1, i
= asnlen
;
902 for (*oidlen
= 0; ndo
->ndo_sflag
&& i
-- > 0; p
++) {
904 o
= (o
<< ASN_SHIFT7
) + (*p
& ~ASN_BIT8
);
905 if (*p
& ASN_LONGLEN
)
909 * first subitem encodes two items with 1st*OIDMUX+2nd
910 * (see X.690:1997 clause 8.19 for the details)
914 if (*oidlen
< oidsize
) {
915 oid
[*oidlen
] = o
/ OIDMUX
;
916 if (oid
[*oidlen
] > 2) oid
[*oidlen
] = 2;
918 o
-= oid
[*oidlen
] * OIDMUX
;
919 if (*oidlen
< oidsize
) (*oidlen
)++;
921 if (*oidlen
< oidsize
) {
922 oid
[(*oidlen
)++] = o
;
929 ND_PRINT((ndo
, "%s", tstr
));
933 static int smi_check_type(SmiBasetype basetype
, int be
)
937 for (i
= 0; smi2betab
[i
].basetype
!= SMI_BASETYPE_UNKNOWN
; i
++) {
938 if (smi2betab
[i
].basetype
== basetype
&& smi2betab
[i
].be
== be
) {
946 static int smi_check_a_range(SmiType
*smiType
, SmiRange
*smiRange
,
951 switch (smiType
->basetype
) {
952 case SMI_BASETYPE_OBJECTIDENTIFIER
:
953 case SMI_BASETYPE_OCTETSTRING
:
954 if (smiRange
->minValue
.value
.unsigned32
955 == smiRange
->maxValue
.value
.unsigned32
) {
956 ok
= (elem
->asnlen
== smiRange
->minValue
.value
.unsigned32
);
958 ok
= (elem
->asnlen
>= smiRange
->minValue
.value
.unsigned32
959 && elem
->asnlen
<= smiRange
->maxValue
.value
.unsigned32
);
963 case SMI_BASETYPE_INTEGER32
:
964 ok
= (elem
->data
.integer
>= smiRange
->minValue
.value
.integer32
965 && elem
->data
.integer
<= smiRange
->maxValue
.value
.integer32
);
968 case SMI_BASETYPE_UNSIGNED32
:
969 ok
= (elem
->data
.uns
>= smiRange
->minValue
.value
.unsigned32
970 && elem
->data
.uns
<= smiRange
->maxValue
.value
.unsigned32
);
973 case SMI_BASETYPE_UNSIGNED64
:
977 /* case SMI_BASETYPE_INTEGER64: SMIng */
978 /* case SMI_BASETYPE_FLOAT32: SMIng */
979 /* case SMI_BASETYPE_FLOAT64: SMIng */
980 /* case SMI_BASETYPE_FLOAT128: SMIng */
982 case SMI_BASETYPE_ENUM
:
983 case SMI_BASETYPE_BITS
:
984 case SMI_BASETYPE_UNKNOWN
:
996 static int smi_check_range(SmiType
*smiType
, struct be
*elem
)
1001 for (smiRange
= smiGetFirstRange(smiType
);
1003 smiRange
= smiGetNextRange(smiRange
)) {
1005 ok
= smi_check_a_range(smiType
, smiRange
, elem
);
1013 SmiType
*parentType
;
1014 parentType
= smiGetParentType(smiType
);
1016 ok
= smi_check_range(parentType
, elem
);
1024 smi_print_variable(netdissect_options
*ndo
,
1025 struct be
*elem
, int *status
)
1027 unsigned int oid
[128], oidlen
;
1028 SmiNode
*smiNode
= NULL
;
1031 *status
= smi_decode_oid(ndo
, elem
, oid
, sizeof(oid
) / sizeof(unsigned int),
1035 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1037 *status
= asn1_print(ndo
, elem
);
1040 if (ndo
->ndo_vflag
) {
1041 ND_PRINT((ndo
, "%s::", smiGetNodeModule(smiNode
)->name
));
1043 ND_PRINT((ndo
, "%s", smiNode
->name
));
1044 if (smiNode
->oidlen
< oidlen
) {
1045 for (i
= smiNode
->oidlen
; i
< oidlen
; i
++) {
1046 ND_PRINT((ndo
, ".%u", oid
[i
]));
1054 smi_print_value(netdissect_options
*ndo
,
1055 SmiNode
*smiNode
, u_char pduid
, struct be
*elem
)
1057 unsigned int i
, oid
[128], oidlen
;
1062 if (! smiNode
|| ! (smiNode
->nodekind
1063 & (SMI_NODEKIND_SCALAR
| SMI_NODEKIND_COLUMN
))) {
1064 return asn1_print(ndo
, elem
);
1067 if (elem
->type
== BE_NOSUCHOBJECT
1068 || elem
->type
== BE_NOSUCHINST
1069 || elem
->type
== BE_ENDOFMIBVIEW
) {
1070 return asn1_print(ndo
, elem
);
1073 if (NOTIFY_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_NOTIFY
) {
1074 ND_PRINT((ndo
, "[notNotifyable]"));
1077 if (READ_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_ONLY
) {
1078 ND_PRINT((ndo
, "[notReadable]"));
1081 if (WRITE_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_WRITE
) {
1082 ND_PRINT((ndo
, "[notWritable]"));
1085 if (RESPONSE_CLASS(pduid
)
1086 && smiNode
->access
== SMI_ACCESS_NOT_ACCESSIBLE
) {
1087 ND_PRINT((ndo
, "[noAccess]"));
1090 smiType
= smiGetNodeType(smiNode
);
1092 return asn1_print(ndo
, elem
);
1095 if (! smi_check_type(smiType
->basetype
, elem
->type
)) {
1096 ND_PRINT((ndo
, "[wrongType]"));
1099 if (! smi_check_range(smiType
, elem
)) {
1100 ND_PRINT((ndo
, "[outOfRange]"));
1103 /* resolve bits to named bits */
1105 /* check whether instance identifier is valid */
1107 /* apply display hints (integer, octetstring) */
1109 /* convert instance identifier to index type values */
1111 switch (elem
->type
) {
1113 if (smiType
->basetype
== SMI_BASETYPE_BITS
) {
1114 /* print bit labels */
1116 smi_decode_oid(ndo
, elem
, oid
,
1117 sizeof(oid
)/sizeof(unsigned int),
1119 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1121 if (ndo
->ndo_vflag
) {
1122 ND_PRINT((ndo
, "%s::", smiGetNodeModule(smiNode
)->name
));
1124 ND_PRINT((ndo
, "%s", smiNode
->name
));
1125 if (smiNode
->oidlen
< oidlen
) {
1126 for (i
= smiNode
->oidlen
;
1128 ND_PRINT((ndo
, ".%u", oid
[i
]));
1137 if (smiType
->basetype
== SMI_BASETYPE_ENUM
) {
1138 for (nn
= smiGetFirstNamedNumber(smiType
);
1140 nn
= smiGetNextNamedNumber(nn
)) {
1141 if (nn
->value
.value
.integer32
1142 == elem
->data
.integer
) {
1143 ND_PRINT((ndo
, "%s", nn
->name
));
1144 ND_PRINT((ndo
, "(%d)", elem
->data
.integer
));
1154 return asn1_print(ndo
, elem
);
1161 * General SNMP header
1163 * version INTEGER {version-1(0)},
1164 * community OCTET STRING,
1167 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1169 * request-id INTEGER,
1170 * error-status INTEGER,
1171 * error-index INTEGER,
1172 * varbindlist SEQUENCE OF
1180 * enterprise OBJECT IDENTIFIER,
1181 * agent-addr NetworkAddress,
1182 * generic-trap INTEGER,
1183 * specific-trap INTEGER,
1184 * time-stamp TimeTicks,
1185 * varbindlist SEQUENCE OF
1194 * Decode SNMP varBind
1197 varbind_print(netdissect_options
*ndo
,
1198 u_char pduid
, const u_char
*np
, u_int length
)
1203 SmiNode
*smiNode
= NULL
;
1207 /* Sequence of varBind */
1208 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1210 if (elem
.type
!= BE_SEQ
) {
1211 ND_PRINT((ndo
, "[!SEQ of varbind]"));
1212 asn1_print(ndo
, &elem
);
1215 if ((u_int
)count
< length
)
1216 ND_PRINT((ndo
, "[%d extra after SEQ of varbind]", length
- count
));
1218 length
= elem
.asnlen
;
1219 np
= (u_char
*)elem
.data
.raw
;
1221 for (ind
= 1; length
> 0; ind
++) {
1222 const u_char
*vbend
;
1225 ND_PRINT((ndo
, " "));
1228 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1230 if (elem
.type
!= BE_SEQ
) {
1231 ND_PRINT((ndo
, "[!varbind]"));
1232 asn1_print(ndo
, &elem
);
1236 vblength
= length
- count
;
1238 length
= elem
.asnlen
;
1239 np
= (u_char
*)elem
.data
.raw
;
1242 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1244 if (elem
.type
!= BE_OID
) {
1245 ND_PRINT((ndo
, "[objName!=OID]"));
1246 asn1_print(ndo
, &elem
);
1250 smiNode
= smi_print_variable(ndo
, &elem
, &status
);
1252 status
= asn1_print(ndo
, &elem
);
1259 if (pduid
!= GETREQ
&& pduid
!= GETNEXTREQ
1260 && pduid
!= GETBULKREQ
)
1261 ND_PRINT((ndo
, "="));
1264 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1266 if (pduid
== GETREQ
|| pduid
== GETNEXTREQ
1267 || pduid
== GETBULKREQ
) {
1268 if (elem
.type
!= BE_NULL
) {
1269 ND_PRINT((ndo
, "[objVal!=NULL]"));
1270 if (asn1_print(ndo
, &elem
) < 0)
1274 if (elem
.type
!= BE_NULL
) {
1276 status
= smi_print_value(ndo
, smiNode
, pduid
, &elem
);
1278 status
= asn1_print(ndo
, &elem
);
1290 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1291 * GetBulk, Inform, V2Trap, and Report
1294 snmppdu_print(netdissect_options
*ndo
,
1295 u_short pduid
, const u_char
*np
, u_int length
)
1298 int count
= 0, error
;
1300 /* reqId (Integer) */
1301 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1303 if (elem
.type
!= BE_INT
) {
1304 ND_PRINT((ndo
, "[reqId!=INT]"));
1305 asn1_print(ndo
, &elem
);
1309 ND_PRINT((ndo
, "R=%d ", elem
.data
.integer
));
1313 /* errorStatus (Integer) */
1314 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1316 if (elem
.type
!= BE_INT
) {
1317 ND_PRINT((ndo
, "[errorStatus!=INT]"));
1318 asn1_print(ndo
, &elem
);
1322 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1323 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1324 && elem
.data
.integer
!= 0) {
1326 ND_PRINT((ndo
, "[errorStatus(%s)!=0]",
1327 DECODE_ErrorStatus(elem
.data
.integer
)));
1328 } else if (pduid
== GETBULKREQ
) {
1329 ND_PRINT((ndo
, " N=%d", elem
.data
.integer
));
1330 } else if (elem
.data
.integer
!= 0) {
1332 ND_PRINT((ndo
, " %s", DECODE_ErrorStatus(elem
.data
.integer
)));
1333 error
= elem
.data
.integer
;
1338 /* errorIndex (Integer) */
1339 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1341 if (elem
.type
!= BE_INT
) {
1342 ND_PRINT((ndo
, "[errorIndex!=INT]"));
1343 asn1_print(ndo
, &elem
);
1346 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1347 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1348 && elem
.data
.integer
!= 0)
1349 ND_PRINT((ndo
, "[errorIndex(%d)!=0]", elem
.data
.integer
));
1350 else if (pduid
== GETBULKREQ
)
1351 ND_PRINT((ndo
, " M=%d", elem
.data
.integer
));
1352 else if (elem
.data
.integer
!= 0) {
1354 ND_PRINT((ndo
, "[errorIndex(%d) w/o errorStatus]", elem
.data
.integer
));
1356 ND_PRINT((ndo
, "@%d", elem
.data
.integer
));
1357 error
= elem
.data
.integer
;
1360 ND_PRINT((ndo
, "[errorIndex==0]"));
1366 varbind_print(ndo
, pduid
, np
, length
);
1371 * Decode SNMP Trap PDU
1374 trappdu_print(netdissect_options
*ndo
,
1375 const u_char
*np
, u_int length
)
1378 int count
= 0, generic
;
1380 ND_PRINT((ndo
, " "));
1382 /* enterprise (oid) */
1383 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1385 if (elem
.type
!= BE_OID
) {
1386 ND_PRINT((ndo
, "[enterprise!=OID]"));
1387 asn1_print(ndo
, &elem
);
1390 if (asn1_print(ndo
, &elem
) < 0)
1395 ND_PRINT((ndo
, " "));
1397 /* agent-addr (inetaddr) */
1398 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1400 if (elem
.type
!= BE_INETADDR
) {
1401 ND_PRINT((ndo
, "[agent-addr!=INETADDR]"));
1402 asn1_print(ndo
, &elem
);
1405 if (asn1_print(ndo
, &elem
) < 0)
1410 /* generic-trap (Integer) */
1411 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1413 if (elem
.type
!= BE_INT
) {
1414 ND_PRINT((ndo
, "[generic-trap!=INT]"));
1415 asn1_print(ndo
, &elem
);
1418 generic
= elem
.data
.integer
;
1421 ND_PRINT((ndo
, " %s", DECODE_GenericTrap(generic
)));
1426 /* specific-trap (Integer) */
1427 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1429 if (elem
.type
!= BE_INT
) {
1430 ND_PRINT((ndo
, "[specific-trap!=INT]"));
1431 asn1_print(ndo
, &elem
);
1434 if (generic
!= GT_ENTERPRISE
) {
1435 if (elem
.data
.integer
!= 0)
1436 ND_PRINT((ndo
, "[specific-trap(%d)!=0]", elem
.data
.integer
));
1438 ND_PRINT((ndo
, " s=%d", elem
.data
.integer
));
1442 ND_PRINT((ndo
, " "));
1444 /* time-stamp (TimeTicks) */
1445 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1447 if (elem
.type
!= BE_UNS
) { /* XXX */
1448 ND_PRINT((ndo
, "[time-stamp!=TIMETICKS]"));
1449 asn1_print(ndo
, &elem
);
1452 if (asn1_print(ndo
, &elem
) < 0)
1457 varbind_print(ndo
, TRAP
, np
, length
);
1462 * Decode arbitrary SNMP PDUs.
1465 pdu_print(netdissect_options
*ndo
,
1466 const u_char
*np
, u_int length
, int version
)
1472 if ((count
= asn1_parse(ndo
, np
, length
, &pdu
)) < 0)
1474 if (pdu
.type
!= BE_PDU
) {
1475 ND_PRINT((ndo
, "[no PDU]"));
1478 if ((u_int
)count
< length
)
1479 ND_PRINT((ndo
, "[%d extra after PDU]", length
- count
));
1480 if (ndo
->ndo_vflag
) {
1481 ND_PRINT((ndo
, "{ "));
1483 if (asn1_print(ndo
, &pdu
) < 0)
1485 ND_PRINT((ndo
, " "));
1486 /* descend into PDU */
1487 length
= pdu
.asnlen
;
1488 np
= (u_char
*)pdu
.data
.raw
;
1490 if (version
== SNMP_VERSION_1
&&
1491 (pdu
.id
== GETBULKREQ
|| pdu
.id
== INFORMREQ
||
1492 pdu
.id
== V2TRAP
|| pdu
.id
== REPORT
)) {
1493 ND_PRINT((ndo
, "[v2 PDU in v1 message]"));
1497 if (version
== SNMP_VERSION_2
&& pdu
.id
== TRAP
) {
1498 ND_PRINT((ndo
, "[v1 PDU in v2 message]"));
1504 trappdu_print(ndo
, np
, length
);
1514 snmppdu_print(ndo
, pdu
.id
, np
, length
);
1518 if (ndo
->ndo_vflag
) {
1519 ND_PRINT((ndo
, " } "));
1524 * Decode a scoped SNMP PDU.
1527 scopedpdu_print(netdissect_options
*ndo
,
1528 const u_char
*np
, u_int length
, int version
)
1534 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1536 if (elem
.type
!= BE_SEQ
) {
1537 ND_PRINT((ndo
, "[!scoped PDU]"));
1538 asn1_print(ndo
, &elem
);
1541 length
= elem
.asnlen
;
1542 np
= (u_char
*)elem
.data
.raw
;
1544 /* contextEngineID (OCTET STRING) */
1545 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1547 if (elem
.type
!= BE_STR
) {
1548 ND_PRINT((ndo
, "[contextEngineID!=STR]"));
1549 asn1_print(ndo
, &elem
);
1555 ND_PRINT((ndo
, "E= "));
1556 for (i
= 0; i
< (int)elem
.asnlen
; i
++) {
1557 ND_PRINT((ndo
, "0x%02X", elem
.data
.str
[i
]));
1559 ND_PRINT((ndo
, " "));
1561 /* contextName (OCTET STRING) */
1562 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1564 if (elem
.type
!= BE_STR
) {
1565 ND_PRINT((ndo
, "[contextName!=STR]"));
1566 asn1_print(ndo
, &elem
);
1572 ND_PRINT((ndo
, "C=%.*s ", (int)elem
.asnlen
, elem
.data
.str
));
1574 pdu_print(ndo
, np
, length
, version
);
1578 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1581 community_print(netdissect_options
*ndo
,
1582 const u_char
*np
, u_int length
, int version
)
1587 /* Community (String) */
1588 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1590 if (elem
.type
!= BE_STR
) {
1591 ND_PRINT((ndo
, "[comm!=STR]"));
1592 asn1_print(ndo
, &elem
);
1595 /* default community */
1596 if (!(elem
.asnlen
== sizeof(DEF_COMMUNITY
) - 1 &&
1597 strncmp((char *)elem
.data
.str
, DEF_COMMUNITY
,
1598 sizeof(DEF_COMMUNITY
) - 1) == 0))
1600 ND_PRINT((ndo
, "C=%.*s ", (int)elem
.asnlen
, elem
.data
.str
));
1604 pdu_print(ndo
, np
, length
, version
);
1608 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1611 usm_print(netdissect_options
*ndo
,
1612 const u_char
*np
, u_int length
)
1618 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1620 if (elem
.type
!= BE_SEQ
) {
1621 ND_PRINT((ndo
, "[!usm]"));
1622 asn1_print(ndo
, &elem
);
1625 length
= elem
.asnlen
;
1626 np
= (u_char
*)elem
.data
.raw
;
1628 /* msgAuthoritativeEngineID (OCTET STRING) */
1629 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1631 if (elem
.type
!= BE_STR
) {
1632 ND_PRINT((ndo
, "[msgAuthoritativeEngineID!=STR]"));
1633 asn1_print(ndo
, &elem
);
1639 /* msgAuthoritativeEngineBoots (INTEGER) */
1640 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1642 if (elem
.type
!= BE_INT
) {
1643 ND_PRINT((ndo
, "[msgAuthoritativeEngineBoots!=INT]"));
1644 asn1_print(ndo
, &elem
);
1648 ND_PRINT((ndo
, "B=%d ", elem
.data
.integer
));
1652 /* msgAuthoritativeEngineTime (INTEGER) */
1653 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1655 if (elem
.type
!= BE_INT
) {
1656 ND_PRINT((ndo
, "[msgAuthoritativeEngineTime!=INT]"));
1657 asn1_print(ndo
, &elem
);
1661 ND_PRINT((ndo
, "T=%d ", elem
.data
.integer
));
1665 /* msgUserName (OCTET STRING) */
1666 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1668 if (elem
.type
!= BE_STR
) {
1669 ND_PRINT((ndo
, "[msgUserName!=STR]"));
1670 asn1_print(ndo
, &elem
);
1676 ND_PRINT((ndo
, "U=%.*s ", (int)elem
.asnlen
, elem
.data
.str
));
1678 /* msgAuthenticationParameters (OCTET STRING) */
1679 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1681 if (elem
.type
!= BE_STR
) {
1682 ND_PRINT((ndo
, "[msgAuthenticationParameters!=STR]"));
1683 asn1_print(ndo
, &elem
);
1689 /* msgPrivacyParameters (OCTET STRING) */
1690 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1692 if (elem
.type
!= BE_STR
) {
1693 ND_PRINT((ndo
, "[msgPrivacyParameters!=STR]"));
1694 asn1_print(ndo
, &elem
);
1700 if ((u_int
)count
< length
)
1701 ND_PRINT((ndo
, "[%d extra after usm SEQ]", length
- count
));
1705 * Decode SNMPv3 Message Header (SNMPv3)
1708 v3msg_print(netdissect_options
*ndo
,
1709 const u_char
*np
, u_int length
)
1715 const u_char
*xnp
= np
;
1716 int xlength
= length
;
1719 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1721 if (elem
.type
!= BE_SEQ
) {
1722 ND_PRINT((ndo
, "[!message]"));
1723 asn1_print(ndo
, &elem
);
1726 length
= elem
.asnlen
;
1727 np
= (u_char
*)elem
.data
.raw
;
1729 if (ndo
->ndo_vflag
) {
1730 ND_PRINT((ndo
, "{ "));
1733 /* msgID (INTEGER) */
1734 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1736 if (elem
.type
!= BE_INT
) {
1737 ND_PRINT((ndo
, "[msgID!=INT]"));
1738 asn1_print(ndo
, &elem
);
1744 /* msgMaxSize (INTEGER) */
1745 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1747 if (elem
.type
!= BE_INT
) {
1748 ND_PRINT((ndo
, "[msgMaxSize!=INT]"));
1749 asn1_print(ndo
, &elem
);
1755 /* msgFlags (OCTET STRING) */
1756 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1758 if (elem
.type
!= BE_STR
) {
1759 ND_PRINT((ndo
, "[msgFlags!=STR]"));
1760 asn1_print(ndo
, &elem
);
1763 if (elem
.asnlen
!= 1) {
1764 ND_PRINT((ndo
, "[msgFlags size %d]", elem
.asnlen
));
1767 flags
= elem
.data
.str
[0];
1768 if (flags
!= 0x00 && flags
!= 0x01 && flags
!= 0x03
1769 && flags
!= 0x04 && flags
!= 0x05 && flags
!= 0x07) {
1770 ND_PRINT((ndo
, "[msgFlags=0x%02X]", flags
));
1776 ND_PRINT((ndo
, "F=%s%s%s ",
1777 flags
& 0x01 ? "a" : "",
1778 flags
& 0x02 ? "p" : "",
1779 flags
& 0x04 ? "r" : ""));
1781 /* msgSecurityModel (INTEGER) */
1782 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1784 if (elem
.type
!= BE_INT
) {
1785 ND_PRINT((ndo
, "[msgSecurityModel!=INT]"));
1786 asn1_print(ndo
, &elem
);
1789 model
= elem
.data
.integer
;
1793 if ((u_int
)count
< length
)
1794 ND_PRINT((ndo
, "[%d extra after message SEQ]", length
- count
));
1796 if (ndo
->ndo_vflag
) {
1797 ND_PRINT((ndo
, "} "));
1801 if (ndo
->ndo_vflag
) {
1802 ND_PRINT((ndo
, "{ USM "));
1805 ND_PRINT((ndo
, "[security model %d]", model
));
1809 np
= xnp
+ (np
- xnp
);
1810 length
= xlength
- (np
- xnp
);
1812 /* msgSecurityParameters (OCTET STRING) */
1813 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1815 if (elem
.type
!= BE_STR
) {
1816 ND_PRINT((ndo
, "[msgSecurityParameters!=STR]"));
1817 asn1_print(ndo
, &elem
);
1824 usm_print(ndo
, elem
.data
.str
, elem
.asnlen
);
1825 if (ndo
->ndo_vflag
) {
1826 ND_PRINT((ndo
, "} "));
1830 if (ndo
->ndo_vflag
) {
1831 ND_PRINT((ndo
, "{ ScopedPDU "));
1834 scopedpdu_print(ndo
, np
, length
, 3);
1836 if (ndo
->ndo_vflag
) {
1837 ND_PRINT((ndo
, "} "));
1842 * Decode SNMP header and pass on to PDU printing routines
1845 snmp_print(netdissect_options
*ndo
,
1846 const u_char
*np
, u_int length
)
1852 ND_PRINT((ndo
, " "));
1854 /* initial Sequence */
1855 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1857 if (elem
.type
!= BE_SEQ
) {
1858 ND_PRINT((ndo
, "[!init SEQ]"));
1859 asn1_print(ndo
, &elem
);
1862 if ((u_int
)count
< length
)
1863 ND_PRINT((ndo
, "[%d extra after iSEQ]", length
- count
));
1865 length
= elem
.asnlen
;
1866 np
= (u_char
*)elem
.data
.raw
;
1868 /* Version (INTEGER) */
1869 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1871 if (elem
.type
!= BE_INT
) {
1872 ND_PRINT((ndo
, "[version!=INT]"));
1873 asn1_print(ndo
, &elem
);
1877 switch (elem
.data
.integer
) {
1878 case SNMP_VERSION_1
:
1879 case SNMP_VERSION_2
:
1880 case SNMP_VERSION_3
:
1882 ND_PRINT((ndo
, "{ %s ", SnmpVersion
[elem
.data
.integer
]));
1885 ND_PRINT((ndo
, "[version = %d]", elem
.data
.integer
));
1888 version
= elem
.data
.integer
;
1893 case SNMP_VERSION_1
:
1894 case SNMP_VERSION_2
:
1895 community_print(ndo
, np
, length
, version
);
1897 case SNMP_VERSION_3
:
1898 v3msg_print(ndo
, np
, length
);
1901 ND_PRINT((ndo
, "[version = %d]", elem
.data
.integer
));
1905 if (ndo
->ndo_vflag
) {
1906 ND_PRINT((ndo
, "} "));