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 /* \summary: Simple Network Management Protocol (SNMP) printer */
65 #include <netdissect-stdinc.h>
74 #include "netdissect.h"
77 #undef OPAQUE /* defined in <wingdi.h> */
79 static const char tstr
[] = "[|snmp]";
82 * Universal ASN.1 types
83 * (we only care about the tag values for those allowed in the Internet SMI)
85 static const char *Universal
[] = {
98 "U-8","U-9","U-10","U-11", /* 8-11 */
99 "U-12","U-13","U-14","U-15", /* 12-15 */
106 * Application-wide ASN.1 types from the Internet SMI and their tags
108 static const char *Application
[] = {
125 * Context-specific ASN.1 types for the SNMP PDUs and their tags
127 static const char *Context
[] = {
148 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
149 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
150 #define WRITE_CLASS(x) (x == SETREQ)
151 #define RESPONSE_CLASS(x) (x == GETRESP)
152 #define INTERNAL_CLASS(x) (x == REPORT)
155 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
157 static const char *Exceptions
[] = {
159 #define NOSUCHOBJECT 0
161 #define NOSUCHINSTANCE 1
163 #define ENDOFMIBVIEW 2
167 * Private ASN.1 types
168 * The Internet SMI does not specify any
170 static const char *Private
[] = {
175 * error-status values for any SNMP PDU
177 static const char *ErrorStatus
[] = {
191 "resourceUnavailable",
194 "authorizationError",
198 #define DECODE_ErrorStatus(e) \
199 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
201 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
204 * generic-trap values in the SNMP Trap-PDU
206 static const char *GenericTrap
[] = {
211 "authenticationFailure",
214 #define GT_ENTERPRISE 6
216 #define DECODE_GenericTrap(t) \
217 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
219 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
222 * ASN.1 type class table
223 * Ties together the preceding Universal, Application, Context, and Private
226 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
227 static const struct {
232 defineCLASS(Universal
),
234 defineCLASS(Application
),
235 #define APPLICATION 1
236 defineCLASS(Context
),
238 defineCLASS(Private
),
240 defineCLASS(Exceptions
),
245 * defined forms for ASN.1 types
247 static const char *Form
[] = {
251 #define CONSTRUCTED 1
255 * A structure for the OID tree for the compiled-in MIB.
256 * This is stored as a general-order tree.
259 const char *desc
; /* name of object */
260 u_char oid
; /* sub-id following parent */
261 u_char type
; /* object type (unused) */
262 struct obj
*child
, *next
; /* child and next sibling pointers */
266 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
267 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
268 * a value for `mibroot'.
270 * In particular, this is gross, as this is including initialized structures,
271 * and by right shouldn't be an "include" file.
276 * This defines a list of OIDs which will be abbreviated on output.
277 * Currently, this includes the prefixes for the Internet MIB, the
278 * private enterprises tree, and the experimental tree.
280 #define OID_FIRST_OCTET(x, y) (((x)*40) + (y)) /* X.690 8.19.4 */
283 static const uint8_t mib_oid
[] = { OID_FIRST_OCTET(1, 3), 6, 1, 2, 1 };
285 #ifndef NO_ABREV_ENTER
286 static const uint8_t enterprises_oid
[] = { OID_FIRST_OCTET(1, 3), 6, 1, 4, 1 };
288 #ifndef NO_ABREV_EXPERI
289 static const uint8_t experimental_oid
[] = { OID_FIRST_OCTET(1, 3), 6, 1, 3 };
291 #ifndef NO_ABBREV_SNMPMODS
292 static const uint8_t snmpModules_oid
[] = { OID_FIRST_OCTET(1, 3), 6, 1, 6, 3 };
295 #define OBJ_ABBREV_ENTRY(prefix, obj) \
296 { prefix, &_ ## obj ## _obj, obj ## _oid, sizeof (obj ## _oid) }
297 static const struct obj_abrev
{
298 const char *prefix
; /* prefix for this abrev */
299 struct obj
*node
; /* pointer into object table */
300 const uint8_t *oid
; /* ASN.1 encoded OID */
301 size_t oid_len
; /* length of OID */
302 } obj_abrev_list
[] = {
304 /* .iso.org.dod.internet.mgmt.mib */
305 OBJ_ABBREV_ENTRY("", mib
),
307 #ifndef NO_ABREV_ENTER
308 /* .iso.org.dod.internet.private.enterprises */
309 OBJ_ABBREV_ENTRY("E:", enterprises
),
311 #ifndef NO_ABREV_EXPERI
312 /* .iso.org.dod.internet.experimental */
313 OBJ_ABBREV_ENTRY("X:", experimental
),
315 #ifndef NO_ABBREV_SNMPMODS
316 /* .iso.org.dod.internet.snmpV2.snmpModules */
317 OBJ_ABBREV_ENTRY("S:", snmpModules
),
323 * This is used in the OID print routine to walk down the object tree
324 * rooted at `mibroot'.
326 #define OBJ_PRINT(o, suppressdot) \
330 if ((o) == objp->oid) \
332 } while ((objp = objp->next) != NULL); \
335 ND_PRINT((ndo, suppressdot?"%s":".%s", objp->desc)); \
336 objp = objp->child; \
338 ND_PRINT((ndo, suppressdot?"%u":".%u", (o))); \
342 * This is the definition for the Any-Data-Type storage used purely for
343 * temporary internal representation while decoding an ASN.1 data stream.
355 u_char form
, class; /* tag info */
366 #define BE_INETADDR 8
369 #define BE_NOSUCHOBJECT 128
370 #define BE_NOSUCHINST 129
371 #define BE_ENDOFMIBVIEW 130
375 * SNMP versions recognized by this module
377 static const char *SnmpVersion
[] = {
379 #define SNMP_VERSION_1 0
381 #define SNMP_VERSION_2 1
383 #define SNMP_VERSION_2U 2
385 #define SNMP_VERSION_3 3
389 * Defaults for SNMP PDU components
391 #define DEF_COMMUNITY "public"
394 * constants for ASN.1 decoding
397 #define ASNLEN_INETADDR 4
400 #define ASN_BIT8 0x80
401 #define ASN_LONGLEN 0x80
403 #define ASN_ID_BITS 0x1f
404 #define ASN_FORM_BITS 0x20
405 #define ASN_FORM_SHIFT 5
406 #define ASN_CLASS_BITS 0xc0
407 #define ASN_CLASS_SHIFT 6
409 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
412 * This decodes the next ASN.1 object in the stream pointed to by "p"
413 * (and of real-length "len") and stores the intermediate data in the
414 * provided BE object.
416 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
417 * O/w, this returns the number of bytes parsed from "p".
420 asn1_parse(netdissect_options
*ndo
,
421 register const u_char
*p
, u_int len
, struct be
*elem
)
423 u_char form
, class, id
;
429 ND_PRINT((ndo
, "[nothing to parse]"));
435 * it would be nice to use a bit field, but you can't depend on them.
436 * +---+---+---+---+---+---+---+---+
438 * +---+---+---+---+---+---+---+---+
441 id
= EXTRACT_8BITS(p
) & ASN_ID_BITS
; /* lower 5 bits, range 00-1f */
443 form
= (*p
& 0xe0) >> 5; /* move upper 3 bits to lower 3 */
444 class = form
>> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
445 form
&= 0x1; /* bit 5 -> bit 0, range 0-1 */
447 form
= (u_char
)(*p
& ASN_FORM_BITS
) >> ASN_FORM_SHIFT
;
448 class = (u_char
)(*p
& ASN_CLASS_BITS
) >> ASN_CLASS_SHIFT
;
454 /* extended tag field */
455 if (id
== ASN_ID_EXT
) {
457 * The ID follows, as a sequence of octets with the
458 * 8th bit set and the remaining 7 bits being
459 * the next 7 bits of the value, terminated with
460 * an octet with the 8th bit not set.
462 * First, assemble all the octets with the 8th
463 * bit set. XXX - this doesn't handle a value
464 * that won't fit in 32 bits.
468 while (*p
& ASN_BIT8
) {
470 ND_PRINT((ndo
, "[Xtagfield?]"));
473 id
= (id
<< 7) | (*p
& ~ASN_BIT8
);
480 ND_PRINT((ndo
, "[Xtagfield?]"));
484 elem
->id
= id
= (id
<< 7) | *p
;
490 ND_PRINT((ndo
, "[no asnlen]"));
496 if (elem
->asnlen
& ASN_BIT8
) {
497 uint32_t noct
= elem
->asnlen
% ASN_BIT8
;
500 ND_PRINT((ndo
, "[asnlen? %d<%d]", len
, noct
));
503 ND_TCHECK2(*p
, noct
);
504 for (; noct
-- > 0; len
--, hdr
++)
505 elem
->asnlen
= (elem
->asnlen
<< ASN_SHIFT8
) | *p
++;
507 if (len
< elem
->asnlen
) {
508 ND_PRINT((ndo
, "[len%d<asnlen%u]", len
, elem
->asnlen
));
511 if (form
>= sizeof(Form
)/sizeof(Form
[0])) {
512 ND_PRINT((ndo
, "[form?%d]", form
));
515 if (class >= sizeof(Class
)/sizeof(Class
[0])) {
516 ND_PRINT((ndo
, "[class?%c/%d]", *Form
[form
], class));
519 if ((int)id
>= Class
[class].numIDs
) {
520 ND_PRINT((ndo
, "[id?%c/%s/%d]", *Form
[form
], Class
[class].name
, id
));
523 ND_TCHECK2(*p
, elem
->asnlen
);
536 register int32_t data
;
540 if (elem
->asnlen
== 0) {
541 ND_PRINT((ndo
, "[asnlen=0]"));
544 if (*p
& ASN_BIT8
) /* negative */
546 for (i
= elem
->asnlen
; i
-- > 0; p
++)
547 data
= (data
<< ASN_SHIFT8
) | *p
;
548 elem
->data
.integer
= data
;
554 elem
->data
.raw
= (const uint8_t *)p
;
558 elem
->type
= BE_NULL
;
559 elem
->data
.raw
= NULL
;
563 elem
->type
= BE_OCTET
;
564 elem
->data
.raw
= (const uint8_t *)p
;
565 ND_PRINT((ndo
, "[P/U/%s]", Class
[class].Id
[id
]));
573 elem
->type
= BE_INETADDR
;
574 elem
->data
.raw
= (const uint8_t *)p
;
580 register uint32_t data
;
583 for (i
= elem
->asnlen
; i
-- > 0; p
++)
584 data
= (data
<< 8) + *p
;
585 elem
->data
.uns
= data
;
590 register uint64_t data64
;
591 elem
->type
= BE_UNS64
;
593 for (i
= elem
->asnlen
; i
-- > 0; p
++)
594 data64
= (data64
<< 8) + *p
;
595 elem
->data
.uns64
= data64
;
600 elem
->type
= BE_OCTET
;
601 elem
->data
.raw
= (const uint8_t *)p
;
602 ND_PRINT((ndo
, "[P/A/%s]",
603 Class
[class].Id
[id
]));
611 elem
->type
= BE_NOSUCHOBJECT
;
612 elem
->data
.raw
= NULL
;
616 elem
->type
= BE_NOSUCHINST
;
617 elem
->data
.raw
= NULL
;
621 elem
->type
= BE_ENDOFMIBVIEW
;
622 elem
->data
.raw
= NULL
;
628 ND_PRINT((ndo
, "[P/%s/%s]", Class
[class].name
, Class
[class].Id
[id
]));
629 elem
->type
= BE_OCTET
;
630 elem
->data
.raw
= (const uint8_t *)p
;
641 elem
->data
.raw
= (const uint8_t *)p
;
645 elem
->type
= BE_OCTET
;
646 elem
->data
.raw
= (const uint8_t *)p
;
647 ND_PRINT((ndo
, "C/U/%s", Class
[class].Id
[id
]));
654 elem
->data
.raw
= (const uint8_t *)p
;
658 elem
->type
= BE_OCTET
;
659 elem
->data
.raw
= (const uint8_t *)p
;
660 ND_PRINT((ndo
, "C/%s/%s", Class
[class].name
, Class
[class].Id
[id
]));
667 return elem
->asnlen
+ hdr
;
670 ND_PRINT((ndo
, "%s", tstr
));
675 asn1_print_octets(netdissect_options
*ndo
, struct be
*elem
)
677 const u_char
*p
= (const u_char
*)elem
->data
.raw
;
678 uint32_t asnlen
= elem
->asnlen
;
681 ND_TCHECK2(*p
, asnlen
);
682 for (i
= asnlen
; i
-- > 0; p
++)
683 ND_PRINT((ndo
, "_%.2x", *p
));
687 ND_PRINT((ndo
, "%s", tstr
));
692 asn1_print_string(netdissect_options
*ndo
, struct be
*elem
)
694 register int printable
= 1, first
= 1;
696 uint32_t asnlen
= elem
->asnlen
;
700 ND_TCHECK2(*p
, asnlen
);
701 for (i
= asnlen
; printable
&& i
-- > 0; p
++)
702 printable
= ND_ISPRINT(*p
);
705 ND_PRINT((ndo
, "\""));
706 if (fn_printn(ndo
, p
, asnlen
, ndo
->ndo_snapend
)) {
707 ND_PRINT((ndo
, "\""));
710 ND_PRINT((ndo
, "\""));
712 for (i
= asnlen
; i
-- > 0; p
++) {
713 ND_PRINT((ndo
, first
? "%.2x" : "_%.2x", *p
));
720 ND_PRINT((ndo
, "%s", tstr
));
725 * Display the ASN.1 object represented by the BE object.
726 * This used to be an integral part of asn1_parse() before the intermediate
730 asn1_print(netdissect_options
*ndo
,
734 uint32_t asnlen
= elem
->asnlen
;
737 switch (elem
->type
) {
740 if (asn1_print_octets(ndo
, elem
) == -1)
748 int o
= 0, first
= -1;
750 p
= (const u_char
*)elem
->data
.raw
;
752 if (!ndo
->ndo_nflag
&& asnlen
> 2) {
753 const struct obj_abrev
*a
= &obj_abrev_list
[0];
754 for (; a
->node
; a
++) {
757 if (!ND_TTEST2(*p
, a
->oid_len
))
759 if (memcmp(a
->oid
, p
, a
->oid_len
) == 0) {
760 objp
= a
->node
->child
;
763 ND_PRINT((ndo
, "%s", a
->prefix
));
770 for (; i
-- > 0; p
++) {
772 o
= (o
<< ASN_SHIFT7
) + (*p
& ~ASN_BIT8
);
773 if (*p
& ASN_LONGLEN
)
777 * first subitem encodes two items with
779 * (see X.690:1997 clause 8.19 for the details)
800 ND_PRINT((ndo
, "%d", elem
->data
.integer
));
804 ND_PRINT((ndo
, "%u", elem
->data
.uns
));
808 ND_PRINT((ndo
, "%" PRIu64
, elem
->data
.uns64
));
812 if (asn1_print_string(ndo
, elem
) == -1)
817 ND_PRINT((ndo
, "Seq(%u)", elem
->asnlen
));
821 if (asnlen
!= ASNLEN_INETADDR
)
822 ND_PRINT((ndo
, "[inetaddr len!=%d]", ASNLEN_INETADDR
));
823 p
= (const u_char
*)elem
->data
.raw
;
824 ND_TCHECK2(*p
, asnlen
);
825 for (i
= asnlen
; i
-- != 0; p
++) {
826 ND_PRINT((ndo
, (i
== asnlen
-1) ? "%u" : ".%u", *p
));
830 case BE_NOSUCHOBJECT
:
832 case BE_ENDOFMIBVIEW
:
833 ND_PRINT((ndo
, "[%s]", Class
[EXCEPTIONS
].Id
[elem
->id
]));
837 ND_PRINT((ndo
, "%s(%u)", Class
[CONTEXT
].Id
[elem
->id
], elem
->asnlen
));
841 ND_PRINT((ndo
, "[BE_ANY!?]"));
845 ND_PRINT((ndo
, "[be!?]"));
851 ND_PRINT((ndo
, "%s", tstr
));
857 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
858 * This will work for any ASN.1 stream, not just an SNMP PDU.
860 * By adding newlines and spaces at the correct places, this would print in
863 * This is not currently used.
866 asn1_decode(u_char
*p
, u_int length
)
871 while (i
>= 0 && length
> 0) {
872 i
= asn1_parse(ndo
, p
, length
, &elem
);
874 ND_PRINT((ndo
, " "));
875 if (asn1_print(ndo
, &elem
) < 0)
877 if (elem
.type
== BE_SEQ
|| elem
.type
== BE_PDU
) {
878 ND_PRINT((ndo
, " {"));
879 asn1_decode(elem
.data
.raw
, elem
.asnlen
);
880 ND_PRINT((ndo
, " }"));
892 SmiBasetype basetype
;
896 static const struct smi2be smi2betab
[] = {
897 { SMI_BASETYPE_INTEGER32
, BE_INT
},
898 { SMI_BASETYPE_OCTETSTRING
, BE_STR
},
899 { SMI_BASETYPE_OCTETSTRING
, BE_INETADDR
},
900 { SMI_BASETYPE_OBJECTIDENTIFIER
, BE_OID
},
901 { SMI_BASETYPE_UNSIGNED32
, BE_UNS
},
902 { SMI_BASETYPE_INTEGER64
, BE_NONE
},
903 { SMI_BASETYPE_UNSIGNED64
, BE_UNS64
},
904 { SMI_BASETYPE_FLOAT32
, BE_NONE
},
905 { SMI_BASETYPE_FLOAT64
, BE_NONE
},
906 { SMI_BASETYPE_FLOAT128
, BE_NONE
},
907 { SMI_BASETYPE_ENUM
, BE_INT
},
908 { SMI_BASETYPE_BITS
, BE_STR
},
909 { SMI_BASETYPE_UNKNOWN
, BE_NONE
}
913 smi_decode_oid(netdissect_options
*ndo
,
914 struct be
*elem
, unsigned int *oid
,
915 unsigned int oidsize
, unsigned int *oidlen
)
917 const u_char
*p
= (const u_char
*)elem
->data
.raw
;
918 uint32_t asnlen
= elem
->asnlen
;
919 int o
= 0, first
= -1, i
= asnlen
;
920 unsigned int firstval
;
922 for (*oidlen
= 0; i
-- > 0; p
++) {
924 o
= (o
<< ASN_SHIFT7
) + (*p
& ~ASN_BIT8
);
925 if (*p
& ASN_LONGLEN
)
929 * first subitem encodes two items with 1st*OIDMUX+2nd
930 * (see X.690:1997 clause 8.19 for the details)
934 firstval
= o
/ OIDMUX
;
935 if (firstval
> 2) firstval
= 2;
936 o
-= firstval
* OIDMUX
;
937 if (*oidlen
< oidsize
) {
938 oid
[(*oidlen
)++] = firstval
;
941 if (*oidlen
< oidsize
) {
942 oid
[(*oidlen
)++] = o
;
949 ND_PRINT((ndo
, "%s", tstr
));
953 static int smi_check_type(SmiBasetype basetype
, int be
)
957 for (i
= 0; smi2betab
[i
].basetype
!= SMI_BASETYPE_UNKNOWN
; i
++) {
958 if (smi2betab
[i
].basetype
== basetype
&& smi2betab
[i
].be
== be
) {
966 static int smi_check_a_range(SmiType
*smiType
, SmiRange
*smiRange
,
971 switch (smiType
->basetype
) {
972 case SMI_BASETYPE_OBJECTIDENTIFIER
:
973 case SMI_BASETYPE_OCTETSTRING
:
974 if (smiRange
->minValue
.value
.unsigned32
975 == smiRange
->maxValue
.value
.unsigned32
) {
976 ok
= (elem
->asnlen
== smiRange
->minValue
.value
.unsigned32
);
978 ok
= (elem
->asnlen
>= smiRange
->minValue
.value
.unsigned32
979 && elem
->asnlen
<= smiRange
->maxValue
.value
.unsigned32
);
983 case SMI_BASETYPE_INTEGER32
:
984 ok
= (elem
->data
.integer
>= smiRange
->minValue
.value
.integer32
985 && elem
->data
.integer
<= smiRange
->maxValue
.value
.integer32
);
988 case SMI_BASETYPE_UNSIGNED32
:
989 ok
= (elem
->data
.uns
>= smiRange
->minValue
.value
.unsigned32
990 && elem
->data
.uns
<= smiRange
->maxValue
.value
.unsigned32
);
993 case SMI_BASETYPE_UNSIGNED64
:
997 /* case SMI_BASETYPE_INTEGER64: SMIng */
998 /* case SMI_BASETYPE_FLOAT32: SMIng */
999 /* case SMI_BASETYPE_FLOAT64: SMIng */
1000 /* case SMI_BASETYPE_FLOAT128: SMIng */
1002 case SMI_BASETYPE_ENUM
:
1003 case SMI_BASETYPE_BITS
:
1004 case SMI_BASETYPE_UNKNOWN
:
1016 static int smi_check_range(SmiType
*smiType
, struct be
*elem
)
1021 for (smiRange
= smiGetFirstRange(smiType
);
1023 smiRange
= smiGetNextRange(smiRange
)) {
1025 ok
= smi_check_a_range(smiType
, smiRange
, elem
);
1033 SmiType
*parentType
;
1034 parentType
= smiGetParentType(smiType
);
1036 ok
= smi_check_range(parentType
, elem
);
1044 smi_print_variable(netdissect_options
*ndo
,
1045 struct be
*elem
, int *status
)
1047 unsigned int oid
[128], oidlen
;
1048 SmiNode
*smiNode
= NULL
;
1051 if (!nd_smi_module_loaded
) {
1052 *status
= asn1_print(ndo
, elem
);
1055 *status
= smi_decode_oid(ndo
, elem
, oid
, sizeof(oid
) / sizeof(unsigned int),
1059 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1061 *status
= asn1_print(ndo
, elem
);
1064 if (ndo
->ndo_vflag
) {
1065 ND_PRINT((ndo
, "%s::", smiGetNodeModule(smiNode
)->name
));
1067 ND_PRINT((ndo
, "%s", smiNode
->name
));
1068 if (smiNode
->oidlen
< oidlen
) {
1069 for (i
= smiNode
->oidlen
; i
< oidlen
; i
++) {
1070 ND_PRINT((ndo
, ".%u", oid
[i
]));
1078 smi_print_value(netdissect_options
*ndo
,
1079 SmiNode
*smiNode
, u_short pduid
, struct be
*elem
)
1081 unsigned int i
, oid
[128], oidlen
;
1086 if (! smiNode
|| ! (smiNode
->nodekind
1087 & (SMI_NODEKIND_SCALAR
| SMI_NODEKIND_COLUMN
))) {
1088 return asn1_print(ndo
, elem
);
1091 if (elem
->type
== BE_NOSUCHOBJECT
1092 || elem
->type
== BE_NOSUCHINST
1093 || elem
->type
== BE_ENDOFMIBVIEW
) {
1094 return asn1_print(ndo
, elem
);
1097 if (NOTIFY_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_NOTIFY
) {
1098 ND_PRINT((ndo
, "[notNotifyable]"));
1101 if (READ_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_ONLY
) {
1102 ND_PRINT((ndo
, "[notReadable]"));
1105 if (WRITE_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_WRITE
) {
1106 ND_PRINT((ndo
, "[notWritable]"));
1109 if (RESPONSE_CLASS(pduid
)
1110 && smiNode
->access
== SMI_ACCESS_NOT_ACCESSIBLE
) {
1111 ND_PRINT((ndo
, "[noAccess]"));
1114 smiType
= smiGetNodeType(smiNode
);
1116 return asn1_print(ndo
, elem
);
1119 if (! smi_check_type(smiType
->basetype
, elem
->type
)) {
1120 ND_PRINT((ndo
, "[wrongType]"));
1123 if (! smi_check_range(smiType
, elem
)) {
1124 ND_PRINT((ndo
, "[outOfRange]"));
1127 /* resolve bits to named bits */
1129 /* check whether instance identifier is valid */
1131 /* apply display hints (integer, octetstring) */
1133 /* convert instance identifier to index type values */
1135 switch (elem
->type
) {
1137 if (smiType
->basetype
== SMI_BASETYPE_BITS
) {
1138 /* print bit labels */
1140 if (nd_smi_module_loaded
&&
1141 smi_decode_oid(ndo
, elem
, oid
,
1142 sizeof(oid
)/sizeof(unsigned int),
1144 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1146 if (ndo
->ndo_vflag
) {
1147 ND_PRINT((ndo
, "%s::", smiGetNodeModule(smiNode
)->name
));
1149 ND_PRINT((ndo
, "%s", smiNode
->name
));
1150 if (smiNode
->oidlen
< oidlen
) {
1151 for (i
= smiNode
->oidlen
;
1153 ND_PRINT((ndo
, ".%u", oid
[i
]));
1163 if (smiType
->basetype
== SMI_BASETYPE_ENUM
) {
1164 for (nn
= smiGetFirstNamedNumber(smiType
);
1166 nn
= smiGetNextNamedNumber(nn
)) {
1167 if (nn
->value
.value
.integer32
1168 == elem
->data
.integer
) {
1169 ND_PRINT((ndo
, "%s", nn
->name
));
1170 ND_PRINT((ndo
, "(%d)", elem
->data
.integer
));
1180 return asn1_print(ndo
, elem
);
1187 * General SNMP header
1189 * version INTEGER {version-1(0)},
1190 * community OCTET STRING,
1193 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1195 * request-id INTEGER,
1196 * error-status INTEGER,
1197 * error-index INTEGER,
1198 * varbindlist SEQUENCE OF
1206 * enterprise OBJECT IDENTIFIER,
1207 * agent-addr NetworkAddress,
1208 * generic-trap INTEGER,
1209 * specific-trap INTEGER,
1210 * time-stamp TimeTicks,
1211 * varbindlist SEQUENCE OF
1220 * Decode SNMP varBind
1223 varbind_print(netdissect_options
*ndo
,
1224 u_short pduid
, const u_char
*np
, u_int length
)
1229 SmiNode
*smiNode
= NULL
;
1233 /* Sequence of varBind */
1234 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1236 if (elem
.type
!= BE_SEQ
) {
1237 ND_PRINT((ndo
, "[!SEQ of varbind]"));
1238 asn1_print(ndo
, &elem
);
1241 if ((u_int
)count
< length
)
1242 ND_PRINT((ndo
, "[%d extra after SEQ of varbind]", length
- count
));
1244 length
= elem
.asnlen
;
1245 np
= (const u_char
*)elem
.data
.raw
;
1247 for (ind
= 1; length
> 0; ind
++) {
1248 const u_char
*vbend
;
1251 ND_PRINT((ndo
, " "));
1254 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1256 if (elem
.type
!= BE_SEQ
) {
1257 ND_PRINT((ndo
, "[!varbind]"));
1258 asn1_print(ndo
, &elem
);
1262 vblength
= length
- count
;
1264 length
= elem
.asnlen
;
1265 np
= (const u_char
*)elem
.data
.raw
;
1268 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1270 if (elem
.type
!= BE_OID
) {
1271 ND_PRINT((ndo
, "[objName!=OID]"));
1272 asn1_print(ndo
, &elem
);
1276 smiNode
= smi_print_variable(ndo
, &elem
, &status
);
1278 status
= asn1_print(ndo
, &elem
);
1285 if (pduid
!= GETREQ
&& pduid
!= GETNEXTREQ
1286 && pduid
!= GETBULKREQ
)
1287 ND_PRINT((ndo
, "="));
1290 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1292 if (pduid
== GETREQ
|| pduid
== GETNEXTREQ
1293 || pduid
== GETBULKREQ
) {
1294 if (elem
.type
!= BE_NULL
) {
1295 ND_PRINT((ndo
, "[objVal!=NULL]"));
1296 if (asn1_print(ndo
, &elem
) < 0)
1300 if (elem
.type
!= BE_NULL
) {
1302 status
= smi_print_value(ndo
, smiNode
, pduid
, &elem
);
1304 status
= asn1_print(ndo
, &elem
);
1316 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1317 * GetBulk, Inform, V2Trap, and Report
1320 snmppdu_print(netdissect_options
*ndo
,
1321 u_short pduid
, const u_char
*np
, u_int length
)
1324 int count
= 0, error_status
;
1326 /* reqId (Integer) */
1327 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1329 if (elem
.type
!= BE_INT
) {
1330 ND_PRINT((ndo
, "[reqId!=INT]"));
1331 asn1_print(ndo
, &elem
);
1335 ND_PRINT((ndo
, "R=%d ", elem
.data
.integer
));
1339 /* errorStatus (Integer) */
1340 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1342 if (elem
.type
!= BE_INT
) {
1343 ND_PRINT((ndo
, "[errorStatus!=INT]"));
1344 asn1_print(ndo
, &elem
);
1348 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1349 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1350 && elem
.data
.integer
!= 0) {
1352 ND_PRINT((ndo
, "[errorStatus(%s)!=0]",
1353 DECODE_ErrorStatus(elem
.data
.integer
)));
1354 } else if (pduid
== GETBULKREQ
) {
1355 ND_PRINT((ndo
, " N=%d", elem
.data
.integer
));
1356 } else if (elem
.data
.integer
!= 0) {
1358 ND_PRINT((ndo
, " %s", DECODE_ErrorStatus(elem
.data
.integer
)));
1359 error_status
= elem
.data
.integer
;
1364 /* errorIndex (Integer) */
1365 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1367 if (elem
.type
!= BE_INT
) {
1368 ND_PRINT((ndo
, "[errorIndex!=INT]"));
1369 asn1_print(ndo
, &elem
);
1372 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1373 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1374 && elem
.data
.integer
!= 0)
1375 ND_PRINT((ndo
, "[errorIndex(%d)!=0]", elem
.data
.integer
));
1376 else if (pduid
== GETBULKREQ
)
1377 ND_PRINT((ndo
, " M=%d", elem
.data
.integer
));
1378 else if (elem
.data
.integer
!= 0) {
1380 ND_PRINT((ndo
, "[errorIndex(%d) w/o errorStatus]", elem
.data
.integer
));
1382 ND_PRINT((ndo
, "@%d", elem
.data
.integer
));
1383 } else if (error_status
) {
1384 ND_PRINT((ndo
, "[errorIndex==0]"));
1389 varbind_print(ndo
, pduid
, np
, length
);
1394 * Decode SNMP Trap PDU
1397 trappdu_print(netdissect_options
*ndo
,
1398 const u_char
*np
, u_int length
)
1401 int count
= 0, generic
;
1403 ND_PRINT((ndo
, " "));
1405 /* enterprise (oid) */
1406 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1408 if (elem
.type
!= BE_OID
) {
1409 ND_PRINT((ndo
, "[enterprise!=OID]"));
1410 asn1_print(ndo
, &elem
);
1413 if (asn1_print(ndo
, &elem
) < 0)
1418 ND_PRINT((ndo
, " "));
1420 /* agent-addr (inetaddr) */
1421 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1423 if (elem
.type
!= BE_INETADDR
) {
1424 ND_PRINT((ndo
, "[agent-addr!=INETADDR]"));
1425 asn1_print(ndo
, &elem
);
1428 if (asn1_print(ndo
, &elem
) < 0)
1433 /* generic-trap (Integer) */
1434 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1436 if (elem
.type
!= BE_INT
) {
1437 ND_PRINT((ndo
, "[generic-trap!=INT]"));
1438 asn1_print(ndo
, &elem
);
1441 generic
= elem
.data
.integer
;
1444 ND_PRINT((ndo
, " %s", DECODE_GenericTrap(generic
)));
1449 /* specific-trap (Integer) */
1450 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1452 if (elem
.type
!= BE_INT
) {
1453 ND_PRINT((ndo
, "[specific-trap!=INT]"));
1454 asn1_print(ndo
, &elem
);
1457 if (generic
!= GT_ENTERPRISE
) {
1458 if (elem
.data
.integer
!= 0)
1459 ND_PRINT((ndo
, "[specific-trap(%d)!=0]", elem
.data
.integer
));
1461 ND_PRINT((ndo
, " s=%d", elem
.data
.integer
));
1465 ND_PRINT((ndo
, " "));
1467 /* time-stamp (TimeTicks) */
1468 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1470 if (elem
.type
!= BE_UNS
) { /* XXX */
1471 ND_PRINT((ndo
, "[time-stamp!=TIMETICKS]"));
1472 asn1_print(ndo
, &elem
);
1475 if (asn1_print(ndo
, &elem
) < 0)
1480 varbind_print(ndo
, TRAP
, np
, length
);
1485 * Decode arbitrary SNMP PDUs.
1488 pdu_print(netdissect_options
*ndo
,
1489 const u_char
*np
, u_int length
, int version
)
1495 if ((count
= asn1_parse(ndo
, np
, length
, &pdu
)) < 0)
1497 if (pdu
.type
!= BE_PDU
) {
1498 ND_PRINT((ndo
, "[no PDU]"));
1501 if ((u_int
)count
< length
)
1502 ND_PRINT((ndo
, "[%d extra after PDU]", length
- count
));
1503 if (ndo
->ndo_vflag
) {
1504 ND_PRINT((ndo
, "{ "));
1506 if (asn1_print(ndo
, &pdu
) < 0)
1508 ND_PRINT((ndo
, " "));
1509 /* descend into PDU */
1510 length
= pdu
.asnlen
;
1511 np
= (const u_char
*)pdu
.data
.raw
;
1513 if (version
== SNMP_VERSION_1
&&
1514 (pdu
.id
== GETBULKREQ
|| pdu
.id
== INFORMREQ
||
1515 pdu
.id
== V2TRAP
|| pdu
.id
== REPORT
)) {
1516 ND_PRINT((ndo
, "[v2 PDU in v1 message]"));
1520 if (version
== SNMP_VERSION_2
&& pdu
.id
== TRAP
) {
1521 ND_PRINT((ndo
, "[v1 PDU in v2 message]"));
1527 trappdu_print(ndo
, np
, length
);
1537 snmppdu_print(ndo
, pdu
.id
, np
, length
);
1541 if (ndo
->ndo_vflag
) {
1542 ND_PRINT((ndo
, " } "));
1547 * Decode a scoped SNMP PDU.
1550 scopedpdu_print(netdissect_options
*ndo
,
1551 const u_char
*np
, u_int length
, int version
)
1557 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1559 if (elem
.type
!= BE_SEQ
) {
1560 ND_PRINT((ndo
, "[!scoped PDU]"));
1561 asn1_print(ndo
, &elem
);
1564 length
= elem
.asnlen
;
1565 np
= (const u_char
*)elem
.data
.raw
;
1567 /* contextEngineID (OCTET STRING) */
1568 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1570 if (elem
.type
!= BE_STR
) {
1571 ND_PRINT((ndo
, "[contextEngineID!=STR]"));
1572 asn1_print(ndo
, &elem
);
1578 ND_PRINT((ndo
, "E="));
1579 if (asn1_print_octets(ndo
, &elem
) == -1)
1581 ND_PRINT((ndo
, " "));
1583 /* contextName (OCTET STRING) */
1584 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1586 if (elem
.type
!= BE_STR
) {
1587 ND_PRINT((ndo
, "[contextName!=STR]"));
1588 asn1_print(ndo
, &elem
);
1594 ND_PRINT((ndo
, "C="));
1595 if (asn1_print_string(ndo
, &elem
) == -1)
1597 ND_PRINT((ndo
, " "));
1599 pdu_print(ndo
, np
, length
, version
);
1603 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1606 community_print(netdissect_options
*ndo
,
1607 const u_char
*np
, u_int length
, int version
)
1612 /* Community (String) */
1613 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1615 if (elem
.type
!= BE_STR
) {
1616 ND_PRINT((ndo
, "[comm!=STR]"));
1617 asn1_print(ndo
, &elem
);
1620 /* default community */
1621 if (!(elem
.asnlen
== sizeof(DEF_COMMUNITY
) - 1 &&
1622 strncmp((const char *)elem
.data
.str
, DEF_COMMUNITY
,
1623 sizeof(DEF_COMMUNITY
) - 1) == 0)) {
1625 ND_PRINT((ndo
, "C="));
1626 if (asn1_print_string(ndo
, &elem
) == -1)
1628 ND_PRINT((ndo
, " "));
1633 pdu_print(ndo
, np
, length
, version
);
1637 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1640 usm_print(netdissect_options
*ndo
,
1641 const u_char
*np
, u_int length
)
1647 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1649 if (elem
.type
!= BE_SEQ
) {
1650 ND_PRINT((ndo
, "[!usm]"));
1651 asn1_print(ndo
, &elem
);
1654 length
= elem
.asnlen
;
1655 np
= (const u_char
*)elem
.data
.raw
;
1657 /* msgAuthoritativeEngineID (OCTET STRING) */
1658 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1660 if (elem
.type
!= BE_STR
) {
1661 ND_PRINT((ndo
, "[msgAuthoritativeEngineID!=STR]"));
1662 asn1_print(ndo
, &elem
);
1668 /* msgAuthoritativeEngineBoots (INTEGER) */
1669 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1671 if (elem
.type
!= BE_INT
) {
1672 ND_PRINT((ndo
, "[msgAuthoritativeEngineBoots!=INT]"));
1673 asn1_print(ndo
, &elem
);
1677 ND_PRINT((ndo
, "B=%d ", elem
.data
.integer
));
1681 /* msgAuthoritativeEngineTime (INTEGER) */
1682 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1684 if (elem
.type
!= BE_INT
) {
1685 ND_PRINT((ndo
, "[msgAuthoritativeEngineTime!=INT]"));
1686 asn1_print(ndo
, &elem
);
1690 ND_PRINT((ndo
, "T=%d ", elem
.data
.integer
));
1694 /* msgUserName (OCTET STRING) */
1695 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1697 if (elem
.type
!= BE_STR
) {
1698 ND_PRINT((ndo
, "[msgUserName!=STR]"));
1699 asn1_print(ndo
, &elem
);
1705 ND_PRINT((ndo
, "U="));
1706 if (asn1_print_string(ndo
, &elem
) == -1)
1708 ND_PRINT((ndo
, " "));
1710 /* msgAuthenticationParameters (OCTET STRING) */
1711 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1713 if (elem
.type
!= BE_STR
) {
1714 ND_PRINT((ndo
, "[msgAuthenticationParameters!=STR]"));
1715 asn1_print(ndo
, &elem
);
1721 /* msgPrivacyParameters (OCTET STRING) */
1722 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1724 if (elem
.type
!= BE_STR
) {
1725 ND_PRINT((ndo
, "[msgPrivacyParameters!=STR]"));
1726 asn1_print(ndo
, &elem
);
1732 if ((u_int
)count
< length
)
1733 ND_PRINT((ndo
, "[%d extra after usm SEQ]", length
- count
));
1737 * Decode SNMPv3 Message Header (SNMPv3)
1740 v3msg_print(netdissect_options
*ndo
,
1741 const u_char
*np
, u_int length
)
1747 const u_char
*xnp
= np
;
1748 int xlength
= length
;
1751 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1753 if (elem
.type
!= BE_SEQ
) {
1754 ND_PRINT((ndo
, "[!message]"));
1755 asn1_print(ndo
, &elem
);
1758 length
= elem
.asnlen
;
1759 np
= (const u_char
*)elem
.data
.raw
;
1761 if (ndo
->ndo_vflag
) {
1762 ND_PRINT((ndo
, "{ "));
1765 /* msgID (INTEGER) */
1766 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1768 if (elem
.type
!= BE_INT
) {
1769 ND_PRINT((ndo
, "[msgID!=INT]"));
1770 asn1_print(ndo
, &elem
);
1776 /* msgMaxSize (INTEGER) */
1777 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1779 if (elem
.type
!= BE_INT
) {
1780 ND_PRINT((ndo
, "[msgMaxSize!=INT]"));
1781 asn1_print(ndo
, &elem
);
1787 /* msgFlags (OCTET STRING) */
1788 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1790 if (elem
.type
!= BE_STR
) {
1791 ND_PRINT((ndo
, "[msgFlags!=STR]"));
1792 asn1_print(ndo
, &elem
);
1795 if (elem
.asnlen
!= 1) {
1796 ND_PRINT((ndo
, "[msgFlags size %d]", elem
.asnlen
));
1799 flags
= elem
.data
.str
[0];
1800 if (flags
!= 0x00 && flags
!= 0x01 && flags
!= 0x03
1801 && flags
!= 0x04 && flags
!= 0x05 && flags
!= 0x07) {
1802 ND_PRINT((ndo
, "[msgFlags=0x%02X]", flags
));
1808 ND_PRINT((ndo
, "F=%s%s%s ",
1809 flags
& 0x01 ? "a" : "",
1810 flags
& 0x02 ? "p" : "",
1811 flags
& 0x04 ? "r" : ""));
1813 /* msgSecurityModel (INTEGER) */
1814 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1816 if (elem
.type
!= BE_INT
) {
1817 ND_PRINT((ndo
, "[msgSecurityModel!=INT]"));
1818 asn1_print(ndo
, &elem
);
1821 model
= elem
.data
.integer
;
1825 if ((u_int
)count
< length
)
1826 ND_PRINT((ndo
, "[%d extra after message SEQ]", length
- count
));
1828 if (ndo
->ndo_vflag
) {
1829 ND_PRINT((ndo
, "} "));
1833 if (ndo
->ndo_vflag
) {
1834 ND_PRINT((ndo
, "{ USM "));
1837 ND_PRINT((ndo
, "[security model %d]", model
));
1841 np
= xnp
+ (np
- xnp
);
1842 length
= xlength
- (np
- xnp
);
1844 /* msgSecurityParameters (OCTET STRING) */
1845 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1847 if (elem
.type
!= BE_STR
) {
1848 ND_PRINT((ndo
, "[msgSecurityParameters!=STR]"));
1849 asn1_print(ndo
, &elem
);
1856 usm_print(ndo
, elem
.data
.str
, elem
.asnlen
);
1857 if (ndo
->ndo_vflag
) {
1858 ND_PRINT((ndo
, "} "));
1862 if (ndo
->ndo_vflag
) {
1863 ND_PRINT((ndo
, "{ ScopedPDU "));
1866 scopedpdu_print(ndo
, np
, length
, 3);
1868 if (ndo
->ndo_vflag
) {
1869 ND_PRINT((ndo
, "} "));
1874 * Decode SNMP header and pass on to PDU printing routines
1877 snmp_print(netdissect_options
*ndo
,
1878 const u_char
*np
, u_int length
)
1884 ND_PRINT((ndo
, " "));
1886 /* initial Sequence */
1887 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1889 if (elem
.type
!= BE_SEQ
) {
1890 ND_PRINT((ndo
, "[!init SEQ]"));
1891 asn1_print(ndo
, &elem
);
1894 if ((u_int
)count
< length
)
1895 ND_PRINT((ndo
, "[%d extra after iSEQ]", length
- count
));
1897 length
= elem
.asnlen
;
1898 np
= (const u_char
*)elem
.data
.raw
;
1900 /* Version (INTEGER) */
1901 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1903 if (elem
.type
!= BE_INT
) {
1904 ND_PRINT((ndo
, "[version!=INT]"));
1905 asn1_print(ndo
, &elem
);
1909 switch (elem
.data
.integer
) {
1910 case SNMP_VERSION_1
:
1911 case SNMP_VERSION_2
:
1912 case SNMP_VERSION_3
:
1914 ND_PRINT((ndo
, "{ %s ", SnmpVersion
[elem
.data
.integer
]));
1917 ND_PRINT((ndo
, "SNMP [version = %d]", elem
.data
.integer
));
1920 version
= elem
.data
.integer
;
1925 case SNMP_VERSION_1
:
1926 case SNMP_VERSION_2
:
1927 community_print(ndo
, np
, length
, version
);
1929 case SNMP_VERSION_3
:
1930 v3msg_print(ndo
, np
, length
);
1933 ND_PRINT((ndo
, "[version = %d]", elem
.data
.integer
));
1937 if (ndo
->ndo_vflag
) {
1938 ND_PRINT((ndo
, "} "));