xref: /netbsd-src/external/bsd/tcpdump/dist/print-snmp.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
30f74e101Schristos  *     John Robert LoVerso. All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that the following conditions
70f74e101Schristos  * are met:
80f74e101Schristos  *
90f74e101Schristos  * 1. Redistributions of source code must retain the above copyright
100f74e101Schristos  *    notice, this list of conditions and the following disclaimer.
110f74e101Schristos  *
120f74e101Schristos  * 2. Redistributions in binary form must reproduce the above copyright
130f74e101Schristos  *    notice, this list of conditions and the following disclaimer in the
140f74e101Schristos  *    documentation and/or other materials provided with the distribution.
150f74e101Schristos  *
160f74e101Schristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
170f74e101Schristos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
180f74e101Schristos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
190f74e101Schristos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
200f74e101Schristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
210f74e101Schristos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
220f74e101Schristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
230f74e101Schristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
240f74e101Schristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
250f74e101Schristos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260f74e101Schristos  *
270f74e101Schristos  *
280f74e101Schristos  * This implementation has been influenced by the CMU SNMP release,
290f74e101Schristos  * by Steve Waldbusser.  However, this shares no code with that system.
300f74e101Schristos  * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
310f74e101Schristos  * Earlier forms of this implementation were derived and/or inspired by an
320f74e101Schristos  * awk script originally written by C. Philip Wood of LANL (but later
330f74e101Schristos  * heavily modified by John Robert LoVerso).  The copyright notice for
340f74e101Schristos  * that work is preserved below, even though it may not rightly apply
350f74e101Schristos  * to this file.
360f74e101Schristos  *
370f74e101Schristos  * Support for SNMPv2c/SNMPv3 and the ability to link the module against
380f74e101Schristos  * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
390f74e101Schristos  *
400f74e101Schristos  * This started out as a very simple program, but the incremental decoding
410f74e101Schristos  * (into the BE structure) complicated things.
420f74e101Schristos  *
430f74e101Schristos  #			Los Alamos National Laboratory
440f74e101Schristos  #
450f74e101Schristos  #	Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
460f74e101Schristos  #	This software was produced under a U.S. Government contract
470f74e101Schristos  #	(W-7405-ENG-36) by Los Alamos National Laboratory, which is
480f74e101Schristos  #	operated by the	University of California for the U.S. Department
490f74e101Schristos  #	of Energy.  The U.S. Government is licensed to use, reproduce,
500f74e101Schristos  #	and distribute this software.  Permission is granted to the
510f74e101Schristos  #	public to copy and use this software without charge, provided
520f74e101Schristos  #	that this Notice and any statement of authorship are reproduced
530f74e101Schristos  #	on all copies.  Neither the Government nor the University makes
540f74e101Schristos  #	any warranty, express or implied, or assumes any liability or
550f74e101Schristos  #	responsibility for the use of this software.
560f74e101Schristos  #	@(#)snmp.awk.x	1.1 (LANL) 1/15/90
570f74e101Schristos  */
580f74e101Schristos 
5911b3aaa1Schristos #include <sys/cdefs.h>
600f74e101Schristos #ifndef lint
61*26ba0b50Schristos __RCSID("$NetBSD: print-snmp.c,v 1.8 2024/09/02 16:15:33 christos Exp $");
620f74e101Schristos #endif
630f74e101Schristos 
64dc860a36Sspz /* \summary: Simple Network Management Protocol (SNMP) printer */
65dc860a36Sspz 
66c74ad251Schristos #include <config.h>
670f74e101Schristos 
68c74ad251Schristos #include "netdissect-stdinc.h"
690f74e101Schristos 
700f74e101Schristos #include <stdio.h>
710f74e101Schristos #include <string.h>
72*26ba0b50Schristos #include <limits.h>
730f74e101Schristos 
74b3a00663Schristos #ifdef USE_LIBSMI
750f74e101Schristos #include <smi.h>
760f74e101Schristos #endif
770f74e101Schristos 
78c74ad251Schristos #include "netdissect-ctype.h"
79c74ad251Schristos 
80fdccd7e4Schristos #include "netdissect.h"
81c74ad251Schristos #include "extract.h"
820f74e101Schristos 
830f74e101Schristos #undef OPAQUE  /* defined in <wingdi.h> */
840f74e101Schristos 
85b3a00663Schristos 
860f74e101Schristos /*
870f74e101Schristos  * Universal ASN.1 types
880f74e101Schristos  * (we only care about the tag values for those allowed in the Internet SMI)
890f74e101Schristos  */
90b3a00663Schristos static const char *Universal[] = {
910f74e101Schristos 	"U-0",
920f74e101Schristos 	"Boolean",
930f74e101Schristos 	"Integer",
940f74e101Schristos #define INTEGER 2
950f74e101Schristos 	"Bitstring",
960f74e101Schristos 	"String",
970f74e101Schristos #define STRING 4
980f74e101Schristos 	"Null",
990f74e101Schristos #define ASN_NULL 5
1000f74e101Schristos 	"ObjID",
1010f74e101Schristos #define OBJECTID 6
1020f74e101Schristos 	"ObjectDes",
1030f74e101Schristos 	"U-8","U-9","U-10","U-11",	/* 8-11 */
1040f74e101Schristos 	"U-12","U-13","U-14","U-15",	/* 12-15 */
1050f74e101Schristos 	"Sequence",
1060f74e101Schristos #define SEQUENCE 16
1070f74e101Schristos 	"Set"
1080f74e101Schristos };
1090f74e101Schristos 
1100f74e101Schristos /*
1110f74e101Schristos  * Application-wide ASN.1 types from the Internet SMI and their tags
1120f74e101Schristos  */
113b3a00663Schristos static const char *Application[] = {
1140f74e101Schristos 	"IpAddress",
1150f74e101Schristos #define IPADDR 0
1160f74e101Schristos 	"Counter",
1170f74e101Schristos #define COUNTER 1
1180f74e101Schristos 	"Gauge",
1190f74e101Schristos #define GAUGE 2
1200f74e101Schristos 	"TimeTicks",
1210f74e101Schristos #define TIMETICKS 3
1220f74e101Schristos 	"Opaque",
1230f74e101Schristos #define OPAQUE 4
1240f74e101Schristos 	"C-5",
1250f74e101Schristos 	"Counter64"
1260f74e101Schristos #define COUNTER64 6
1270f74e101Schristos };
1280f74e101Schristos 
1290f74e101Schristos /*
1300f74e101Schristos  * Context-specific ASN.1 types for the SNMP PDUs and their tags
1310f74e101Schristos  */
132b3a00663Schristos static const char *Context[] = {
1330f74e101Schristos 	"GetRequest",
1340f74e101Schristos #define GETREQ 0
1350f74e101Schristos 	"GetNextRequest",
1360f74e101Schristos #define GETNEXTREQ 1
1370f74e101Schristos 	"GetResponse",
1380f74e101Schristos #define GETRESP 2
1390f74e101Schristos 	"SetRequest",
1400f74e101Schristos #define SETREQ 3
1410f74e101Schristos 	"Trap",
1420f74e101Schristos #define TRAP 4
1430f74e101Schristos 	"GetBulk",
1440f74e101Schristos #define GETBULKREQ 5
1450f74e101Schristos 	"Inform",
1460f74e101Schristos #define INFORMREQ 6
1470f74e101Schristos 	"V2Trap",
1480f74e101Schristos #define V2TRAP 7
1490f74e101Schristos 	"Report"
1500f74e101Schristos #define REPORT 8
1510f74e101Schristos };
1520f74e101Schristos 
1530f74e101Schristos #define NOTIFY_CLASS(x)	    (x == TRAP || x == V2TRAP || x == INFORMREQ)
1540f74e101Schristos #define READ_CLASS(x)       (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
1550f74e101Schristos #define WRITE_CLASS(x)	    (x == SETREQ)
1560f74e101Schristos #define RESPONSE_CLASS(x)   (x == GETRESP)
1570f74e101Schristos #define INTERNAL_CLASS(x)   (x == REPORT)
1580f74e101Schristos 
1590f74e101Schristos /*
1600f74e101Schristos  * Context-specific ASN.1 types for the SNMP Exceptions and their tags
1610f74e101Schristos  */
162b3a00663Schristos static const char *Exceptions[] = {
1630f74e101Schristos 	"noSuchObject",
1640f74e101Schristos #define NOSUCHOBJECT 0
1650f74e101Schristos 	"noSuchInstance",
1660f74e101Schristos #define NOSUCHINSTANCE 1
1670f74e101Schristos 	"endOfMibView",
1680f74e101Schristos #define ENDOFMIBVIEW 2
1690f74e101Schristos };
1700f74e101Schristos 
1710f74e101Schristos /*
1720f74e101Schristos  * Private ASN.1 types
1730f74e101Schristos  * The Internet SMI does not specify any
1740f74e101Schristos  */
175b3a00663Schristos static const char *Private[] = {
1760f74e101Schristos 	"P-0"
1770f74e101Schristos };
1780f74e101Schristos 
1790f74e101Schristos /*
1800f74e101Schristos  * error-status values for any SNMP PDU
1810f74e101Schristos  */
182b3a00663Schristos static const char *ErrorStatus[] = {
1830f74e101Schristos 	"noError",
1840f74e101Schristos 	"tooBig",
1850f74e101Schristos 	"noSuchName",
1860f74e101Schristos 	"badValue",
1870f74e101Schristos 	"readOnly",
1880f74e101Schristos 	"genErr",
1890f74e101Schristos 	"noAccess",
1900f74e101Schristos 	"wrongType",
1910f74e101Schristos 	"wrongLength",
1920f74e101Schristos 	"wrongEncoding",
1930f74e101Schristos 	"wrongValue",
1940f74e101Schristos 	"noCreation",
1950f74e101Schristos 	"inconsistentValue",
1960f74e101Schristos 	"resourceUnavailable",
1970f74e101Schristos 	"commitFailed",
1980f74e101Schristos 	"undoFailed",
1990f74e101Schristos 	"authorizationError",
2000f74e101Schristos 	"notWritable",
2010f74e101Schristos 	"inconsistentName"
2020f74e101Schristos };
2030f74e101Schristos #define DECODE_ErrorStatus(e) \
2040f74e101Schristos 	( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
2050f74e101Schristos 		? ErrorStatus[e] \
2060f74e101Schristos 		: (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
2070f74e101Schristos 
2080f74e101Schristos /*
2090f74e101Schristos  * generic-trap values in the SNMP Trap-PDU
2100f74e101Schristos  */
211b3a00663Schristos static const char *GenericTrap[] = {
2120f74e101Schristos 	"coldStart",
2130f74e101Schristos 	"warmStart",
2140f74e101Schristos 	"linkDown",
2150f74e101Schristos 	"linkUp",
2160f74e101Schristos 	"authenticationFailure",
2170f74e101Schristos 	"egpNeighborLoss",
2180f74e101Schristos 	"enterpriseSpecific"
2190f74e101Schristos #define GT_ENTERPRISE 6
2200f74e101Schristos };
2210f74e101Schristos #define DECODE_GenericTrap(t) \
2220f74e101Schristos 	( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
2230f74e101Schristos 		? GenericTrap[t] \
2240f74e101Schristos 		: (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
2250f74e101Schristos 
2260f74e101Schristos /*
2270f74e101Schristos  * ASN.1 type class table
2280f74e101Schristos  * Ties together the preceding Universal, Application, Context, and Private
2290f74e101Schristos  * type definitions.
2300f74e101Schristos  */
2310f74e101Schristos #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
232b3a00663Schristos static const struct {
2330f74e101Schristos 	const char	*name;
2340f74e101Schristos 	const char	**Id;
2350f74e101Schristos 	    int	numIDs;
2360f74e101Schristos     } Class[] = {
2370f74e101Schristos 	defineCLASS(Universal),
2380f74e101Schristos #define	UNIVERSAL	0
2390f74e101Schristos 	defineCLASS(Application),
2400f74e101Schristos #define	APPLICATION	1
2410f74e101Schristos 	defineCLASS(Context),
2420f74e101Schristos #define	CONTEXT		2
2430f74e101Schristos 	defineCLASS(Private),
2440f74e101Schristos #define	PRIVATE		3
2450f74e101Schristos 	defineCLASS(Exceptions),
2460f74e101Schristos #define EXCEPTIONS	4
2470f74e101Schristos };
2480f74e101Schristos 
2490f74e101Schristos /*
2500f74e101Schristos  * defined forms for ASN.1 types
2510f74e101Schristos  */
252b3a00663Schristos static const char *Form[] = {
2530f74e101Schristos 	"Primitive",
2540f74e101Schristos #define PRIMITIVE	0
2550f74e101Schristos 	"Constructed",
2560f74e101Schristos #define CONSTRUCTED	1
2570f74e101Schristos };
2580f74e101Schristos 
2590f74e101Schristos /*
2600f74e101Schristos  * A structure for the OID tree for the compiled-in MIB.
2610f74e101Schristos  * This is stored as a general-order tree.
2620f74e101Schristos  */
263dc860a36Sspz static struct obj {
2640f74e101Schristos 	const char	*desc;		/* name of object */
2650f74e101Schristos 	u_char	oid;			/* sub-id following parent */
2660f74e101Schristos 	u_char	type;			/* object type (unused) */
2670f74e101Schristos 	struct obj *child, *next;	/* child and next sibling pointers */
2680f74e101Schristos } *objp = NULL;
2690f74e101Schristos 
2700f74e101Schristos /*
2710f74e101Schristos  * Include the compiled in SNMP MIB.  "mib.h" is produced by feeding
2720f74e101Schristos  * RFC-1156 format files into "makemib".  "mib.h" MUST define at least
2730f74e101Schristos  * a value for `mibroot'.
2740f74e101Schristos  *
2750f74e101Schristos  * In particular, this is gross, as this is including initialized structures,
2760f74e101Schristos  * and by right shouldn't be an "include" file.
2770f74e101Schristos  */
2780f74e101Schristos #include "mib.h"
2790f74e101Schristos 
2800f74e101Schristos /*
2810f74e101Schristos  * This defines a list of OIDs which will be abbreviated on output.
2820f74e101Schristos  * Currently, this includes the prefixes for the Internet MIB, the
2830f74e101Schristos  * private enterprises tree, and the experimental tree.
2840f74e101Schristos  */
285dc860a36Sspz #define OID_FIRST_OCTET(x, y)	(((x)*40) + (y))	/* X.690 8.19.4 */
286dc860a36Sspz 
287dc860a36Sspz #ifndef NO_ABREV_MIB
288dc860a36Sspz static const uint8_t mib_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 2, 1 };
289dc860a36Sspz #endif
290dc860a36Sspz #ifndef NO_ABREV_ENTER
291dc860a36Sspz static const uint8_t enterprises_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 4, 1 };
292dc860a36Sspz #endif
293dc860a36Sspz #ifndef NO_ABREV_EXPERI
294dc860a36Sspz static const uint8_t experimental_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 3 };
295dc860a36Sspz #endif
296dc860a36Sspz #ifndef NO_ABBREV_SNMPMODS
297dc860a36Sspz static const uint8_t snmpModules_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 6, 3 };
298dc860a36Sspz #endif
299dc860a36Sspz 
300dc860a36Sspz #define OBJ_ABBREV_ENTRY(prefix, obj) \
301dc860a36Sspz 	{ prefix, &_ ## obj ## _obj, obj ## _oid, sizeof (obj ## _oid) }
302b3a00663Schristos static const struct obj_abrev {
3030f74e101Schristos 	const char *prefix;		/* prefix for this abrev */
3040f74e101Schristos 	struct obj *node;		/* pointer into object table */
305dc860a36Sspz 	const uint8_t *oid;		/* ASN.1 encoded OID */
306dc860a36Sspz 	size_t oid_len;			/* length of OID */
3070f74e101Schristos } obj_abrev_list[] = {
3080f74e101Schristos #ifndef NO_ABREV_MIB
3090f74e101Schristos 	/* .iso.org.dod.internet.mgmt.mib */
310dc860a36Sspz 	OBJ_ABBREV_ENTRY("",	mib),
3110f74e101Schristos #endif
3120f74e101Schristos #ifndef NO_ABREV_ENTER
3130f74e101Schristos 	/* .iso.org.dod.internet.private.enterprises */
314dc860a36Sspz 	OBJ_ABBREV_ENTRY("E:",	enterprises),
3150f74e101Schristos #endif
3160f74e101Schristos #ifndef NO_ABREV_EXPERI
3170f74e101Schristos 	/* .iso.org.dod.internet.experimental */
318dc860a36Sspz 	OBJ_ABBREV_ENTRY("X:",	experimental),
3190f74e101Schristos #endif
3200f74e101Schristos #ifndef NO_ABBREV_SNMPMODS
3210f74e101Schristos 	/* .iso.org.dod.internet.snmpV2.snmpModules */
322dc860a36Sspz 	OBJ_ABBREV_ENTRY("S:",	snmpModules),
3230f74e101Schristos #endif
324dc860a36Sspz 	{ 0,0,0,0 }
3250f74e101Schristos };
3260f74e101Schristos 
3270f74e101Schristos /*
3280f74e101Schristos  * This is used in the OID print routine to walk down the object tree
3290f74e101Schristos  * rooted at `mibroot'.
3300f74e101Schristos  */
3310f74e101Schristos #define OBJ_PRINT(o, suppressdot) \
3320f74e101Schristos { \
3330f74e101Schristos 	if (objp) { \
3340f74e101Schristos 		do { \
3350f74e101Schristos 			if ((o) == objp->oid) \
3360f74e101Schristos 				break; \
3370f74e101Schristos 		} while ((objp = objp->next) != NULL); \
3380f74e101Schristos 	} \
3390f74e101Schristos 	if (objp) { \
340c74ad251Schristos 		ND_PRINT(suppressdot?"%s":".%s", objp->desc); \
3410f74e101Schristos 		objp = objp->child; \
3420f74e101Schristos 	} else \
343c74ad251Schristos 		ND_PRINT(suppressdot?"%u":".%u", (o)); \
3440f74e101Schristos }
3450f74e101Schristos 
3460f74e101Schristos /*
3470f74e101Schristos  * This is the definition for the Any-Data-Type storage used purely for
3480f74e101Schristos  * temporary internal representation while decoding an ASN.1 data stream.
3490f74e101Schristos  */
3500f74e101Schristos struct be {
351b3a00663Schristos 	uint32_t asnlen;
3520f74e101Schristos 	union {
353fdccd7e4Schristos 		const uint8_t *raw;
3540f74e101Schristos 		int32_t integer;
355b3a00663Schristos 		uint32_t uns;
3560f74e101Schristos 		const u_char *str;
357dc860a36Sspz 		uint64_t uns64;
3580f74e101Schristos 	} data;
3590f74e101Schristos 	u_short id;
3600f74e101Schristos 	u_char form, class;		/* tag info */
3610f74e101Schristos 	u_char type;
3620f74e101Schristos #define BE_ANY		255
3630f74e101Schristos #define BE_NONE		0
3640f74e101Schristos #define BE_NULL		1
3650f74e101Schristos #define BE_OCTET	2
3660f74e101Schristos #define BE_OID		3
3670f74e101Schristos #define BE_INT		4
3680f74e101Schristos #define BE_UNS		5
3690f74e101Schristos #define BE_STR		6
3700f74e101Schristos #define BE_SEQ		7
3710f74e101Schristos #define BE_INETADDR	8
3720f74e101Schristos #define BE_PDU		9
3730f74e101Schristos #define BE_UNS64	10
3740f74e101Schristos #define BE_NOSUCHOBJECT	128
3750f74e101Schristos #define BE_NOSUCHINST	129
3760f74e101Schristos #define BE_ENDOFMIBVIEW	130
3770f74e101Schristos };
3780f74e101Schristos 
3790f74e101Schristos /*
3800f74e101Schristos  * SNMP versions recognized by this module
3810f74e101Schristos  */
382b3a00663Schristos static const char *SnmpVersion[] = {
3830f74e101Schristos 	"SNMPv1",
3840f74e101Schristos #define SNMP_VERSION_1	0
3850f74e101Schristos 	"SNMPv2c",
3860f74e101Schristos #define SNMP_VERSION_2	1
3870f74e101Schristos 	"SNMPv2u",
3880f74e101Schristos #define SNMP_VERSION_2U	2
3890f74e101Schristos 	"SNMPv3"
3900f74e101Schristos #define SNMP_VERSION_3	3
3910f74e101Schristos };
3920f74e101Schristos 
3930f74e101Schristos /*
3940f74e101Schristos  * Defaults for SNMP PDU components
3950f74e101Schristos  */
3960f74e101Schristos #define DEF_COMMUNITY "public"
3970f74e101Schristos 
3980f74e101Schristos /*
3990f74e101Schristos  * constants for ASN.1 decoding
4000f74e101Schristos  */
4010f74e101Schristos #define OIDMUX 40
4020f74e101Schristos #define ASNLEN_INETADDR 4
4030f74e101Schristos #define ASN_SHIFT7 7
4040f74e101Schristos #define ASN_SHIFT8 8
4050f74e101Schristos #define ASN_BIT8 0x80
4060f74e101Schristos #define ASN_LONGLEN 0x80
4070f74e101Schristos 
4080f74e101Schristos #define ASN_ID_BITS 0x1f
4090f74e101Schristos #define ASN_FORM_BITS 0x20
4100f74e101Schristos #define ASN_FORM_SHIFT 5
4110f74e101Schristos #define ASN_CLASS_BITS 0xc0
4120f74e101Schristos #define ASN_CLASS_SHIFT 6
4130f74e101Schristos 
4140f74e101Schristos #define ASN_ID_EXT 0x1f		/* extension ID in tag field */
4150f74e101Schristos 
4160f74e101Schristos /*
4170f74e101Schristos  * This decodes the next ASN.1 object in the stream pointed to by "p"
4180f74e101Schristos  * (and of real-length "len") and stores the intermediate data in the
4190f74e101Schristos  * provided BE object.
4200f74e101Schristos  *
4210f74e101Schristos  * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
4220f74e101Schristos  * O/w, this returns the number of bytes parsed from "p".
4230f74e101Schristos  */
4240f74e101Schristos static int
425b3a00663Schristos asn1_parse(netdissect_options *ndo,
426c74ad251Schristos            const u_char *p, u_int len, struct be *elem)
4270f74e101Schristos {
4280f74e101Schristos 	u_char form, class, id;
429c74ad251Schristos 	u_int i, hdr;
4300f74e101Schristos 
4310f74e101Schristos 	elem->asnlen = 0;
4320f74e101Schristos 	elem->type = BE_ANY;
4330f74e101Schristos 	if (len < 1) {
434c74ad251Schristos 		ND_PRINT("[nothing to parse]");
4350f74e101Schristos 		return -1;
4360f74e101Schristos 	}
4370f74e101Schristos 
4380f74e101Schristos 	/*
4390f74e101Schristos 	 * it would be nice to use a bit field, but you can't depend on them.
4400f74e101Schristos 	 *  +---+---+---+---+---+---+---+---+
4410f74e101Schristos 	 *  + class |frm|        id         |
4420f74e101Schristos 	 *  +---+---+---+---+---+---+---+---+
4430f74e101Schristos 	 *    7   6   5   4   3   2   1   0
4440f74e101Schristos 	 */
445c74ad251Schristos 	id = GET_U_1(p) & ASN_ID_BITS;		/* lower 5 bits, range 00-1f */
4460f74e101Schristos #ifdef notdef
447c74ad251Schristos 	form = (GET_U_1(p) & 0xe0) >> 5;	/* move upper 3 bits to lower 3 */
4480f74e101Schristos 	class = form >> 1;		/* bits 7&6 -> bits 1&0, range 0-3 */
4490f74e101Schristos 	form &= 0x1;			/* bit 5 -> bit 0, range 0-1 */
4500f74e101Schristos #else
451c74ad251Schristos 	form = (u_char)(GET_U_1(p) & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
452c74ad251Schristos 	class = (u_char)(GET_U_1(p) & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
4530f74e101Schristos #endif
4540f74e101Schristos 	elem->form = form;
4550f74e101Schristos 	elem->class = class;
4560f74e101Schristos 	elem->id = id;
4570f74e101Schristos 	p++; len--; hdr = 1;
4580f74e101Schristos 	/* extended tag field */
4590f74e101Schristos 	if (id == ASN_ID_EXT) {
4600f74e101Schristos 		/*
4610f74e101Schristos 		 * The ID follows, as a sequence of octets with the
4620f74e101Schristos 		 * 8th bit set and the remaining 7 bits being
4630f74e101Schristos 		 * the next 7 bits of the value, terminated with
4640f74e101Schristos 		 * an octet with the 8th bit not set.
4650f74e101Schristos 		 *
4660f74e101Schristos 		 * First, assemble all the octets with the 8th
4670f74e101Schristos 		 * bit set.  XXX - this doesn't handle a value
4680f74e101Schristos 		 * that won't fit in 32 bits.
4690f74e101Schristos 		 */
470dc860a36Sspz 		id = 0;
471c74ad251Schristos 		while (GET_U_1(p) & ASN_BIT8) {
4720f74e101Schristos 			if (len < 1) {
473c74ad251Schristos 				ND_PRINT("[Xtagfield?]");
4740f74e101Schristos 				return -1;
4750f74e101Schristos 			}
476c74ad251Schristos 			id = (id << 7) | (GET_U_1(p) & ~ASN_BIT8);
477dc860a36Sspz 			len--;
478dc860a36Sspz 			hdr++;
479dc860a36Sspz 			p++;
4800f74e101Schristos 		}
4810f74e101Schristos 		if (len < 1) {
482c74ad251Schristos 			ND_PRINT("[Xtagfield?]");
4830f74e101Schristos 			return -1;
4840f74e101Schristos 		}
485c74ad251Schristos 		elem->id = id = (id << 7) | GET_U_1(p);
4860f74e101Schristos 		--len;
4870f74e101Schristos 		++hdr;
4880f74e101Schristos 		++p;
4890f74e101Schristos 	}
4900f74e101Schristos 	if (len < 1) {
491c74ad251Schristos 		ND_PRINT("[no asnlen]");
4920f74e101Schristos 		return -1;
4930f74e101Schristos 	}
494c74ad251Schristos 	elem->asnlen = GET_U_1(p);
4950f74e101Schristos 	p++; len--; hdr++;
4960f74e101Schristos 	if (elem->asnlen & ASN_BIT8) {
497b3a00663Schristos 		uint32_t noct = elem->asnlen % ASN_BIT8;
4980f74e101Schristos 		elem->asnlen = 0;
4990f74e101Schristos 		if (len < noct) {
500c74ad251Schristos 			ND_PRINT("[asnlen? %d<%d]", len, noct);
5010f74e101Schristos 			return -1;
5020f74e101Schristos 		}
503c74ad251Schristos 		ND_TCHECK_LEN(p, noct);
504c74ad251Schristos 		for (; noct != 0; len--, hdr++, noct--) {
505c74ad251Schristos 			elem->asnlen = (elem->asnlen << ASN_SHIFT8) | GET_U_1(p);
506c74ad251Schristos 			p++;
507c74ad251Schristos 		}
5080f74e101Schristos 	}
5090f74e101Schristos 	if (len < elem->asnlen) {
510c74ad251Schristos 		ND_PRINT("[len%d<asnlen%u]", len, elem->asnlen);
5110f74e101Schristos 		return -1;
5120f74e101Schristos 	}
5130f74e101Schristos 	if (form >= sizeof(Form)/sizeof(Form[0])) {
514c74ad251Schristos 		ND_PRINT("[form?%d]", form);
5150f74e101Schristos 		return -1;
5160f74e101Schristos 	}
5170f74e101Schristos 	if (class >= sizeof(Class)/sizeof(Class[0])) {
518c74ad251Schristos 		ND_PRINT("[class?%c/%d]", *Form[form], class);
5190f74e101Schristos 		return -1;
5200f74e101Schristos 	}
5210f74e101Schristos 	if ((int)id >= Class[class].numIDs) {
522c74ad251Schristos 		ND_PRINT("[id?%c/%s/%d]", *Form[form], Class[class].name, id);
5230f74e101Schristos 		return -1;
5240f74e101Schristos 	}
525c74ad251Schristos 	ND_TCHECK_LEN(p, elem->asnlen);
5260f74e101Schristos 
5270f74e101Schristos 	switch (form) {
5280f74e101Schristos 	case PRIMITIVE:
5290f74e101Schristos 		switch (class) {
5300f74e101Schristos 		case UNIVERSAL:
5310f74e101Schristos 			switch (id) {
5320f74e101Schristos 			case STRING:
5330f74e101Schristos 				elem->type = BE_STR;
5340f74e101Schristos 				elem->data.str = p;
5350f74e101Schristos 				break;
5360f74e101Schristos 
5370f74e101Schristos 			case INTEGER: {
538*26ba0b50Schristos 				uint32_t data;
5390f74e101Schristos 				elem->type = BE_INT;
5400f74e101Schristos 				data = 0;
5410f74e101Schristos 
542dc860a36Sspz 				if (elem->asnlen == 0) {
543c74ad251Schristos 					ND_PRINT("[asnlen=0]");
544dc860a36Sspz 					return -1;
545dc860a36Sspz 				}
546c74ad251Schristos 				if (GET_U_1(p) & ASN_BIT8)	/* negative */
547*26ba0b50Schristos 					data = UINT_MAX;
548c74ad251Schristos 				for (i = elem->asnlen; i != 0; p++, i--)
549c74ad251Schristos 					data = (data << ASN_SHIFT8) | GET_U_1(p);
5500f74e101Schristos 				elem->data.integer = data;
5510f74e101Schristos 				break;
5520f74e101Schristos 			}
5530f74e101Schristos 
5540f74e101Schristos 			case OBJECTID:
5550f74e101Schristos 				elem->type = BE_OID;
556fdccd7e4Schristos 				elem->data.raw = (const uint8_t *)p;
5570f74e101Schristos 				break;
5580f74e101Schristos 
5590f74e101Schristos 			case ASN_NULL:
5600f74e101Schristos 				elem->type = BE_NULL;
5610f74e101Schristos 				elem->data.raw = NULL;
5620f74e101Schristos 				break;
5630f74e101Schristos 
5640f74e101Schristos 			default:
5650f74e101Schristos 				elem->type = BE_OCTET;
566fdccd7e4Schristos 				elem->data.raw = (const uint8_t *)p;
567c74ad251Schristos 				ND_PRINT("[P/U/%s]", Class[class].Id[id]);
5680f74e101Schristos 				break;
5690f74e101Schristos 			}
5700f74e101Schristos 			break;
5710f74e101Schristos 
5720f74e101Schristos 		case APPLICATION:
5730f74e101Schristos 			switch (id) {
5740f74e101Schristos 			case IPADDR:
5750f74e101Schristos 				elem->type = BE_INETADDR;
576fdccd7e4Schristos 				elem->data.raw = (const uint8_t *)p;
5770f74e101Schristos 				break;
5780f74e101Schristos 
5790f74e101Schristos 			case COUNTER:
5800f74e101Schristos 			case GAUGE:
5810f74e101Schristos 			case TIMETICKS: {
582c74ad251Schristos 				uint32_t data;
5830f74e101Schristos 				elem->type = BE_UNS;
5840f74e101Schristos 				data = 0;
585c74ad251Schristos 				for (i = elem->asnlen; i != 0; p++, i--)
586c74ad251Schristos 					data = (data << 8) + GET_U_1(p);
5870f74e101Schristos 				elem->data.uns = data;
5880f74e101Schristos 				break;
5890f74e101Schristos 			}
5900f74e101Schristos 
5910f74e101Schristos 			case COUNTER64: {
592c74ad251Schristos 				uint64_t data64;
5930f74e101Schristos 			        elem->type = BE_UNS64;
594dc860a36Sspz 				data64 = 0;
595c74ad251Schristos 				for (i = elem->asnlen; i != 0; p++, i--)
596c74ad251Schristos 					data64 = (data64 << 8) + GET_U_1(p);
597dc860a36Sspz 				elem->data.uns64 = data64;
5980f74e101Schristos 				break;
5990f74e101Schristos 			}
6000f74e101Schristos 
6010f74e101Schristos 			default:
6020f74e101Schristos 				elem->type = BE_OCTET;
603fdccd7e4Schristos 				elem->data.raw = (const uint8_t *)p;
604c74ad251Schristos 				ND_PRINT("[P/A/%s]",
605c74ad251Schristos 					Class[class].Id[id]);
6060f74e101Schristos 				break;
6070f74e101Schristos 			}
6080f74e101Schristos 			break;
6090f74e101Schristos 
6100f74e101Schristos 		case CONTEXT:
6110f74e101Schristos 			switch (id) {
6120f74e101Schristos 			case NOSUCHOBJECT:
6130f74e101Schristos 				elem->type = BE_NOSUCHOBJECT;
6140f74e101Schristos 				elem->data.raw = NULL;
6150f74e101Schristos 				break;
6160f74e101Schristos 
6170f74e101Schristos 			case NOSUCHINSTANCE:
6180f74e101Schristos 				elem->type = BE_NOSUCHINST;
6190f74e101Schristos 				elem->data.raw = NULL;
6200f74e101Schristos 				break;
6210f74e101Schristos 
6220f74e101Schristos 			case ENDOFMIBVIEW:
6230f74e101Schristos 				elem->type = BE_ENDOFMIBVIEW;
6240f74e101Schristos 				elem->data.raw = NULL;
6250f74e101Schristos 				break;
6260f74e101Schristos 			}
6270f74e101Schristos 			break;
6280f74e101Schristos 
6290f74e101Schristos 		default:
630c74ad251Schristos 			ND_PRINT("[P/%s/%s]", Class[class].name, Class[class].Id[id]);
6310f74e101Schristos 			elem->type = BE_OCTET;
632fdccd7e4Schristos 			elem->data.raw = (const uint8_t *)p;
6330f74e101Schristos 			break;
6340f74e101Schristos 		}
6350f74e101Schristos 		break;
6360f74e101Schristos 
6370f74e101Schristos 	case CONSTRUCTED:
6380f74e101Schristos 		switch (class) {
6390f74e101Schristos 		case UNIVERSAL:
6400f74e101Schristos 			switch (id) {
6410f74e101Schristos 			case SEQUENCE:
6420f74e101Schristos 				elem->type = BE_SEQ;
643fdccd7e4Schristos 				elem->data.raw = (const uint8_t *)p;
6440f74e101Schristos 				break;
6450f74e101Schristos 
6460f74e101Schristos 			default:
6470f74e101Schristos 				elem->type = BE_OCTET;
648fdccd7e4Schristos 				elem->data.raw = (const uint8_t *)p;
649c74ad251Schristos 				ND_PRINT("C/U/%s", Class[class].Id[id]);
6500f74e101Schristos 				break;
6510f74e101Schristos 			}
6520f74e101Schristos 			break;
6530f74e101Schristos 
6540f74e101Schristos 		case CONTEXT:
6550f74e101Schristos 			elem->type = BE_PDU;
656fdccd7e4Schristos 			elem->data.raw = (const uint8_t *)p;
6570f74e101Schristos 			break;
6580f74e101Schristos 
6590f74e101Schristos 		default:
6600f74e101Schristos 			elem->type = BE_OCTET;
661fdccd7e4Schristos 			elem->data.raw = (const uint8_t *)p;
662c74ad251Schristos 			ND_PRINT("C/%s/%s", Class[class].name, Class[class].Id[id]);
6630f74e101Schristos 			break;
6640f74e101Schristos 		}
6650f74e101Schristos 		break;
6660f74e101Schristos 	}
6670f74e101Schristos 	p += elem->asnlen;
6680f74e101Schristos 	len -= elem->asnlen;
6690f74e101Schristos 	return elem->asnlen + hdr;
6700f74e101Schristos 
6710f74e101Schristos trunc:
672c74ad251Schristos 	nd_print_trunc(ndo);
6730f74e101Schristos 	return -1;
6740f74e101Schristos }
6750f74e101Schristos 
676dc860a36Sspz static int
677dc860a36Sspz asn1_print_octets(netdissect_options *ndo, struct be *elem)
678dc860a36Sspz {
679dc860a36Sspz 	const u_char *p = (const u_char *)elem->data.raw;
680dc860a36Sspz 	uint32_t asnlen = elem->asnlen;
681dc860a36Sspz 	uint32_t i;
682dc860a36Sspz 
683c74ad251Schristos 	ND_TCHECK_LEN(p, asnlen);
684c74ad251Schristos 	for (i = asnlen; i != 0; p++, i--)
685c74ad251Schristos 		ND_PRINT("_%.2x", GET_U_1(p));
686dc860a36Sspz 	return 0;
687dc860a36Sspz 
688dc860a36Sspz trunc:
689c74ad251Schristos 	nd_print_trunc(ndo);
690dc860a36Sspz 	return -1;
691dc860a36Sspz }
692dc860a36Sspz 
693dc860a36Sspz static int
694dc860a36Sspz asn1_print_string(netdissect_options *ndo, struct be *elem)
695dc860a36Sspz {
696c74ad251Schristos 	int printable = 1, first = 1;
697dc860a36Sspz 	const u_char *p;
698dc860a36Sspz 	uint32_t asnlen = elem->asnlen;
699dc860a36Sspz 	uint32_t i;
700dc860a36Sspz 
701dc860a36Sspz 	p = elem->data.str;
702c74ad251Schristos 	ND_TCHECK_LEN(p, asnlen);
703c74ad251Schristos 	for (i = asnlen; printable && i != 0; p++, i--)
704c74ad251Schristos 		printable = ND_ASCII_ISPRINT(GET_U_1(p));
705dc860a36Sspz 	p = elem->data.str;
706dc860a36Sspz 	if (printable) {
707c74ad251Schristos 		ND_PRINT("\"");
708c74ad251Schristos 		if (nd_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
709c74ad251Schristos 			ND_PRINT("\"");
710dc860a36Sspz 			goto trunc;
711dc860a36Sspz 		}
712c74ad251Schristos 		ND_PRINT("\"");
713dc860a36Sspz 	} else {
714c74ad251Schristos 		for (i = asnlen; i != 0; p++, i--) {
715c74ad251Schristos 			ND_PRINT(first ? "%.2x" : "_%.2x", GET_U_1(p));
716dc860a36Sspz 			first = 0;
717dc860a36Sspz 		}
718dc860a36Sspz 	}
719dc860a36Sspz 	return 0;
720dc860a36Sspz 
721dc860a36Sspz trunc:
722c74ad251Schristos 	nd_print_trunc(ndo);
723dc860a36Sspz 	return -1;
724dc860a36Sspz }
725dc860a36Sspz 
7260f74e101Schristos /*
7270f74e101Schristos  * Display the ASN.1 object represented by the BE object.
7280f74e101Schristos  * This used to be an integral part of asn1_parse() before the intermediate
7290f74e101Schristos  * BE form was added.
7300f74e101Schristos  */
7310f74e101Schristos static int
732b3a00663Schristos asn1_print(netdissect_options *ndo,
733b3a00663Schristos            struct be *elem)
7340f74e101Schristos {
735dc860a36Sspz 	const u_char *p;
736b3a00663Schristos 	uint32_t asnlen = elem->asnlen;
737b3a00663Schristos 	uint32_t i;
7380f74e101Schristos 
7390f74e101Schristos 	switch (elem->type) {
7400f74e101Schristos 
7410f74e101Schristos 	case BE_OCTET:
742dc860a36Sspz 		if (asn1_print_octets(ndo, elem) == -1)
743dc860a36Sspz 			return -1;
7440f74e101Schristos 		break;
7450f74e101Schristos 
7460f74e101Schristos 	case BE_NULL:
7470f74e101Schristos 		break;
7480f74e101Schristos 
7490f74e101Schristos 	case BE_OID: {
750*26ba0b50Schristos 		int first = -1;
751*26ba0b50Schristos 		uint32_t o = 0;
7520f74e101Schristos 
753dc860a36Sspz 		p = (const u_char *)elem->data.raw;
754fdccd7e4Schristos 		i = asnlen;
755dc860a36Sspz 		if (!ndo->ndo_nflag && asnlen > 2) {
756b3a00663Schristos 			const struct obj_abrev *a = &obj_abrev_list[0];
7570f74e101Schristos 			for (; a->node; a++) {
758dc860a36Sspz 				if (i < a->oid_len)
759dc860a36Sspz 					continue;
760c74ad251Schristos 				if (!ND_TTEST_LEN(p, a->oid_len))
761dc860a36Sspz 					continue;
762dc860a36Sspz 				if (memcmp(a->oid, p, a->oid_len) == 0) {
7630f74e101Schristos 					objp = a->node->child;
764dc860a36Sspz 					i -= a->oid_len;
765dc860a36Sspz 					p += a->oid_len;
766c74ad251Schristos 					ND_PRINT("%s", a->prefix);
7670f74e101Schristos 					first = 1;
7680f74e101Schristos 					break;
7690f74e101Schristos 				}
7700f74e101Schristos 			}
7710f74e101Schristos 		}
7720f74e101Schristos 
773c74ad251Schristos 		for (; i != 0; p++, i--) {
774c74ad251Schristos 			o = (o << ASN_SHIFT7) + (GET_U_1(p) & ~ASN_BIT8);
775c74ad251Schristos 			if (GET_U_1(p) & ASN_LONGLEN)
7760f74e101Schristos 			        continue;
7770f74e101Schristos 
7780f74e101Schristos 			/*
779dc860a36Sspz 			 * first subitem encodes two items with
780dc860a36Sspz 			 * 1st*OIDMUX+2nd
7810f74e101Schristos 			 * (see X.690:1997 clause 8.19 for the details)
7820f74e101Schristos 			 */
7830f74e101Schristos 			if (first < 0) {
7840f74e101Schristos 			        int s;
785b3a00663Schristos 				if (!ndo->ndo_nflag)
7860f74e101Schristos 					objp = mibroot;
7870f74e101Schristos 				first = 0;
7880f74e101Schristos 				s = o / OIDMUX;
7890f74e101Schristos 				if (s > 2) s = 2;
7900f74e101Schristos 				OBJ_PRINT(s, first);
7910f74e101Schristos 				o -= s * OIDMUX;
7920f74e101Schristos 			}
7930f74e101Schristos 			OBJ_PRINT(o, first);
7940f74e101Schristos 			if (--first < 0)
7950f74e101Schristos 				first = 0;
7960f74e101Schristos 			o = 0;
7970f74e101Schristos 		}
7980f74e101Schristos 		break;
7990f74e101Schristos 	}
8000f74e101Schristos 
8010f74e101Schristos 	case BE_INT:
802c74ad251Schristos 		ND_PRINT("%d", elem->data.integer);
8030f74e101Schristos 		break;
8040f74e101Schristos 
8050f74e101Schristos 	case BE_UNS:
806c74ad251Schristos 		ND_PRINT("%u", elem->data.uns);
8070f74e101Schristos 		break;
8080f74e101Schristos 
809dc860a36Sspz 	case BE_UNS64:
810c74ad251Schristos 		ND_PRINT("%" PRIu64, elem->data.uns64);
8110f74e101Schristos 		break;
8120f74e101Schristos 
813dc860a36Sspz 	case BE_STR:
814dc860a36Sspz 		if (asn1_print_string(ndo, elem) == -1)
815dc860a36Sspz 			return -1;
8160f74e101Schristos 		break;
8170f74e101Schristos 
8180f74e101Schristos 	case BE_SEQ:
819c74ad251Schristos 		ND_PRINT("Seq(%u)", elem->asnlen);
8200f74e101Schristos 		break;
8210f74e101Schristos 
8220f74e101Schristos 	case BE_INETADDR:
8230f74e101Schristos 		if (asnlen != ASNLEN_INETADDR)
824c74ad251Schristos 			ND_PRINT("[inetaddr len!=%d]", ASNLEN_INETADDR);
825dc860a36Sspz 		p = (const u_char *)elem->data.raw;
826c74ad251Schristos 		ND_TCHECK_LEN(p, asnlen);
827c74ad251Schristos 		for (i = asnlen; i != 0; p++, i--) {
828c74ad251Schristos 			ND_PRINT((i == asnlen) ? "%u" : ".%u", GET_U_1(p));
8290f74e101Schristos 		}
8300f74e101Schristos 		break;
8310f74e101Schristos 
8320f74e101Schristos 	case BE_NOSUCHOBJECT:
8330f74e101Schristos 	case BE_NOSUCHINST:
8340f74e101Schristos 	case BE_ENDOFMIBVIEW:
835c74ad251Schristos 		ND_PRINT("[%s]", Class[EXCEPTIONS].Id[elem->id]);
8360f74e101Schristos 		break;
8370f74e101Schristos 
8380f74e101Schristos 	case BE_PDU:
839c74ad251Schristos 		ND_PRINT("%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen);
8400f74e101Schristos 		break;
8410f74e101Schristos 
8420f74e101Schristos 	case BE_ANY:
843c74ad251Schristos 		ND_PRINT("[BE_ANY!?]");
8440f74e101Schristos 		break;
8450f74e101Schristos 
8460f74e101Schristos 	default:
847c74ad251Schristos 		ND_PRINT("[be!?]");
8480f74e101Schristos 		break;
8490f74e101Schristos 	}
8500f74e101Schristos 	return 0;
8510f74e101Schristos 
8520f74e101Schristos trunc:
853c74ad251Schristos 	nd_print_trunc(ndo);
8540f74e101Schristos 	return -1;
8550f74e101Schristos }
8560f74e101Schristos 
8570f74e101Schristos #ifdef notdef
8580f74e101Schristos /*
8590f74e101Schristos  * This is a brute force ASN.1 printer: recurses to dump an entire structure.
8600f74e101Schristos  * This will work for any ASN.1 stream, not just an SNMP PDU.
8610f74e101Schristos  *
8620f74e101Schristos  * By adding newlines and spaces at the correct places, this would print in
8630f74e101Schristos  * Rose-Normal-Form.
8640f74e101Schristos  *
8650f74e101Schristos  * This is not currently used.
8660f74e101Schristos  */
8670f74e101Schristos static void
8680f74e101Schristos asn1_decode(u_char *p, u_int length)
8690f74e101Schristos {
8700f74e101Schristos 	struct be elem;
8710f74e101Schristos 	int i = 0;
8720f74e101Schristos 
8730f74e101Schristos 	while (i >= 0 && length > 0) {
874b3a00663Schristos 		i = asn1_parse(ndo, p, length, &elem);
8750f74e101Schristos 		if (i >= 0) {
876c74ad251Schristos 			ND_PRINT(" ");
877b3a00663Schristos 			if (asn1_print(ndo, &elem) < 0)
8780f74e101Schristos 				return;
8790f74e101Schristos 			if (elem.type == BE_SEQ || elem.type == BE_PDU) {
880c74ad251Schristos 				ND_PRINT(" {");
8810f74e101Schristos 				asn1_decode(elem.data.raw, elem.asnlen);
882c74ad251Schristos 				ND_PRINT(" }");
8830f74e101Schristos 			}
8840f74e101Schristos 			length -= i;
8850f74e101Schristos 			p += i;
8860f74e101Schristos 		}
8870f74e101Schristos 	}
8880f74e101Schristos }
8890f74e101Schristos #endif
8900f74e101Schristos 
891b3a00663Schristos #ifdef USE_LIBSMI
8920f74e101Schristos 
8930f74e101Schristos struct smi2be {
8940f74e101Schristos     SmiBasetype basetype;
8950f74e101Schristos     int be;
8960f74e101Schristos };
8970f74e101Schristos 
898b3a00663Schristos static const struct smi2be smi2betab[] = {
8990f74e101Schristos     { SMI_BASETYPE_INTEGER32,		BE_INT },
9000f74e101Schristos     { SMI_BASETYPE_OCTETSTRING,		BE_STR },
9010f74e101Schristos     { SMI_BASETYPE_OCTETSTRING,		BE_INETADDR },
9020f74e101Schristos     { SMI_BASETYPE_OBJECTIDENTIFIER,	BE_OID },
9030f74e101Schristos     { SMI_BASETYPE_UNSIGNED32,		BE_UNS },
9040f74e101Schristos     { SMI_BASETYPE_INTEGER64,		BE_NONE },
9050f74e101Schristos     { SMI_BASETYPE_UNSIGNED64,		BE_UNS64 },
9060f74e101Schristos     { SMI_BASETYPE_FLOAT32,		BE_NONE },
9070f74e101Schristos     { SMI_BASETYPE_FLOAT64,		BE_NONE },
9080f74e101Schristos     { SMI_BASETYPE_FLOAT128,		BE_NONE },
9090f74e101Schristos     { SMI_BASETYPE_ENUM,		BE_INT },
9100f74e101Schristos     { SMI_BASETYPE_BITS,		BE_STR },
9110f74e101Schristos     { SMI_BASETYPE_UNKNOWN,		BE_NONE }
9120f74e101Schristos };
9130f74e101Schristos 
9140f74e101Schristos static int
915b3a00663Schristos smi_decode_oid(netdissect_options *ndo,
916b3a00663Schristos                struct be *elem, unsigned int *oid,
9170f74e101Schristos                unsigned int oidsize, unsigned int *oidlen)
9180f74e101Schristos {
919fdccd7e4Schristos 	const u_char *p = (const u_char *)elem->data.raw;
920b3a00663Schristos 	uint32_t asnlen = elem->asnlen;
921c74ad251Schristos 	uint32_t i = asnlen;
922c74ad251Schristos 	int o = 0, first = -1;
923b3a00663Schristos 	unsigned int firstval;
9240f74e101Schristos 
925c74ad251Schristos 	for (*oidlen = 0; i != 0; p++, i--) {
926c74ad251Schristos 	        o = (o << ASN_SHIFT7) + (GET_U_1(p) & ~ASN_BIT8);
927c74ad251Schristos 		if (GET_U_1(p) & ASN_LONGLEN)
9280f74e101Schristos 		    continue;
9290f74e101Schristos 
9300f74e101Schristos 		/*
9310f74e101Schristos 		 * first subitem encodes two items with 1st*OIDMUX+2nd
9320f74e101Schristos 		 * (see X.690:1997 clause 8.19 for the details)
9330f74e101Schristos 		 */
9340f74e101Schristos 		if (first < 0) {
9350f74e101Schristos 			first = 0;
936b3a00663Schristos 			firstval = o / OIDMUX;
937b3a00663Schristos 			if (firstval > 2) firstval = 2;
938b3a00663Schristos 			o -= firstval * OIDMUX;
9390f74e101Schristos 			if (*oidlen < oidsize) {
940b3a00663Schristos 			    oid[(*oidlen)++] = firstval;
9410f74e101Schristos 			}
9420f74e101Schristos 		}
9430f74e101Schristos 		if (*oidlen < oidsize) {
9440f74e101Schristos 			oid[(*oidlen)++] = o;
9450f74e101Schristos 		}
9460f74e101Schristos 		o = 0;
9470f74e101Schristos 	}
9480f74e101Schristos 	return 0;
9490f74e101Schristos }
9500f74e101Schristos 
9510f74e101Schristos static int smi_check_type(SmiBasetype basetype, int be)
9520f74e101Schristos {
9530f74e101Schristos     int i;
9540f74e101Schristos 
9550f74e101Schristos     for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
9560f74e101Schristos 	if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
9570f74e101Schristos 	    return 1;
9580f74e101Schristos 	}
9590f74e101Schristos     }
9600f74e101Schristos 
9610f74e101Schristos     return 0;
9620f74e101Schristos }
9630f74e101Schristos 
9640f74e101Schristos static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
9650f74e101Schristos 			     struct be *elem)
9660f74e101Schristos {
9670f74e101Schristos     int ok = 1;
9680f74e101Schristos 
9690f74e101Schristos     switch (smiType->basetype) {
9700f74e101Schristos     case SMI_BASETYPE_OBJECTIDENTIFIER:
9710f74e101Schristos     case SMI_BASETYPE_OCTETSTRING:
9720f74e101Schristos 	if (smiRange->minValue.value.unsigned32
9730f74e101Schristos 	    == smiRange->maxValue.value.unsigned32) {
9740f74e101Schristos 	    ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
9750f74e101Schristos 	} else {
9760f74e101Schristos 	    ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
9770f74e101Schristos 		  && elem->asnlen <= smiRange->maxValue.value.unsigned32);
9780f74e101Schristos 	}
9790f74e101Schristos 	break;
9800f74e101Schristos 
9810f74e101Schristos     case SMI_BASETYPE_INTEGER32:
9820f74e101Schristos 	ok = (elem->data.integer >= smiRange->minValue.value.integer32
9830f74e101Schristos 	      && elem->data.integer <= smiRange->maxValue.value.integer32);
9840f74e101Schristos 	break;
9850f74e101Schristos 
9860f74e101Schristos     case SMI_BASETYPE_UNSIGNED32:
9870f74e101Schristos 	ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
9880f74e101Schristos 	      && elem->data.uns <= smiRange->maxValue.value.unsigned32);
9890f74e101Schristos 	break;
9900f74e101Schristos 
9910f74e101Schristos     case SMI_BASETYPE_UNSIGNED64:
9920f74e101Schristos 	/* XXX */
9930f74e101Schristos 	break;
9940f74e101Schristos 
9950f74e101Schristos 	/* case SMI_BASETYPE_INTEGER64: SMIng */
9960f74e101Schristos 	/* case SMI_BASETYPE_FLOAT32: SMIng */
9970f74e101Schristos 	/* case SMI_BASETYPE_FLOAT64: SMIng */
9980f74e101Schristos 	/* case SMI_BASETYPE_FLOAT128: SMIng */
9990f74e101Schristos 
10000f74e101Schristos     case SMI_BASETYPE_ENUM:
10010f74e101Schristos     case SMI_BASETYPE_BITS:
10020f74e101Schristos     case SMI_BASETYPE_UNKNOWN:
10030f74e101Schristos 	ok = 1;
10040f74e101Schristos 	break;
10050f74e101Schristos 
10060f74e101Schristos     default:
10070f74e101Schristos 	ok = 0;
10080f74e101Schristos 	break;
10090f74e101Schristos     }
10100f74e101Schristos 
10110f74e101Schristos     return ok;
10120f74e101Schristos }
10130f74e101Schristos 
10140f74e101Schristos static int smi_check_range(SmiType *smiType, struct be *elem)
10150f74e101Schristos {
10160f74e101Schristos         SmiRange *smiRange;
10170f74e101Schristos 	int ok = 1;
10180f74e101Schristos 
10190f74e101Schristos 	for (smiRange = smiGetFirstRange(smiType);
10200f74e101Schristos 	     smiRange;
10210f74e101Schristos 	     smiRange = smiGetNextRange(smiRange)) {
10220f74e101Schristos 
10230f74e101Schristos 	    ok = smi_check_a_range(smiType, smiRange, elem);
10240f74e101Schristos 
10250f74e101Schristos 	    if (ok) {
10260f74e101Schristos 		break;
10270f74e101Schristos 	    }
10280f74e101Schristos 	}
10290f74e101Schristos 
10300f74e101Schristos 	if (ok) {
10310f74e101Schristos 	    SmiType *parentType;
10320f74e101Schristos 	    parentType = smiGetParentType(smiType);
10330f74e101Schristos 	    if (parentType) {
10340f74e101Schristos 		ok = smi_check_range(parentType, elem);
10350f74e101Schristos 	    }
10360f74e101Schristos 	}
10370f74e101Schristos 
10380f74e101Schristos 	return ok;
10390f74e101Schristos }
10400f74e101Schristos 
1041b3a00663Schristos static SmiNode *
1042b3a00663Schristos smi_print_variable(netdissect_options *ndo,
1043b3a00663Schristos                    struct be *elem, int *status)
10440f74e101Schristos {
10450f74e101Schristos 	unsigned int oid[128], oidlen;
10460f74e101Schristos 	SmiNode *smiNode = NULL;
10470f74e101Schristos 	unsigned int i;
10480f74e101Schristos 
1049dc860a36Sspz 	if (!nd_smi_module_loaded) {
1050dc860a36Sspz 		*status = asn1_print(ndo, elem);
1051dc860a36Sspz 		return NULL;
1052dc860a36Sspz 	}
1053b3a00663Schristos 	*status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
10540f74e101Schristos 	    &oidlen);
10550f74e101Schristos 	if (*status < 0)
10560f74e101Schristos 		return NULL;
10570f74e101Schristos 	smiNode = smiGetNodeByOID(oidlen, oid);
10580f74e101Schristos 	if (! smiNode) {
1059b3a00663Schristos 		*status = asn1_print(ndo, elem);
10600f74e101Schristos 		return NULL;
10610f74e101Schristos 	}
1062b3a00663Schristos 	if (ndo->ndo_vflag) {
1063c74ad251Schristos 		ND_PRINT("%s::", smiGetNodeModule(smiNode)->name);
10640f74e101Schristos 	}
1065c74ad251Schristos 	ND_PRINT("%s", smiNode->name);
10660f74e101Schristos 	if (smiNode->oidlen < oidlen) {
10670f74e101Schristos 		for (i = smiNode->oidlen; i < oidlen; i++) {
1068c74ad251Schristos 			ND_PRINT(".%u", oid[i]);
10690f74e101Schristos 		}
10700f74e101Schristos 	}
10710f74e101Schristos 	*status = 0;
10720f74e101Schristos 	return smiNode;
10730f74e101Schristos }
10740f74e101Schristos 
10750f74e101Schristos static int
1076b3a00663Schristos smi_print_value(netdissect_options *ndo,
1077fdccd7e4Schristos                 SmiNode *smiNode, u_short pduid, struct be *elem)
10780f74e101Schristos {
10790f74e101Schristos 	unsigned int i, oid[128], oidlen;
10800f74e101Schristos 	SmiType *smiType;
10810f74e101Schristos 	SmiNamedNumber *nn;
10820f74e101Schristos 	int done = 0;
10830f74e101Schristos 
10840f74e101Schristos 	if (! smiNode || ! (smiNode->nodekind
10850f74e101Schristos 			    & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1086b3a00663Schristos 	    return asn1_print(ndo, elem);
10870f74e101Schristos 	}
10880f74e101Schristos 
10890f74e101Schristos 	if (elem->type == BE_NOSUCHOBJECT
10900f74e101Schristos 	    || elem->type == BE_NOSUCHINST
10910f74e101Schristos 	    || elem->type == BE_ENDOFMIBVIEW) {
1092b3a00663Schristos 	    return asn1_print(ndo, elem);
10930f74e101Schristos 	}
10940f74e101Schristos 
10950f74e101Schristos 	if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1096*26ba0b50Schristos 	    ND_PRINT("[notNotifiable]");
10970f74e101Schristos 	}
10980f74e101Schristos 
10990f74e101Schristos 	if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1100c74ad251Schristos 	    ND_PRINT("[notReadable]");
11010f74e101Schristos 	}
11020f74e101Schristos 
11030f74e101Schristos 	if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1104c74ad251Schristos 	    ND_PRINT("[notWritable]");
11050f74e101Schristos 	}
11060f74e101Schristos 
11070f74e101Schristos 	if (RESPONSE_CLASS(pduid)
11080f74e101Schristos 	    && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1109c74ad251Schristos 	    ND_PRINT("[noAccess]");
11100f74e101Schristos 	}
11110f74e101Schristos 
11120f74e101Schristos 	smiType = smiGetNodeType(smiNode);
11130f74e101Schristos 	if (! smiType) {
1114b3a00663Schristos 	    return asn1_print(ndo, elem);
11150f74e101Schristos 	}
11160f74e101Schristos 
11170f74e101Schristos 	if (! smi_check_type(smiType->basetype, elem->type)) {
1118c74ad251Schristos 	    ND_PRINT("[wrongType]");
11190f74e101Schristos 	}
11200f74e101Schristos 
11210f74e101Schristos 	if (! smi_check_range(smiType, elem)) {
1122c74ad251Schristos 	    ND_PRINT("[outOfRange]");
11230f74e101Schristos 	}
11240f74e101Schristos 
11250f74e101Schristos 	/* resolve bits to named bits */
11260f74e101Schristos 
11270f74e101Schristos 	/* check whether instance identifier is valid */
11280f74e101Schristos 
11290f74e101Schristos 	/* apply display hints (integer, octetstring) */
11300f74e101Schristos 
11310f74e101Schristos 	/* convert instance identifier to index type values */
11320f74e101Schristos 
11330f74e101Schristos 	switch (elem->type) {
11340f74e101Schristos 	case BE_OID:
11350f74e101Schristos 	        if (smiType->basetype == SMI_BASETYPE_BITS) {
11360f74e101Schristos 		        /* print bit labels */
11370f74e101Schristos 		} else {
1138dc860a36Sspz 			if (nd_smi_module_loaded &&
1139b3a00663Schristos 			    smi_decode_oid(ndo, elem, oid,
11400f74e101Schristos 					   sizeof(oid)/sizeof(unsigned int),
1141dc860a36Sspz 					   &oidlen) == 0) {
11420f74e101Schristos 				smiNode = smiGetNodeByOID(oidlen, oid);
11430f74e101Schristos 				if (smiNode) {
1144b3a00663Schristos 				        if (ndo->ndo_vflag) {
1145c74ad251Schristos 						ND_PRINT("%s::", smiGetNodeModule(smiNode)->name);
11460f74e101Schristos 					}
1147c74ad251Schristos 					ND_PRINT("%s", smiNode->name);
11480f74e101Schristos 					if (smiNode->oidlen < oidlen) {
11490f74e101Schristos 					        for (i = smiNode->oidlen;
11500f74e101Schristos 						     i < oidlen; i++) {
1151c74ad251Schristos 						        ND_PRINT(".%u", oid[i]);
11520f74e101Schristos 						}
11530f74e101Schristos 					}
11540f74e101Schristos 					done++;
11550f74e101Schristos 				}
11560f74e101Schristos 			}
1157dc860a36Sspz 		}
11580f74e101Schristos 		break;
11590f74e101Schristos 
11600f74e101Schristos 	case BE_INT:
11610f74e101Schristos 	        if (smiType->basetype == SMI_BASETYPE_ENUM) {
11620f74e101Schristos 		        for (nn = smiGetFirstNamedNumber(smiType);
11630f74e101Schristos 			     nn;
11640f74e101Schristos 			     nn = smiGetNextNamedNumber(nn)) {
11650f74e101Schristos 			         if (nn->value.value.integer32
11660f74e101Schristos 				     == elem->data.integer) {
1167c74ad251Schristos 				         ND_PRINT("%s", nn->name);
1168c74ad251Schristos 					 ND_PRINT("(%d)", elem->data.integer);
11690f74e101Schristos 					 done++;
11700f74e101Schristos 					 break;
11710f74e101Schristos 				}
11720f74e101Schristos 			}
11730f74e101Schristos 		}
11740f74e101Schristos 		break;
11750f74e101Schristos 	}
11760f74e101Schristos 
11770f74e101Schristos 	if (! done) {
1178b3a00663Schristos 		return asn1_print(ndo, elem);
11790f74e101Schristos 	}
11800f74e101Schristos 	return 0;
11810f74e101Schristos }
11820f74e101Schristos #endif
11830f74e101Schristos 
11840f74e101Schristos /*
11850f74e101Schristos  * General SNMP header
11860f74e101Schristos  *	SEQUENCE {
11870f74e101Schristos  *		version INTEGER {version-1(0)},
11880f74e101Schristos  *		community OCTET STRING,
11890f74e101Schristos  *		data ANY	-- PDUs
11900f74e101Schristos  *	}
11910f74e101Schristos  * PDUs for all but Trap: (see rfc1157 from page 15 on)
11920f74e101Schristos  *	SEQUENCE {
11930f74e101Schristos  *		request-id INTEGER,
11940f74e101Schristos  *		error-status INTEGER,
11950f74e101Schristos  *		error-index INTEGER,
11960f74e101Schristos  *		varbindlist SEQUENCE OF
11970f74e101Schristos  *			SEQUENCE {
11980f74e101Schristos  *				name ObjectName,
11990f74e101Schristos  *				value ObjectValue
12000f74e101Schristos  *			}
12010f74e101Schristos  *	}
12020f74e101Schristos  * PDU for Trap:
12030f74e101Schristos  *	SEQUENCE {
12040f74e101Schristos  *		enterprise OBJECT IDENTIFIER,
12050f74e101Schristos  *		agent-addr NetworkAddress,
12060f74e101Schristos  *		generic-trap INTEGER,
12070f74e101Schristos  *		specific-trap INTEGER,
12080f74e101Schristos  *		time-stamp TimeTicks,
12090f74e101Schristos  *		varbindlist SEQUENCE OF
12100f74e101Schristos  *			SEQUENCE {
12110f74e101Schristos  *				name ObjectName,
12120f74e101Schristos  *				value ObjectValue
12130f74e101Schristos  *			}
12140f74e101Schristos  *	}
12150f74e101Schristos  */
12160f74e101Schristos 
12170f74e101Schristos /*
12180f74e101Schristos  * Decode SNMP varBind
12190f74e101Schristos  */
12200f74e101Schristos static void
1221b3a00663Schristos varbind_print(netdissect_options *ndo,
1222fdccd7e4Schristos               u_short pduid, const u_char *np, u_int length)
12230f74e101Schristos {
12240f74e101Schristos 	struct be elem;
1225c74ad251Schristos 	int count = 0;
1226b3a00663Schristos #ifdef USE_LIBSMI
12270f74e101Schristos 	SmiNode *smiNode = NULL;
12280f74e101Schristos #endif
12290f74e101Schristos 	int status;
12300f74e101Schristos 
12310f74e101Schristos 	/* Sequence of varBind */
1232b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
12330f74e101Schristos 		return;
12340f74e101Schristos 	if (elem.type != BE_SEQ) {
1235c74ad251Schristos 		ND_PRINT("[!SEQ of varbind]");
1236b3a00663Schristos 		asn1_print(ndo, &elem);
12370f74e101Schristos 		return;
12380f74e101Schristos 	}
12390f74e101Schristos 	if ((u_int)count < length)
1240c74ad251Schristos 		ND_PRINT("[%d extra after SEQ of varbind]", length - count);
12410f74e101Schristos 	/* descend */
12420f74e101Schristos 	length = elem.asnlen;
1243fdccd7e4Schristos 	np = (const u_char *)elem.data.raw;
12440f74e101Schristos 
1245c74ad251Schristos 	while (length) {
12460f74e101Schristos 		const u_char *vbend;
12470f74e101Schristos 		u_int vblength;
12480f74e101Schristos 
1249c74ad251Schristos 		ND_PRINT(" ");
12500f74e101Schristos 
12510f74e101Schristos 		/* Sequence */
1252b3a00663Schristos 		if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
12530f74e101Schristos 			return;
12540f74e101Schristos 		if (elem.type != BE_SEQ) {
1255c74ad251Schristos 			ND_PRINT("[!varbind]");
1256b3a00663Schristos 			asn1_print(ndo, &elem);
12570f74e101Schristos 			return;
12580f74e101Schristos 		}
12590f74e101Schristos 		vbend = np + count;
12600f74e101Schristos 		vblength = length - count;
12610f74e101Schristos 		/* descend */
12620f74e101Schristos 		length = elem.asnlen;
1263fdccd7e4Schristos 		np = (const u_char *)elem.data.raw;
12640f74e101Schristos 
12650f74e101Schristos 		/* objName (OID) */
1266b3a00663Schristos 		if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
12670f74e101Schristos 			return;
12680f74e101Schristos 		if (elem.type != BE_OID) {
1269c74ad251Schristos 			ND_PRINT("[objName!=OID]");
1270b3a00663Schristos 			asn1_print(ndo, &elem);
12710f74e101Schristos 			return;
12720f74e101Schristos 		}
1273b3a00663Schristos #ifdef USE_LIBSMI
1274b3a00663Schristos 		smiNode = smi_print_variable(ndo, &elem, &status);
12750f74e101Schristos #else
1276b3a00663Schristos 		status = asn1_print(ndo, &elem);
12770f74e101Schristos #endif
12780f74e101Schristos 		if (status < 0)
12790f74e101Schristos 			return;
12800f74e101Schristos 		length -= count;
12810f74e101Schristos 		np += count;
12820f74e101Schristos 
12830f74e101Schristos 		if (pduid != GETREQ && pduid != GETNEXTREQ
12840f74e101Schristos 		    && pduid != GETBULKREQ)
1285c74ad251Schristos 			ND_PRINT("=");
12860f74e101Schristos 
12870f74e101Schristos 		/* objVal (ANY) */
1288b3a00663Schristos 		if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
12890f74e101Schristos 			return;
12900f74e101Schristos 		if (pduid == GETREQ || pduid == GETNEXTREQ
12910f74e101Schristos 		    || pduid == GETBULKREQ) {
12920f74e101Schristos 			if (elem.type != BE_NULL) {
1293c74ad251Schristos 				ND_PRINT("[objVal!=NULL]");
1294b3a00663Schristos 				if (asn1_print(ndo, &elem) < 0)
12950f74e101Schristos 					return;
12960f74e101Schristos 			}
12970f74e101Schristos 		} else {
12980f74e101Schristos 		        if (elem.type != BE_NULL) {
1299b3a00663Schristos #ifdef USE_LIBSMI
1300b3a00663Schristos 				status = smi_print_value(ndo, smiNode, pduid, &elem);
13010f74e101Schristos #else
1302b3a00663Schristos 				status = asn1_print(ndo, &elem);
13030f74e101Schristos #endif
13040f74e101Schristos 			}
13050f74e101Schristos 			if (status < 0)
13060f74e101Schristos 				return;
13070f74e101Schristos 		}
13080f74e101Schristos 		length = vblength;
13090f74e101Schristos 		np = vbend;
13100f74e101Schristos 	}
13110f74e101Schristos }
13120f74e101Schristos 
13130f74e101Schristos /*
13140f74e101Schristos  * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
13150f74e101Schristos  * GetBulk, Inform, V2Trap, and Report
13160f74e101Schristos  */
13170f74e101Schristos static void
1318b3a00663Schristos snmppdu_print(netdissect_options *ndo,
1319b3a00663Schristos               u_short pduid, const u_char *np, u_int length)
13200f74e101Schristos {
13210f74e101Schristos 	struct be elem;
1322fdccd7e4Schristos 	int count = 0, error_status;
13230f74e101Schristos 
13240f74e101Schristos 	/* reqId (Integer) */
1325b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
13260f74e101Schristos 		return;
13270f74e101Schristos 	if (elem.type != BE_INT) {
1328c74ad251Schristos 		ND_PRINT("[reqId!=INT]");
1329b3a00663Schristos 		asn1_print(ndo, &elem);
13300f74e101Schristos 		return;
13310f74e101Schristos 	}
1332b3a00663Schristos 	if (ndo->ndo_vflag)
1333c74ad251Schristos 		ND_PRINT("R=%d ", elem.data.integer);
13340f74e101Schristos 	length -= count;
13350f74e101Schristos 	np += count;
13360f74e101Schristos 
13370f74e101Schristos 	/* errorStatus (Integer) */
1338b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
13390f74e101Schristos 		return;
13400f74e101Schristos 	if (elem.type != BE_INT) {
1341c74ad251Schristos 		ND_PRINT("[errorStatus!=INT]");
1342b3a00663Schristos 		asn1_print(ndo, &elem);
13430f74e101Schristos 		return;
13440f74e101Schristos 	}
1345fdccd7e4Schristos 	error_status = 0;
13460f74e101Schristos 	if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
13470f74e101Schristos 	    || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
13480f74e101Schristos 	    && elem.data.integer != 0) {
13490f74e101Schristos 		char errbuf[20];
1350c74ad251Schristos 		ND_PRINT("[errorStatus(%s)!=0]",
1351c74ad251Schristos 			DECODE_ErrorStatus(elem.data.integer));
13520f74e101Schristos 	} else if (pduid == GETBULKREQ) {
1353c74ad251Schristos 		ND_PRINT(" N=%d", elem.data.integer);
13540f74e101Schristos 	} else if (elem.data.integer != 0) {
13550f74e101Schristos 		char errbuf[20];
1356c74ad251Schristos 		ND_PRINT(" %s", DECODE_ErrorStatus(elem.data.integer));
1357fdccd7e4Schristos 		error_status = elem.data.integer;
13580f74e101Schristos 	}
13590f74e101Schristos 	length -= count;
13600f74e101Schristos 	np += count;
13610f74e101Schristos 
13620f74e101Schristos 	/* errorIndex (Integer) */
1363b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
13640f74e101Schristos 		return;
13650f74e101Schristos 	if (elem.type != BE_INT) {
1366c74ad251Schristos 		ND_PRINT("[errorIndex!=INT]");
1367b3a00663Schristos 		asn1_print(ndo, &elem);
13680f74e101Schristos 		return;
13690f74e101Schristos 	}
13700f74e101Schristos 	if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
13710f74e101Schristos 	    || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
13720f74e101Schristos 	    && elem.data.integer != 0)
1373c74ad251Schristos 		ND_PRINT("[errorIndex(%d)!=0]", elem.data.integer);
13740f74e101Schristos 	else if (pduid == GETBULKREQ)
1375c74ad251Schristos 		ND_PRINT(" M=%d", elem.data.integer);
13760f74e101Schristos 	else if (elem.data.integer != 0) {
1377fdccd7e4Schristos 		if (!error_status)
1378c74ad251Schristos 			ND_PRINT("[errorIndex(%d) w/o errorStatus]", elem.data.integer);
1379fdccd7e4Schristos 		else
1380c74ad251Schristos 			ND_PRINT("@%d", elem.data.integer);
1381fdccd7e4Schristos 	} else if (error_status) {
1382c74ad251Schristos 		ND_PRINT("[errorIndex==0]");
13830f74e101Schristos 	}
13840f74e101Schristos 	length -= count;
13850f74e101Schristos 	np += count;
13860f74e101Schristos 
1387b3a00663Schristos 	varbind_print(ndo, pduid, np, length);
13880f74e101Schristos }
13890f74e101Schristos 
13900f74e101Schristos /*
13910f74e101Schristos  * Decode SNMP Trap PDU
13920f74e101Schristos  */
13930f74e101Schristos static void
1394b3a00663Schristos trappdu_print(netdissect_options *ndo,
1395b3a00663Schristos               const u_char *np, u_int length)
13960f74e101Schristos {
13970f74e101Schristos 	struct be elem;
13980f74e101Schristos 	int count = 0, generic;
13990f74e101Schristos 
1400c74ad251Schristos 	ND_PRINT(" ");
14010f74e101Schristos 
14020f74e101Schristos 	/* enterprise (oid) */
1403b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
14040f74e101Schristos 		return;
14050f74e101Schristos 	if (elem.type != BE_OID) {
1406c74ad251Schristos 		ND_PRINT("[enterprise!=OID]");
1407b3a00663Schristos 		asn1_print(ndo, &elem);
14080f74e101Schristos 		return;
14090f74e101Schristos 	}
1410b3a00663Schristos 	if (asn1_print(ndo, &elem) < 0)
14110f74e101Schristos 		return;
14120f74e101Schristos 	length -= count;
14130f74e101Schristos 	np += count;
14140f74e101Schristos 
1415c74ad251Schristos 	ND_PRINT(" ");
14160f74e101Schristos 
14170f74e101Schristos 	/* agent-addr (inetaddr) */
1418b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
14190f74e101Schristos 		return;
14200f74e101Schristos 	if (elem.type != BE_INETADDR) {
1421c74ad251Schristos 		ND_PRINT("[agent-addr!=INETADDR]");
1422b3a00663Schristos 		asn1_print(ndo, &elem);
14230f74e101Schristos 		return;
14240f74e101Schristos 	}
1425b3a00663Schristos 	if (asn1_print(ndo, &elem) < 0)
14260f74e101Schristos 		return;
14270f74e101Schristos 	length -= count;
14280f74e101Schristos 	np += count;
14290f74e101Schristos 
14300f74e101Schristos 	/* generic-trap (Integer) */
1431b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
14320f74e101Schristos 		return;
14330f74e101Schristos 	if (elem.type != BE_INT) {
1434c74ad251Schristos 		ND_PRINT("[generic-trap!=INT]");
1435b3a00663Schristos 		asn1_print(ndo, &elem);
14360f74e101Schristos 		return;
14370f74e101Schristos 	}
14380f74e101Schristos 	generic = elem.data.integer;
14390f74e101Schristos 	{
14400f74e101Schristos 		char buf[20];
1441c74ad251Schristos 		ND_PRINT(" %s", DECODE_GenericTrap(generic));
14420f74e101Schristos 	}
14430f74e101Schristos 	length -= count;
14440f74e101Schristos 	np += count;
14450f74e101Schristos 
14460f74e101Schristos 	/* specific-trap (Integer) */
1447b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
14480f74e101Schristos 		return;
14490f74e101Schristos 	if (elem.type != BE_INT) {
1450c74ad251Schristos 		ND_PRINT("[specific-trap!=INT]");
1451b3a00663Schristos 		asn1_print(ndo, &elem);
14520f74e101Schristos 		return;
14530f74e101Schristos 	}
14540f74e101Schristos 	if (generic != GT_ENTERPRISE) {
14550f74e101Schristos 		if (elem.data.integer != 0)
1456c74ad251Schristos 			ND_PRINT("[specific-trap(%d)!=0]", elem.data.integer);
14570f74e101Schristos 	} else
1458c74ad251Schristos 		ND_PRINT(" s=%d", elem.data.integer);
14590f74e101Schristos 	length -= count;
14600f74e101Schristos 	np += count;
14610f74e101Schristos 
1462c74ad251Schristos 	ND_PRINT(" ");
14630f74e101Schristos 
14640f74e101Schristos 	/* time-stamp (TimeTicks) */
1465b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
14660f74e101Schristos 		return;
14670f74e101Schristos 	if (elem.type != BE_UNS) {			/* XXX */
1468c74ad251Schristos 		ND_PRINT("[time-stamp!=TIMETICKS]");
1469b3a00663Schristos 		asn1_print(ndo, &elem);
14700f74e101Schristos 		return;
14710f74e101Schristos 	}
1472b3a00663Schristos 	if (asn1_print(ndo, &elem) < 0)
14730f74e101Schristos 		return;
14740f74e101Schristos 	length -= count;
14750f74e101Schristos 	np += count;
14760f74e101Schristos 
1477b3a00663Schristos 	varbind_print(ndo, TRAP, np, length);
14780f74e101Schristos }
14790f74e101Schristos 
14800f74e101Schristos /*
14810f74e101Schristos  * Decode arbitrary SNMP PDUs.
14820f74e101Schristos  */
14830f74e101Schristos static void
1484b3a00663Schristos pdu_print(netdissect_options *ndo,
1485b3a00663Schristos           const u_char *np, u_int length, int version)
14860f74e101Schristos {
14870f74e101Schristos 	struct be pdu;
14880f74e101Schristos 	int count = 0;
14890f74e101Schristos 
14900f74e101Schristos 	/* PDU (Context) */
1491b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &pdu)) < 0)
14920f74e101Schristos 		return;
14930f74e101Schristos 	if (pdu.type != BE_PDU) {
1494c74ad251Schristos 		ND_PRINT("[no PDU]");
14950f74e101Schristos 		return;
14960f74e101Schristos 	}
14970f74e101Schristos 	if ((u_int)count < length)
1498c74ad251Schristos 		ND_PRINT("[%d extra after PDU]", length - count);
1499b3a00663Schristos 	if (ndo->ndo_vflag) {
1500c74ad251Schristos 		ND_PRINT("{ ");
15010f74e101Schristos 	}
1502b3a00663Schristos 	if (asn1_print(ndo, &pdu) < 0)
15030f74e101Schristos 		return;
1504c74ad251Schristos 	ND_PRINT(" ");
15050f74e101Schristos 	/* descend into PDU */
15060f74e101Schristos 	length = pdu.asnlen;
1507fdccd7e4Schristos 	np = (const u_char *)pdu.data.raw;
15080f74e101Schristos 
15090f74e101Schristos 	if (version == SNMP_VERSION_1 &&
15100f74e101Schristos 	    (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
15110f74e101Schristos 	     pdu.id == V2TRAP || pdu.id == REPORT)) {
1512c74ad251Schristos 	        ND_PRINT("[v2 PDU in v1 message]");
15130f74e101Schristos 		return;
15140f74e101Schristos 	}
15150f74e101Schristos 
15160f74e101Schristos 	if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1517c74ad251Schristos 		ND_PRINT("[v1 PDU in v2 message]");
15180f74e101Schristos 		return;
15190f74e101Schristos 	}
15200f74e101Schristos 
15210f74e101Schristos 	switch (pdu.id) {
15220f74e101Schristos 	case TRAP:
1523b3a00663Schristos 		trappdu_print(ndo, np, length);
15240f74e101Schristos 		break;
15250f74e101Schristos 	case GETREQ:
15260f74e101Schristos 	case GETNEXTREQ:
15270f74e101Schristos 	case GETRESP:
15280f74e101Schristos 	case SETREQ:
15290f74e101Schristos 	case GETBULKREQ:
15300f74e101Schristos 	case INFORMREQ:
15310f74e101Schristos 	case V2TRAP:
15320f74e101Schristos 	case REPORT:
1533b3a00663Schristos 		snmppdu_print(ndo, pdu.id, np, length);
15340f74e101Schristos 		break;
15350f74e101Schristos 	}
15360f74e101Schristos 
1537b3a00663Schristos 	if (ndo->ndo_vflag) {
1538c74ad251Schristos 		ND_PRINT(" } ");
15390f74e101Schristos 	}
15400f74e101Schristos }
15410f74e101Schristos 
15420f74e101Schristos /*
15430f74e101Schristos  * Decode a scoped SNMP PDU.
15440f74e101Schristos  */
15450f74e101Schristos static void
1546b3a00663Schristos scopedpdu_print(netdissect_options *ndo,
1547b3a00663Schristos                 const u_char *np, u_int length, int version)
15480f74e101Schristos {
15490f74e101Schristos 	struct be elem;
1550dc860a36Sspz 	int count = 0;
15510f74e101Schristos 
15520f74e101Schristos 	/* Sequence */
1553b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
15540f74e101Schristos 		return;
15550f74e101Schristos 	if (elem.type != BE_SEQ) {
1556c74ad251Schristos 		ND_PRINT("[!scoped PDU]");
1557b3a00663Schristos 		asn1_print(ndo, &elem);
15580f74e101Schristos 		return;
15590f74e101Schristos 	}
15600f74e101Schristos 	length = elem.asnlen;
1561fdccd7e4Schristos 	np = (const u_char *)elem.data.raw;
15620f74e101Schristos 
15630f74e101Schristos 	/* contextEngineID (OCTET STRING) */
1564b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
15650f74e101Schristos 		return;
15660f74e101Schristos 	if (elem.type != BE_STR) {
1567c74ad251Schristos 		ND_PRINT("[contextEngineID!=STR]");
1568b3a00663Schristos 		asn1_print(ndo, &elem);
15690f74e101Schristos 		return;
15700f74e101Schristos 	}
15710f74e101Schristos 	length -= count;
15720f74e101Schristos 	np += count;
15730f74e101Schristos 
1574c74ad251Schristos 	ND_PRINT("E=");
1575dc860a36Sspz 	if (asn1_print_octets(ndo, &elem) == -1)
1576dc860a36Sspz 		return;
1577c74ad251Schristos 	ND_PRINT(" ");
15780f74e101Schristos 
15790f74e101Schristos 	/* contextName (OCTET STRING) */
1580b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
15810f74e101Schristos 		return;
15820f74e101Schristos 	if (elem.type != BE_STR) {
1583c74ad251Schristos 		ND_PRINT("[contextName!=STR]");
1584b3a00663Schristos 		asn1_print(ndo, &elem);
15850f74e101Schristos 		return;
15860f74e101Schristos 	}
15870f74e101Schristos 	length -= count;
15880f74e101Schristos 	np += count;
15890f74e101Schristos 
1590c74ad251Schristos 	ND_PRINT("C=");
1591dc860a36Sspz 	if (asn1_print_string(ndo, &elem) == -1)
1592dc860a36Sspz 		return;
1593c74ad251Schristos 	ND_PRINT(" ");
15940f74e101Schristos 
1595b3a00663Schristos 	pdu_print(ndo, np, length, version);
15960f74e101Schristos }
15970f74e101Schristos 
15980f74e101Schristos /*
15990f74e101Schristos  * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
16000f74e101Schristos  */
16010f74e101Schristos static void
1602b3a00663Schristos community_print(netdissect_options *ndo,
1603b3a00663Schristos                 const u_char *np, u_int length, int version)
16040f74e101Schristos {
16050f74e101Schristos 	struct be elem;
16060f74e101Schristos 	int count = 0;
16070f74e101Schristos 
16080f74e101Schristos 	/* Community (String) */
1609b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
16100f74e101Schristos 		return;
16110f74e101Schristos 	if (elem.type != BE_STR) {
1612c74ad251Schristos 		ND_PRINT("[comm!=STR]");
1613b3a00663Schristos 		asn1_print(ndo, &elem);
16140f74e101Schristos 		return;
16150f74e101Schristos 	}
16160f74e101Schristos 	/* default community */
16170f74e101Schristos 	if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
1618fdccd7e4Schristos 	    strncmp((const char *)elem.data.str, DEF_COMMUNITY,
1619dc860a36Sspz 	            sizeof(DEF_COMMUNITY) - 1) == 0)) {
16200f74e101Schristos 		/* ! "public" */
1621c74ad251Schristos 		ND_PRINT("C=");
1622dc860a36Sspz 		if (asn1_print_string(ndo, &elem) == -1)
1623dc860a36Sspz 			return;
1624c74ad251Schristos 		ND_PRINT(" ");
1625dc860a36Sspz 	}
16260f74e101Schristos 	length -= count;
16270f74e101Schristos 	np += count;
16280f74e101Schristos 
1629b3a00663Schristos 	pdu_print(ndo, np, length, version);
16300f74e101Schristos }
16310f74e101Schristos 
16320f74e101Schristos /*
16330f74e101Schristos  * Decode SNMPv3 User-based Security Message Header (SNMPv3)
16340f74e101Schristos  */
16350f74e101Schristos static void
1636b3a00663Schristos usm_print(netdissect_options *ndo,
1637b3a00663Schristos           const u_char *np, u_int length)
16380f74e101Schristos {
16390f74e101Schristos         struct be elem;
16400f74e101Schristos 	int count = 0;
16410f74e101Schristos 
16420f74e101Schristos 	/* Sequence */
1643b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
16440f74e101Schristos 		return;
16450f74e101Schristos 	if (elem.type != BE_SEQ) {
1646c74ad251Schristos 		ND_PRINT("[!usm]");
1647b3a00663Schristos 		asn1_print(ndo, &elem);
16480f74e101Schristos 		return;
16490f74e101Schristos 	}
16500f74e101Schristos 	length = elem.asnlen;
1651fdccd7e4Schristos 	np = (const u_char *)elem.data.raw;
16520f74e101Schristos 
16530f74e101Schristos 	/* msgAuthoritativeEngineID (OCTET STRING) */
1654b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
16550f74e101Schristos 		return;
16560f74e101Schristos 	if (elem.type != BE_STR) {
1657c74ad251Schristos 		ND_PRINT("[msgAuthoritativeEngineID!=STR]");
1658b3a00663Schristos 		asn1_print(ndo, &elem);
16590f74e101Schristos 		return;
16600f74e101Schristos 	}
16610f74e101Schristos 	length -= count;
16620f74e101Schristos 	np += count;
16630f74e101Schristos 
16640f74e101Schristos 	/* msgAuthoritativeEngineBoots (INTEGER) */
1665b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
16660f74e101Schristos 		return;
16670f74e101Schristos 	if (elem.type != BE_INT) {
1668c74ad251Schristos 		ND_PRINT("[msgAuthoritativeEngineBoots!=INT]");
1669b3a00663Schristos 		asn1_print(ndo, &elem);
16700f74e101Schristos 		return;
16710f74e101Schristos 	}
1672b3a00663Schristos 	if (ndo->ndo_vflag)
1673c74ad251Schristos 		ND_PRINT("B=%d ", elem.data.integer);
16740f74e101Schristos 	length -= count;
16750f74e101Schristos 	np += count;
16760f74e101Schristos 
16770f74e101Schristos 	/* msgAuthoritativeEngineTime (INTEGER) */
1678b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
16790f74e101Schristos 		return;
16800f74e101Schristos 	if (elem.type != BE_INT) {
1681c74ad251Schristos 		ND_PRINT("[msgAuthoritativeEngineTime!=INT]");
1682b3a00663Schristos 		asn1_print(ndo, &elem);
16830f74e101Schristos 		return;
16840f74e101Schristos 	}
1685b3a00663Schristos 	if (ndo->ndo_vflag)
1686c74ad251Schristos 		ND_PRINT("T=%d ", elem.data.integer);
16870f74e101Schristos 	length -= count;
16880f74e101Schristos 	np += count;
16890f74e101Schristos 
16900f74e101Schristos 	/* msgUserName (OCTET STRING) */
1691b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
16920f74e101Schristos 		return;
16930f74e101Schristos 	if (elem.type != BE_STR) {
1694c74ad251Schristos 		ND_PRINT("[msgUserName!=STR]");
1695b3a00663Schristos 		asn1_print(ndo, &elem);
16960f74e101Schristos 		return;
16970f74e101Schristos 	}
16980f74e101Schristos 	length -= count;
16990f74e101Schristos         np += count;
17000f74e101Schristos 
1701c74ad251Schristos 	ND_PRINT("U=");
1702dc860a36Sspz 	if (asn1_print_string(ndo, &elem) == -1)
1703dc860a36Sspz 		return;
1704c74ad251Schristos 	ND_PRINT(" ");
17050f74e101Schristos 
17060f74e101Schristos 	/* msgAuthenticationParameters (OCTET STRING) */
1707b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
17080f74e101Schristos 		return;
17090f74e101Schristos 	if (elem.type != BE_STR) {
1710c74ad251Schristos 		ND_PRINT("[msgAuthenticationParameters!=STR]");
1711b3a00663Schristos 		asn1_print(ndo, &elem);
17120f74e101Schristos 		return;
17130f74e101Schristos 	}
17140f74e101Schristos 	length -= count;
17150f74e101Schristos         np += count;
17160f74e101Schristos 
17170f74e101Schristos 	/* msgPrivacyParameters (OCTET STRING) */
1718b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
17190f74e101Schristos 		return;
17200f74e101Schristos 	if (elem.type != BE_STR) {
1721c74ad251Schristos 		ND_PRINT("[msgPrivacyParameters!=STR]");
1722b3a00663Schristos 		asn1_print(ndo, &elem);
17230f74e101Schristos 		return;
17240f74e101Schristos 	}
17250f74e101Schristos 	length -= count;
17260f74e101Schristos         np += count;
17270f74e101Schristos 
17280f74e101Schristos 	if ((u_int)count < length)
1729c74ad251Schristos 		ND_PRINT("[%d extra after usm SEQ]", length - count);
17300f74e101Schristos }
17310f74e101Schristos 
17320f74e101Schristos /*
17330f74e101Schristos  * Decode SNMPv3 Message Header (SNMPv3)
17340f74e101Schristos  */
17350f74e101Schristos static void
1736b3a00663Schristos v3msg_print(netdissect_options *ndo,
1737b3a00663Schristos             const u_char *np, u_int length)
17380f74e101Schristos {
17390f74e101Schristos 	struct be elem;
17400f74e101Schristos 	int count = 0;
17410f74e101Schristos 	u_char flags;
17420f74e101Schristos 	int model;
17430f74e101Schristos 	const u_char *xnp = np;
17440f74e101Schristos 	int xlength = length;
17450f74e101Schristos 
17460f74e101Schristos 	/* Sequence */
1747b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
17480f74e101Schristos 		return;
17490f74e101Schristos 	if (elem.type != BE_SEQ) {
1750c74ad251Schristos 		ND_PRINT("[!message]");
1751b3a00663Schristos 		asn1_print(ndo, &elem);
17520f74e101Schristos 		return;
17530f74e101Schristos 	}
17540f74e101Schristos 	length = elem.asnlen;
1755fdccd7e4Schristos 	np = (const u_char *)elem.data.raw;
17560f74e101Schristos 
1757b3a00663Schristos 	if (ndo->ndo_vflag) {
1758c74ad251Schristos 		ND_PRINT("{ ");
17590f74e101Schristos 	}
17600f74e101Schristos 
17610f74e101Schristos 	/* msgID (INTEGER) */
1762b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
17630f74e101Schristos 		return;
17640f74e101Schristos 	if (elem.type != BE_INT) {
1765c74ad251Schristos 		ND_PRINT("[msgID!=INT]");
1766b3a00663Schristos 		asn1_print(ndo, &elem);
17670f74e101Schristos 		return;
17680f74e101Schristos 	}
17690f74e101Schristos 	length -= count;
17700f74e101Schristos 	np += count;
17710f74e101Schristos 
17720f74e101Schristos 	/* msgMaxSize (INTEGER) */
1773b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
17740f74e101Schristos 		return;
17750f74e101Schristos 	if (elem.type != BE_INT) {
1776c74ad251Schristos 		ND_PRINT("[msgMaxSize!=INT]");
1777b3a00663Schristos 		asn1_print(ndo, &elem);
17780f74e101Schristos 		return;
17790f74e101Schristos 	}
17800f74e101Schristos 	length -= count;
17810f74e101Schristos 	np += count;
17820f74e101Schristos 
17830f74e101Schristos 	/* msgFlags (OCTET STRING) */
1784b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
17850f74e101Schristos 		return;
17860f74e101Schristos 	if (elem.type != BE_STR) {
1787c74ad251Schristos 		ND_PRINT("[msgFlags!=STR]");
1788b3a00663Schristos 		asn1_print(ndo, &elem);
17890f74e101Schristos 		return;
17900f74e101Schristos 	}
17910f74e101Schristos 	if (elem.asnlen != 1) {
1792c74ad251Schristos 		ND_PRINT("[msgFlags size %d]", elem.asnlen);
17930f74e101Schristos 		return;
17940f74e101Schristos 	}
1795c74ad251Schristos 	flags = GET_U_1(elem.data.str);
17960f74e101Schristos 	if (flags != 0x00 && flags != 0x01 && flags != 0x03
17970f74e101Schristos 	    && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1798c74ad251Schristos 		ND_PRINT("[msgFlags=0x%02X]", flags);
17990f74e101Schristos 		return;
18000f74e101Schristos 	}
18010f74e101Schristos 	length -= count;
18020f74e101Schristos 	np += count;
18030f74e101Schristos 
1804c74ad251Schristos 	ND_PRINT("F=%s%s%s ",
1805b3a00663Schristos 	          flags & 0x01 ? "a" : "",
1806b3a00663Schristos 	          flags & 0x02 ? "p" : "",
1807c74ad251Schristos 	          flags & 0x04 ? "r" : "");
18080f74e101Schristos 
18090f74e101Schristos 	/* msgSecurityModel (INTEGER) */
1810b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
18110f74e101Schristos 		return;
18120f74e101Schristos 	if (elem.type != BE_INT) {
1813c74ad251Schristos 		ND_PRINT("[msgSecurityModel!=INT]");
1814b3a00663Schristos 		asn1_print(ndo, &elem);
18150f74e101Schristos 		return;
18160f74e101Schristos 	}
18170f74e101Schristos 	model = elem.data.integer;
18180f74e101Schristos 	length -= count;
18190f74e101Schristos 	np += count;
18200f74e101Schristos 
18210f74e101Schristos 	if ((u_int)count < length)
1822c74ad251Schristos 		ND_PRINT("[%d extra after message SEQ]", length - count);
18230f74e101Schristos 
1824b3a00663Schristos 	if (ndo->ndo_vflag) {
1825c74ad251Schristos 		ND_PRINT("} ");
18260f74e101Schristos 	}
18270f74e101Schristos 
18280f74e101Schristos 	if (model == 3) {
1829b3a00663Schristos 	    if (ndo->ndo_vflag) {
1830c74ad251Schristos 		ND_PRINT("{ USM ");
18310f74e101Schristos 	    }
18320f74e101Schristos 	} else {
1833c74ad251Schristos 	    ND_PRINT("[security model %d]", model);
18340f74e101Schristos             return;
18350f74e101Schristos 	}
18360f74e101Schristos 
18370f74e101Schristos 	np = xnp + (np - xnp);
18380f74e101Schristos 	length = xlength - (np - xnp);
18390f74e101Schristos 
18400f74e101Schristos 	/* msgSecurityParameters (OCTET STRING) */
1841b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
18420f74e101Schristos 		return;
18430f74e101Schristos 	if (elem.type != BE_STR) {
1844c74ad251Schristos 		ND_PRINT("[msgSecurityParameters!=STR]");
1845b3a00663Schristos 		asn1_print(ndo, &elem);
18460f74e101Schristos 		return;
18470f74e101Schristos 	}
18480f74e101Schristos 	length -= count;
18490f74e101Schristos 	np += count;
18500f74e101Schristos 
18510f74e101Schristos 	if (model == 3) {
1852b3a00663Schristos 	    usm_print(ndo, elem.data.str, elem.asnlen);
1853b3a00663Schristos 	    if (ndo->ndo_vflag) {
1854c74ad251Schristos 		ND_PRINT("} ");
18550f74e101Schristos 	    }
18560f74e101Schristos 	}
18570f74e101Schristos 
1858b3a00663Schristos 	if (ndo->ndo_vflag) {
1859c74ad251Schristos 	    ND_PRINT("{ ScopedPDU ");
18600f74e101Schristos 	}
18610f74e101Schristos 
1862b3a00663Schristos 	scopedpdu_print(ndo, np, length, 3);
18630f74e101Schristos 
1864b3a00663Schristos 	if (ndo->ndo_vflag) {
1865c74ad251Schristos 		ND_PRINT("} ");
18660f74e101Schristos 	}
18670f74e101Schristos }
18680f74e101Schristos 
18690f74e101Schristos /*
18700f74e101Schristos  * Decode SNMP header and pass on to PDU printing routines
18710f74e101Schristos  */
18720f74e101Schristos void
1873b3a00663Schristos snmp_print(netdissect_options *ndo,
1874b3a00663Schristos            const u_char *np, u_int length)
18750f74e101Schristos {
18760f74e101Schristos 	struct be elem;
18770f74e101Schristos 	int count = 0;
18780f74e101Schristos 	int version = 0;
18790f74e101Schristos 
1880c74ad251Schristos 	ndo->ndo_protocol = "snmp";
1881c74ad251Schristos 	ND_PRINT(" ");
18820f74e101Schristos 
18830f74e101Schristos 	/* initial Sequence */
1884b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
18850f74e101Schristos 		return;
18860f74e101Schristos 	if (elem.type != BE_SEQ) {
1887c74ad251Schristos 		ND_PRINT("[!init SEQ]");
1888b3a00663Schristos 		asn1_print(ndo, &elem);
18890f74e101Schristos 		return;
18900f74e101Schristos 	}
18910f74e101Schristos 	if ((u_int)count < length)
1892c74ad251Schristos 		ND_PRINT("[%d extra after iSEQ]", length - count);
18930f74e101Schristos 	/* descend */
18940f74e101Schristos 	length = elem.asnlen;
1895fdccd7e4Schristos 	np = (const u_char *)elem.data.raw;
18960f74e101Schristos 
18970f74e101Schristos 	/* Version (INTEGER) */
1898b3a00663Schristos 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
18990f74e101Schristos 		return;
19000f74e101Schristos 	if (elem.type != BE_INT) {
1901c74ad251Schristos 		ND_PRINT("[version!=INT]");
1902b3a00663Schristos 		asn1_print(ndo, &elem);
19030f74e101Schristos 		return;
19040f74e101Schristos 	}
19050f74e101Schristos 
19060f74e101Schristos 	switch (elem.data.integer) {
19070f74e101Schristos 	case SNMP_VERSION_1:
19080f74e101Schristos 	case SNMP_VERSION_2:
19090f74e101Schristos 	case SNMP_VERSION_3:
1910b3a00663Schristos 		if (ndo->ndo_vflag)
1911c74ad251Schristos 			ND_PRINT("{ %s ", SnmpVersion[elem.data.integer]);
19120f74e101Schristos 		break;
19130f74e101Schristos 	default:
1914c74ad251Schristos 	        ND_PRINT("SNMP [version = %d]", elem.data.integer);
19150f74e101Schristos 		return;
19160f74e101Schristos 	}
19170f74e101Schristos 	version = elem.data.integer;
19180f74e101Schristos 	length -= count;
19190f74e101Schristos 	np += count;
19200f74e101Schristos 
19210f74e101Schristos 	switch (version) {
19220f74e101Schristos 	case SNMP_VERSION_1:
19230f74e101Schristos         case SNMP_VERSION_2:
1924b3a00663Schristos 		community_print(ndo, np, length, version);
19250f74e101Schristos 		break;
19260f74e101Schristos 	case SNMP_VERSION_3:
1927b3a00663Schristos 		v3msg_print(ndo, np, length);
19280f74e101Schristos 		break;
19290f74e101Schristos 	default:
1930c74ad251Schristos 		ND_PRINT("[version = %d]", elem.data.integer);
19310f74e101Schristos 		break;
19320f74e101Schristos 	}
19330f74e101Schristos 
1934b3a00663Schristos 	if (ndo->ndo_vflag) {
1935c74ad251Schristos 		ND_PRINT("} ");
19360f74e101Schristos 	}
19370f74e101Schristos }
1938