Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
      3  *     John Robert LoVerso. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  *
     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.
     15  *
     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.
     26  *
     27  *
     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
     35  * to this file.
     36  *
     37  * Support for SNMPv2c/SNMPv3 and the ability to link the module against
     38  * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
     39  *
     40  * This started out as a very simple program, but the incremental decoding
     41  * (into the BE structure) complicated things.
     42  *
     43  #			Los Alamos National Laboratory
     44  #
     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
     57  */
     58 
     59 /* \summary: Simple Network Management Protocol (SNMP) printer */
     60 
     61 #ifdef HAVE_CONFIG_H
     62 #include "config.h"
     63 #endif
     64 
     65 #include <netdissect-stdinc.h>
     66 
     67 #include <stdio.h>
     68 #include <string.h>
     69 
     70 #ifdef USE_LIBSMI
     71 #include <smi.h>
     72 #endif
     73 
     74 #include "netdissect.h"
     75 
     76 #undef OPAQUE  /* defined in <wingdi.h> */
     77 
     78 static const char tstr[] = "[|snmp]";
     79 
     80 /*
     81  * Universal ASN.1 types
     82  * (we only care about the tag values for those allowed in the Internet SMI)
     83  */
     84 static const char *Universal[] = {
     85 	"U-0",
     86 	"Boolean",
     87 	"Integer",
     88 #define INTEGER 2
     89 	"Bitstring",
     90 	"String",
     91 #define STRING 4
     92 	"Null",
     93 #define ASN_NULL 5
     94 	"ObjID",
     95 #define OBJECTID 6
     96 	"ObjectDes",
     97 	"U-8","U-9","U-10","U-11",	/* 8-11 */
     98 	"U-12","U-13","U-14","U-15",	/* 12-15 */
     99 	"Sequence",
    100 #define SEQUENCE 16
    101 	"Set"
    102 };
    103 
    104 /*
    105  * Application-wide ASN.1 types from the Internet SMI and their tags
    106  */
    107 static const char *Application[] = {
    108 	"IpAddress",
    109 #define IPADDR 0
    110 	"Counter",
    111 #define COUNTER 1
    112 	"Gauge",
    113 #define GAUGE 2
    114 	"TimeTicks",
    115 #define TIMETICKS 3
    116 	"Opaque",
    117 #define OPAQUE 4
    118 	"C-5",
    119 	"Counter64"
    120 #define COUNTER64 6
    121 };
    122 
    123 /*
    124  * Context-specific ASN.1 types for the SNMP PDUs and their tags
    125  */
    126 static const char *Context[] = {
    127 	"GetRequest",
    128 #define GETREQ 0
    129 	"GetNextRequest",
    130 #define GETNEXTREQ 1
    131 	"GetResponse",
    132 #define GETRESP 2
    133 	"SetRequest",
    134 #define SETREQ 3
    135 	"Trap",
    136 #define TRAP 4
    137 	"GetBulk",
    138 #define GETBULKREQ 5
    139 	"Inform",
    140 #define INFORMREQ 6
    141 	"V2Trap",
    142 #define V2TRAP 7
    143 	"Report"
    144 #define REPORT 8
    145 };
    146 
    147 #define NOTIFY_CLASS(x)	    (x == TRAP || x == V2TRAP || x == INFORMREQ)
    148 #define READ_CLASS(x)       (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
    149 #define WRITE_CLASS(x)	    (x == SETREQ)
    150 #define RESPONSE_CLASS(x)   (x == GETRESP)
    151 #define INTERNAL_CLASS(x)   (x == REPORT)
    152 
    153 /*
    154  * Context-specific ASN.1 types for the SNMP Exceptions and their tags
    155  */
    156 static const char *Exceptions[] = {
    157 	"noSuchObject",
    158 #define NOSUCHOBJECT 0
    159 	"noSuchInstance",
    160 #define NOSUCHINSTANCE 1
    161 	"endOfMibView",
    162 #define ENDOFMIBVIEW 2
    163 };
    164 
    165 /*
    166  * Private ASN.1 types
    167  * The Internet SMI does not specify any
    168  */
    169 static const char *Private[] = {
    170 	"P-0"
    171 };
    172 
    173 /*
    174  * error-status values for any SNMP PDU
    175  */
    176 static const char *ErrorStatus[] = {
    177 	"noError",
    178 	"tooBig",
    179 	"noSuchName",
    180 	"badValue",
    181 	"readOnly",
    182 	"genErr",
    183 	"noAccess",
    184 	"wrongType",
    185 	"wrongLength",
    186 	"wrongEncoding",
    187 	"wrongValue",
    188 	"noCreation",
    189 	"inconsistentValue",
    190 	"resourceUnavailable",
    191 	"commitFailed",
    192 	"undoFailed",
    193 	"authorizationError",
    194 	"notWritable",
    195 	"inconsistentName"
    196 };
    197 #define DECODE_ErrorStatus(e) \
    198 	( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
    199 		? ErrorStatus[e] \
    200 		: (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
    201 
    202 /*
    203  * generic-trap values in the SNMP Trap-PDU
    204  */
    205 static const char *GenericTrap[] = {
    206 	"coldStart",
    207 	"warmStart",
    208 	"linkDown",
    209 	"linkUp",
    210 	"authenticationFailure",
    211 	"egpNeighborLoss",
    212 	"enterpriseSpecific"
    213 #define GT_ENTERPRISE 6
    214 };
    215 #define DECODE_GenericTrap(t) \
    216 	( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
    217 		? GenericTrap[t] \
    218 		: (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
    219 
    220 /*
    221  * ASN.1 type class table
    222  * Ties together the preceding Universal, Application, Context, and Private
    223  * type definitions.
    224  */
    225 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
    226 static const struct {
    227 	const char	*name;
    228 	const char	**Id;
    229 	    int	numIDs;
    230     } Class[] = {
    231 	defineCLASS(Universal),
    232 #define	UNIVERSAL	0
    233 	defineCLASS(Application),
    234 #define	APPLICATION	1
    235 	defineCLASS(Context),
    236 #define	CONTEXT		2
    237 	defineCLASS(Private),
    238 #define	PRIVATE		3
    239 	defineCLASS(Exceptions),
    240 #define EXCEPTIONS	4
    241 };
    242 
    243 /*
    244  * defined forms for ASN.1 types
    245  */
    246 static const char *Form[] = {
    247 	"Primitive",
    248 #define PRIMITIVE	0
    249 	"Constructed",
    250 #define CONSTRUCTED	1
    251 };
    252 
    253 /*
    254  * A structure for the OID tree for the compiled-in MIB.
    255  * This is stored as a general-order tree.
    256  */
    257 static struct obj {
    258 	const char	*desc;		/* name of object */
    259 	u_char	oid;			/* sub-id following parent */
    260 	u_char	type;			/* object type (unused) */
    261 	struct obj *child, *next;	/* child and next sibling pointers */
    262 } *objp = NULL;
    263 
    264 /*
    265  * Include the compiled in SNMP MIB.  "mib.h" is produced by feeding
    266  * RFC-1156 format files into "makemib".  "mib.h" MUST define at least
    267  * a value for `mibroot'.
    268  *
    269  * In particular, this is gross, as this is including initialized structures,
    270  * and by right shouldn't be an "include" file.
    271  */
    272 #include "mib.h"
    273 
    274 /*
    275  * This defines a list of OIDs which will be abbreviated on output.
    276  * Currently, this includes the prefixes for the Internet MIB, the
    277  * private enterprises tree, and the experimental tree.
    278  */
    279 #define OID_FIRST_OCTET(x, y)	(((x)*40) + (y))	/* X.690 8.19.4 */
    280 
    281 #ifndef NO_ABREV_MIB
    282 static const uint8_t mib_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 2, 1 };
    283 #endif
    284 #ifndef NO_ABREV_ENTER
    285 static const uint8_t enterprises_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 4, 1 };
    286 #endif
    287 #ifndef NO_ABREV_EXPERI
    288 static const uint8_t experimental_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 3 };
    289 #endif
    290 #ifndef NO_ABBREV_SNMPMODS
    291 static const uint8_t snmpModules_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 6, 3 };
    292 #endif
    293 
    294 #define OBJ_ABBREV_ENTRY(prefix, obj) \
    295 	{ prefix, &_ ## obj ## _obj, obj ## _oid, sizeof (obj ## _oid) }
    296 static const struct obj_abrev {
    297 	const char *prefix;		/* prefix for this abrev */
    298 	struct obj *node;		/* pointer into object table */
    299 	const uint8_t *oid;		/* ASN.1 encoded OID */
    300 	size_t oid_len;			/* length of OID */
    301 } obj_abrev_list[] = {
    302 #ifndef NO_ABREV_MIB
    303 	/* .iso.org.dod.internet.mgmt.mib */
    304 	OBJ_ABBREV_ENTRY("",	mib),
    305 #endif
    306 #ifndef NO_ABREV_ENTER
    307 	/* .iso.org.dod.internet.private.enterprises */
    308 	OBJ_ABBREV_ENTRY("E:",	enterprises),
    309 #endif
    310 #ifndef NO_ABREV_EXPERI
    311 	/* .iso.org.dod.internet.experimental */
    312 	OBJ_ABBREV_ENTRY("X:",	experimental),
    313 #endif
    314 #ifndef NO_ABBREV_SNMPMODS
    315 	/* .iso.org.dod.internet.snmpV2.snmpModules */
    316 	OBJ_ABBREV_ENTRY("S:",	snmpModules),
    317 #endif
    318 	{ 0,0,0,0 }
    319 };
    320 
    321 /*
    322  * This is used in the OID print routine to walk down the object tree
    323  * rooted at `mibroot'.
    324  */
    325 #define OBJ_PRINT(o, suppressdot) \
    326 { \
    327 	if (objp) { \
    328 		do { \
    329 			if ((o) == objp->oid) \
    330 				break; \
    331 		} while ((objp = objp->next) != NULL); \
    332 	} \
    333 	if (objp) { \
    334 		ND_PRINT((ndo, suppressdot?"%s":".%s", objp->desc)); \
    335 		objp = objp->child; \
    336 	} else \
    337 		ND_PRINT((ndo, suppressdot?"%u":".%u", (o))); \
    338 }
    339 
    340 /*
    341  * This is the definition for the Any-Data-Type storage used purely for
    342  * temporary internal representation while decoding an ASN.1 data stream.
    343  */
    344 struct be {
    345 	uint32_t asnlen;
    346 	union {
    347 		const uint8_t *raw;
    348 		int32_t integer;
    349 		uint32_t uns;
    350 		const u_char *str;
    351 		uint64_t uns64;
    352 	} data;
    353 	u_short id;
    354 	u_char form, class;		/* tag info */
    355 	u_char type;
    356 #define BE_ANY		255
    357 #define BE_NONE		0
    358 #define BE_NULL		1
    359 #define BE_OCTET	2
    360 #define BE_OID		3
    361 #define BE_INT		4
    362 #define BE_UNS		5
    363 #define BE_STR		6
    364 #define BE_SEQ		7
    365 #define BE_INETADDR	8
    366 #define BE_PDU		9
    367 #define BE_UNS64	10
    368 #define BE_NOSUCHOBJECT	128
    369 #define BE_NOSUCHINST	129
    370 #define BE_ENDOFMIBVIEW	130
    371 };
    372 
    373 /*
    374  * SNMP versions recognized by this module
    375  */
    376 static const char *SnmpVersion[] = {
    377 	"SNMPv1",
    378 #define SNMP_VERSION_1	0
    379 	"SNMPv2c",
    380 #define SNMP_VERSION_2	1
    381 	"SNMPv2u",
    382 #define SNMP_VERSION_2U	2
    383 	"SNMPv3"
    384 #define SNMP_VERSION_3	3
    385 };
    386 
    387 /*
    388  * Defaults for SNMP PDU components
    389  */
    390 #define DEF_COMMUNITY "public"
    391 
    392 /*
    393  * constants for ASN.1 decoding
    394  */
    395 #define OIDMUX 40
    396 #define ASNLEN_INETADDR 4
    397 #define ASN_SHIFT7 7
    398 #define ASN_SHIFT8 8
    399 #define ASN_BIT8 0x80
    400 #define ASN_LONGLEN 0x80
    401 
    402 #define ASN_ID_BITS 0x1f
    403 #define ASN_FORM_BITS 0x20
    404 #define ASN_FORM_SHIFT 5
    405 #define ASN_CLASS_BITS 0xc0
    406 #define ASN_CLASS_SHIFT 6
    407 
    408 #define ASN_ID_EXT 0x1f		/* extension ID in tag field */
    409 
    410 /*
    411  * This decodes the next ASN.1 object in the stream pointed to by "p"
    412  * (and of real-length "len") and stores the intermediate data in the
    413  * provided BE object.
    414  *
    415  * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
    416  * O/w, this returns the number of bytes parsed from "p".
    417  */
    418 static int
    419 asn1_parse(netdissect_options *ndo,
    420            register const u_char *p, u_int len, struct be *elem)
    421 {
    422 	u_char form, class, id;
    423 	int i, hdr;
    424 
    425 	elem->asnlen = 0;
    426 	elem->type = BE_ANY;
    427 	if (len < 1) {
    428 		ND_PRINT((ndo, "[nothing to parse]"));
    429 		return -1;
    430 	}
    431 	ND_TCHECK(*p);
    432 
    433 	/*
    434 	 * it would be nice to use a bit field, but you can't depend on them.
    435 	 *  +---+---+---+---+---+---+---+---+
    436 	 *  + class |frm|        id         |
    437 	 *  +---+---+---+---+---+---+---+---+
    438 	 *    7   6   5   4   3   2   1   0
    439 	 */
    440 	id = *p & ASN_ID_BITS;		/* lower 5 bits, range 00-1f */
    441 #ifdef notdef
    442 	form = (*p & 0xe0) >> 5;	/* move upper 3 bits to lower 3 */
    443 	class = form >> 1;		/* bits 7&6 -> bits 1&0, range 0-3 */
    444 	form &= 0x1;			/* bit 5 -> bit 0, range 0-1 */
    445 #else
    446 	form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
    447 	class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
    448 #endif
    449 	elem->form = form;
    450 	elem->class = class;
    451 	elem->id = id;
    452 	p++; len--; hdr = 1;
    453 	/* extended tag field */
    454 	if (id == ASN_ID_EXT) {
    455 		/*
    456 		 * The ID follows, as a sequence of octets with the
    457 		 * 8th bit set and the remaining 7 bits being
    458 		 * the next 7 bits of the value, terminated with
    459 		 * an octet with the 8th bit not set.
    460 		 *
    461 		 * First, assemble all the octets with the 8th
    462 		 * bit set.  XXX - this doesn't handle a value
    463 		 * that won't fit in 32 bits.
    464 		 */
    465 		id = 0;
    466 		ND_TCHECK(*p);
    467 		while (*p & ASN_BIT8) {
    468 			if (len < 1) {
    469 				ND_PRINT((ndo, "[Xtagfield?]"));
    470 				return -1;
    471 			}
    472 			id = (id << 7) | (*p & ~ASN_BIT8);
    473 			len--;
    474 			hdr++;
    475 			p++;
    476 			ND_TCHECK(*p);
    477 		}
    478 		if (len < 1) {
    479 			ND_PRINT((ndo, "[Xtagfield?]"));
    480 			return -1;
    481 		}
    482 		ND_TCHECK(*p);
    483 		elem->id = id = (id << 7) | *p;
    484 		--len;
    485 		++hdr;
    486 		++p;
    487 	}
    488 	if (len < 1) {
    489 		ND_PRINT((ndo, "[no asnlen]"));
    490 		return -1;
    491 	}
    492 	ND_TCHECK(*p);
    493 	elem->asnlen = *p;
    494 	p++; len--; hdr++;
    495 	if (elem->asnlen & ASN_BIT8) {
    496 		uint32_t noct = elem->asnlen % ASN_BIT8;
    497 		elem->asnlen = 0;
    498 		if (len < noct) {
    499 			ND_PRINT((ndo, "[asnlen? %d<%d]", len, noct));
    500 			return -1;
    501 		}
    502 		ND_TCHECK2(*p, noct);
    503 		for (; noct-- > 0; len--, hdr++)
    504 			elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
    505 	}
    506 	if (len < elem->asnlen) {
    507 		ND_PRINT((ndo, "[len%d<asnlen%u]", len, elem->asnlen));
    508 		return -1;
    509 	}
    510 	if (form >= sizeof(Form)/sizeof(Form[0])) {
    511 		ND_PRINT((ndo, "[form?%d]", form));
    512 		return -1;
    513 	}
    514 	if (class >= sizeof(Class)/sizeof(Class[0])) {
    515 		ND_PRINT((ndo, "[class?%c/%d]", *Form[form], class));
    516 		return -1;
    517 	}
    518 	if ((int)id >= Class[class].numIDs) {
    519 		ND_PRINT((ndo, "[id?%c/%s/%d]", *Form[form], Class[class].name, id));
    520 		return -1;
    521 	}
    522 	ND_TCHECK2(*p, elem->asnlen);
    523 
    524 	switch (form) {
    525 	case PRIMITIVE:
    526 		switch (class) {
    527 		case UNIVERSAL:
    528 			switch (id) {
    529 			case STRING:
    530 				elem->type = BE_STR;
    531 				elem->data.str = p;
    532 				break;
    533 
    534 			case INTEGER: {
    535 				register int32_t data;
    536 				elem->type = BE_INT;
    537 				data = 0;
    538 
    539 				if (elem->asnlen == 0) {
    540 					ND_PRINT((ndo, "[asnlen=0]"));
    541 					return -1;
    542 				}
    543 				if (*p & ASN_BIT8)	/* negative */
    544 					data = -1;
    545 				for (i = elem->asnlen; i-- > 0; p++)
    546 					data = (data << ASN_SHIFT8) | *p;
    547 				elem->data.integer = data;
    548 				break;
    549 			}
    550 
    551 			case OBJECTID:
    552 				elem->type = BE_OID;
    553 				elem->data.raw = (const uint8_t *)p;
    554 				break;
    555 
    556 			case ASN_NULL:
    557 				elem->type = BE_NULL;
    558 				elem->data.raw = NULL;
    559 				break;
    560 
    561 			default:
    562 				elem->type = BE_OCTET;
    563 				elem->data.raw = (const uint8_t *)p;
    564 				ND_PRINT((ndo, "[P/U/%s]", Class[class].Id[id]));
    565 				break;
    566 			}
    567 			break;
    568 
    569 		case APPLICATION:
    570 			switch (id) {
    571 			case IPADDR:
    572 				elem->type = BE_INETADDR;
    573 				elem->data.raw = (const uint8_t *)p;
    574 				break;
    575 
    576 			case COUNTER:
    577 			case GAUGE:
    578 			case TIMETICKS: {
    579 				register uint32_t data;
    580 				elem->type = BE_UNS;
    581 				data = 0;
    582 				for (i = elem->asnlen; i-- > 0; p++)
    583 					data = (data << 8) + *p;
    584 				elem->data.uns = data;
    585 				break;
    586 			}
    587 
    588 			case COUNTER64: {
    589 				register uint64_t data64;
    590 			        elem->type = BE_UNS64;
    591 				data64 = 0;
    592 				for (i = elem->asnlen; i-- > 0; p++)
    593 					data64 = (data64 << 8) + *p;
    594 				elem->data.uns64 = data64;
    595 				break;
    596 			}
    597 
    598 			default:
    599 				elem->type = BE_OCTET;
    600 				elem->data.raw = (const uint8_t *)p;
    601 				ND_PRINT((ndo, "[P/A/%s]",
    602 					Class[class].Id[id]));
    603 				break;
    604 			}
    605 			break;
    606 
    607 		case CONTEXT:
    608 			switch (id) {
    609 			case NOSUCHOBJECT:
    610 				elem->type = BE_NOSUCHOBJECT;
    611 				elem->data.raw = NULL;
    612 				break;
    613 
    614 			case NOSUCHINSTANCE:
    615 				elem->type = BE_NOSUCHINST;
    616 				elem->data.raw = NULL;
    617 				break;
    618 
    619 			case ENDOFMIBVIEW:
    620 				elem->type = BE_ENDOFMIBVIEW;
    621 				elem->data.raw = NULL;
    622 				break;
    623 			}
    624 			break;
    625 
    626 		default:
    627 			ND_PRINT((ndo, "[P/%s/%s]", Class[class].name, Class[class].Id[id]));
    628 			elem->type = BE_OCTET;
    629 			elem->data.raw = (const uint8_t *)p;
    630 			break;
    631 		}
    632 		break;
    633 
    634 	case CONSTRUCTED:
    635 		switch (class) {
    636 		case UNIVERSAL:
    637 			switch (id) {
    638 			case SEQUENCE:
    639 				elem->type = BE_SEQ;
    640 				elem->data.raw = (const uint8_t *)p;
    641 				break;
    642 
    643 			default:
    644 				elem->type = BE_OCTET;
    645 				elem->data.raw = (const uint8_t *)p;
    646 				ND_PRINT((ndo, "C/U/%s", Class[class].Id[id]));
    647 				break;
    648 			}
    649 			break;
    650 
    651 		case CONTEXT:
    652 			elem->type = BE_PDU;
    653 			elem->data.raw = (const uint8_t *)p;
    654 			break;
    655 
    656 		default:
    657 			elem->type = BE_OCTET;
    658 			elem->data.raw = (const uint8_t *)p;
    659 			ND_PRINT((ndo, "C/%s/%s", Class[class].name, Class[class].Id[id]));
    660 			break;
    661 		}
    662 		break;
    663 	}
    664 	p += elem->asnlen;
    665 	len -= elem->asnlen;
    666 	return elem->asnlen + hdr;
    667 
    668 trunc:
    669 	ND_PRINT((ndo, "%s", tstr));
    670 	return -1;
    671 }
    672 
    673 static int
    674 asn1_print_octets(netdissect_options *ndo, struct be *elem)
    675 {
    676 	const u_char *p = (const u_char *)elem->data.raw;
    677 	uint32_t asnlen = elem->asnlen;
    678 	uint32_t i;
    679 
    680 	ND_TCHECK2(*p, asnlen);
    681 	for (i = asnlen; i-- > 0; p++)
    682 		ND_PRINT((ndo, "_%.2x", *p));
    683 	return 0;
    684 
    685 trunc:
    686 	ND_PRINT((ndo, "%s", tstr));
    687 	return -1;
    688 }
    689 
    690 static int
    691 asn1_print_string(netdissect_options *ndo, struct be *elem)
    692 {
    693 	register int printable = 1, first = 1;
    694 	const u_char *p;
    695 	uint32_t asnlen = elem->asnlen;
    696 	uint32_t i;
    697 
    698 	p = elem->data.str;
    699 	ND_TCHECK2(*p, asnlen);
    700 	for (i = asnlen; printable && i-- > 0; p++)
    701 		printable = ND_ISPRINT(*p);
    702 	p = elem->data.str;
    703 	if (printable) {
    704 		ND_PRINT((ndo, "\""));
    705 		if (fn_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
    706 			ND_PRINT((ndo, "\""));
    707 			goto trunc;
    708 		}
    709 		ND_PRINT((ndo, "\""));
    710 	} else {
    711 		for (i = asnlen; i-- > 0; p++) {
    712 			ND_PRINT((ndo, first ? "%.2x" : "_%.2x", *p));
    713 			first = 0;
    714 		}
    715 	}
    716 	return 0;
    717 
    718 trunc:
    719 	ND_PRINT((ndo, "%s", tstr));
    720 	return -1;
    721 }
    722 
    723 /*
    724  * Display the ASN.1 object represented by the BE object.
    725  * This used to be an integral part of asn1_parse() before the intermediate
    726  * BE form was added.
    727  */
    728 static int
    729 asn1_print(netdissect_options *ndo,
    730            struct be *elem)
    731 {
    732 	const u_char *p;
    733 	uint32_t asnlen = elem->asnlen;
    734 	uint32_t i;
    735 
    736 	switch (elem->type) {
    737 
    738 	case BE_OCTET:
    739 		if (asn1_print_octets(ndo, elem) == -1)
    740 			return -1;
    741 		break;
    742 
    743 	case BE_NULL:
    744 		break;
    745 
    746 	case BE_OID: {
    747 		int o = 0, first = -1;
    748 
    749 		p = (const u_char *)elem->data.raw;
    750 		i = asnlen;
    751 		if (!ndo->ndo_nflag && asnlen > 2) {
    752 			const struct obj_abrev *a = &obj_abrev_list[0];
    753 			for (; a->node; a++) {
    754 				if (i < a->oid_len)
    755 					continue;
    756 				if (!ND_TTEST2(*p, a->oid_len))
    757 					continue;
    758 				if (memcmp(a->oid, p, a->oid_len) == 0) {
    759 					objp = a->node->child;
    760 					i -= a->oid_len;
    761 					p += a->oid_len;
    762 					ND_PRINT((ndo, "%s", a->prefix));
    763 					first = 1;
    764 					break;
    765 				}
    766 			}
    767 		}
    768 
    769 		for (; i-- > 0; p++) {
    770 			ND_TCHECK(*p);
    771 			o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
    772 			if (*p & ASN_LONGLEN)
    773 			        continue;
    774 
    775 			/*
    776 			 * first subitem encodes two items with
    777 			 * 1st*OIDMUX+2nd
    778 			 * (see X.690:1997 clause 8.19 for the details)
    779 			 */
    780 			if (first < 0) {
    781 			        int s;
    782 				if (!ndo->ndo_nflag)
    783 					objp = mibroot;
    784 				first = 0;
    785 				s = o / OIDMUX;
    786 				if (s > 2) s = 2;
    787 				OBJ_PRINT(s, first);
    788 				o -= s * OIDMUX;
    789 			}
    790 			OBJ_PRINT(o, first);
    791 			if (--first < 0)
    792 				first = 0;
    793 			o = 0;
    794 		}
    795 		break;
    796 	}
    797 
    798 	case BE_INT:
    799 		ND_PRINT((ndo, "%d", elem->data.integer));
    800 		break;
    801 
    802 	case BE_UNS:
    803 		ND_PRINT((ndo, "%u", elem->data.uns));
    804 		break;
    805 
    806 	case BE_UNS64:
    807 		ND_PRINT((ndo, "%" PRIu64, elem->data.uns64));
    808 		break;
    809 
    810 	case BE_STR:
    811 		if (asn1_print_string(ndo, elem) == -1)
    812 			return -1;
    813 		break;
    814 
    815 	case BE_SEQ:
    816 		ND_PRINT((ndo, "Seq(%u)", elem->asnlen));
    817 		break;
    818 
    819 	case BE_INETADDR:
    820 		if (asnlen != ASNLEN_INETADDR)
    821 			ND_PRINT((ndo, "[inetaddr len!=%d]", ASNLEN_INETADDR));
    822 		p = (const u_char *)elem->data.raw;
    823 		ND_TCHECK2(*p, asnlen);
    824 		for (i = asnlen; i-- != 0; p++) {
    825 			ND_PRINT((ndo, (i == asnlen-1) ? "%u" : ".%u", *p));
    826 		}
    827 		break;
    828 
    829 	case BE_NOSUCHOBJECT:
    830 	case BE_NOSUCHINST:
    831 	case BE_ENDOFMIBVIEW:
    832 		ND_PRINT((ndo, "[%s]", Class[EXCEPTIONS].Id[elem->id]));
    833 		break;
    834 
    835 	case BE_PDU:
    836 		ND_PRINT((ndo, "%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen));
    837 		break;
    838 
    839 	case BE_ANY:
    840 		ND_PRINT((ndo, "[BE_ANY!?]"));
    841 		break;
    842 
    843 	default:
    844 		ND_PRINT((ndo, "[be!?]"));
    845 		break;
    846 	}
    847 	return 0;
    848 
    849 trunc:
    850 	ND_PRINT((ndo, "%s", tstr));
    851 	return -1;
    852 }
    853 
    854 #ifdef notdef
    855 /*
    856  * This is a brute force ASN.1 printer: recurses to dump an entire structure.
    857  * This will work for any ASN.1 stream, not just an SNMP PDU.
    858  *
    859  * By adding newlines and spaces at the correct places, this would print in
    860  * Rose-Normal-Form.
    861  *
    862  * This is not currently used.
    863  */
    864 static void
    865 asn1_decode(u_char *p, u_int length)
    866 {
    867 	struct be elem;
    868 	int i = 0;
    869 
    870 	while (i >= 0 && length > 0) {
    871 		i = asn1_parse(ndo, p, length, &elem);
    872 		if (i >= 0) {
    873 			ND_PRINT((ndo, " "));
    874 			if (asn1_print(ndo, &elem) < 0)
    875 				return;
    876 			if (elem.type == BE_SEQ || elem.type == BE_PDU) {
    877 				ND_PRINT((ndo, " {"));
    878 				asn1_decode(elem.data.raw, elem.asnlen);
    879 				ND_PRINT((ndo, " }"));
    880 			}
    881 			length -= i;
    882 			p += i;
    883 		}
    884 	}
    885 }
    886 #endif
    887 
    888 #ifdef USE_LIBSMI
    889 
    890 struct smi2be {
    891     SmiBasetype basetype;
    892     int be;
    893 };
    894 
    895 static const struct smi2be smi2betab[] = {
    896     { SMI_BASETYPE_INTEGER32,		BE_INT },
    897     { SMI_BASETYPE_OCTETSTRING,		BE_STR },
    898     { SMI_BASETYPE_OCTETSTRING,		BE_INETADDR },
    899     { SMI_BASETYPE_OBJECTIDENTIFIER,	BE_OID },
    900     { SMI_BASETYPE_UNSIGNED32,		BE_UNS },
    901     { SMI_BASETYPE_INTEGER64,		BE_NONE },
    902     { SMI_BASETYPE_UNSIGNED64,		BE_UNS64 },
    903     { SMI_BASETYPE_FLOAT32,		BE_NONE },
    904     { SMI_BASETYPE_FLOAT64,		BE_NONE },
    905     { SMI_BASETYPE_FLOAT128,		BE_NONE },
    906     { SMI_BASETYPE_ENUM,		BE_INT },
    907     { SMI_BASETYPE_BITS,		BE_STR },
    908     { SMI_BASETYPE_UNKNOWN,		BE_NONE }
    909 };
    910 
    911 static int
    912 smi_decode_oid(netdissect_options *ndo,
    913                struct be *elem, unsigned int *oid,
    914                unsigned int oidsize, unsigned int *oidlen)
    915 {
    916 	const u_char *p = (const u_char *)elem->data.raw;
    917 	uint32_t asnlen = elem->asnlen;
    918 	int o = 0, first = -1, i = asnlen;
    919 	unsigned int firstval;
    920 
    921 	for (*oidlen = 0; i-- > 0; p++) {
    922 		ND_TCHECK(*p);
    923 	        o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
    924 		if (*p & ASN_LONGLEN)
    925 		    continue;
    926 
    927 		/*
    928 		 * first subitem encodes two items with 1st*OIDMUX+2nd
    929 		 * (see X.690:1997 clause 8.19 for the details)
    930 		 */
    931 		if (first < 0) {
    932 	        	first = 0;
    933 			firstval = o / OIDMUX;
    934 			if (firstval > 2) firstval = 2;
    935 			o -= firstval * OIDMUX;
    936 			if (*oidlen < oidsize) {
    937 			    oid[(*oidlen)++] = firstval;
    938 			}
    939 		}
    940 		if (*oidlen < oidsize) {
    941 			oid[(*oidlen)++] = o;
    942 		}
    943 		o = 0;
    944 	}
    945 	return 0;
    946 
    947 trunc:
    948 	ND_PRINT((ndo, "%s", tstr));
    949 	return -1;
    950 }
    951 
    952 static int smi_check_type(SmiBasetype basetype, int be)
    953 {
    954     int i;
    955 
    956     for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
    957 	if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
    958 	    return 1;
    959 	}
    960     }
    961 
    962     return 0;
    963 }
    964 
    965 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
    966 			     struct be *elem)
    967 {
    968     int ok = 1;
    969 
    970     switch (smiType->basetype) {
    971     case SMI_BASETYPE_OBJECTIDENTIFIER:
    972     case SMI_BASETYPE_OCTETSTRING:
    973 	if (smiRange->minValue.value.unsigned32
    974 	    == smiRange->maxValue.value.unsigned32) {
    975 	    ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
    976 	} else {
    977 	    ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
    978 		  && elem->asnlen <= smiRange->maxValue.value.unsigned32);
    979 	}
    980 	break;
    981 
    982     case SMI_BASETYPE_INTEGER32:
    983 	ok = (elem->data.integer >= smiRange->minValue.value.integer32
    984 	      && elem->data.integer <= smiRange->maxValue.value.integer32);
    985 	break;
    986 
    987     case SMI_BASETYPE_UNSIGNED32:
    988 	ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
    989 	      && elem->data.uns <= smiRange->maxValue.value.unsigned32);
    990 	break;
    991 
    992     case SMI_BASETYPE_UNSIGNED64:
    993 	/* XXX */
    994 	break;
    995 
    996 	/* case SMI_BASETYPE_INTEGER64: SMIng */
    997 	/* case SMI_BASETYPE_FLOAT32: SMIng */
    998 	/* case SMI_BASETYPE_FLOAT64: SMIng */
    999 	/* case SMI_BASETYPE_FLOAT128: SMIng */
   1000 
   1001     case SMI_BASETYPE_ENUM:
   1002     case SMI_BASETYPE_BITS:
   1003     case SMI_BASETYPE_UNKNOWN:
   1004 	ok = 1;
   1005 	break;
   1006 
   1007     default:
   1008 	ok = 0;
   1009 	break;
   1010     }
   1011 
   1012     return ok;
   1013 }
   1014 
   1015 static int smi_check_range(SmiType *smiType, struct be *elem)
   1016 {
   1017         SmiRange *smiRange;
   1018 	int ok = 1;
   1019 
   1020 	for (smiRange = smiGetFirstRange(smiType);
   1021 	     smiRange;
   1022 	     smiRange = smiGetNextRange(smiRange)) {
   1023 
   1024 	    ok = smi_check_a_range(smiType, smiRange, elem);
   1025 
   1026 	    if (ok) {
   1027 		break;
   1028 	    }
   1029 	}
   1030 
   1031 	if (ok) {
   1032 	    SmiType *parentType;
   1033 	    parentType = smiGetParentType(smiType);
   1034 	    if (parentType) {
   1035 		ok = smi_check_range(parentType, elem);
   1036 	    }
   1037 	}
   1038 
   1039 	return ok;
   1040 }
   1041 
   1042 static SmiNode *
   1043 smi_print_variable(netdissect_options *ndo,
   1044                    struct be *elem, int *status)
   1045 {
   1046 	unsigned int oid[128], oidlen;
   1047 	SmiNode *smiNode = NULL;
   1048 	unsigned int i;
   1049 
   1050 	if (!nd_smi_module_loaded) {
   1051 		*status = asn1_print(ndo, elem);
   1052 		return NULL;
   1053 	}
   1054 	*status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
   1055 	    &oidlen);
   1056 	if (*status < 0)
   1057 		return NULL;
   1058 	smiNode = smiGetNodeByOID(oidlen, oid);
   1059 	if (! smiNode) {
   1060 		*status = asn1_print(ndo, elem);
   1061 		return NULL;
   1062 	}
   1063 	if (ndo->ndo_vflag) {
   1064 		ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
   1065 	}
   1066 	ND_PRINT((ndo, "%s", smiNode->name));
   1067 	if (smiNode->oidlen < oidlen) {
   1068 		for (i = smiNode->oidlen; i < oidlen; i++) {
   1069 			ND_PRINT((ndo, ".%u", oid[i]));
   1070 		}
   1071 	}
   1072 	*status = 0;
   1073 	return smiNode;
   1074 }
   1075 
   1076 static int
   1077 smi_print_value(netdissect_options *ndo,
   1078                 SmiNode *smiNode, u_short pduid, struct be *elem)
   1079 {
   1080 	unsigned int i, oid[128], oidlen;
   1081 	SmiType *smiType;
   1082 	SmiNamedNumber *nn;
   1083 	int done = 0;
   1084 
   1085 	if (! smiNode || ! (smiNode->nodekind
   1086 			    & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
   1087 	    return asn1_print(ndo, elem);
   1088 	}
   1089 
   1090 	if (elem->type == BE_NOSUCHOBJECT
   1091 	    || elem->type == BE_NOSUCHINST
   1092 	    || elem->type == BE_ENDOFMIBVIEW) {
   1093 	    return asn1_print(ndo, elem);
   1094 	}
   1095 
   1096 	if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
   1097 	    ND_PRINT((ndo, "[notNotifyable]"));
   1098 	}
   1099 
   1100 	if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
   1101 	    ND_PRINT((ndo, "[notReadable]"));
   1102 	}
   1103 
   1104 	if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
   1105 	    ND_PRINT((ndo, "[notWritable]"));
   1106 	}
   1107 
   1108 	if (RESPONSE_CLASS(pduid)
   1109 	    && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
   1110 	    ND_PRINT((ndo, "[noAccess]"));
   1111 	}
   1112 
   1113 	smiType = smiGetNodeType(smiNode);
   1114 	if (! smiType) {
   1115 	    return asn1_print(ndo, elem);
   1116 	}
   1117 
   1118 	if (! smi_check_type(smiType->basetype, elem->type)) {
   1119 	    ND_PRINT((ndo, "[wrongType]"));
   1120 	}
   1121 
   1122 	if (! smi_check_range(smiType, elem)) {
   1123 	    ND_PRINT((ndo, "[outOfRange]"));
   1124 	}
   1125 
   1126 	/* resolve bits to named bits */
   1127 
   1128 	/* check whether instance identifier is valid */
   1129 
   1130 	/* apply display hints (integer, octetstring) */
   1131 
   1132 	/* convert instance identifier to index type values */
   1133 
   1134 	switch (elem->type) {
   1135 	case BE_OID:
   1136 	        if (smiType->basetype == SMI_BASETYPE_BITS) {
   1137 		        /* print bit labels */
   1138 		} else {
   1139 			if (nd_smi_module_loaded &&
   1140 			    smi_decode_oid(ndo, elem, oid,
   1141 					   sizeof(oid)/sizeof(unsigned int),
   1142 					   &oidlen) == 0) {
   1143 				smiNode = smiGetNodeByOID(oidlen, oid);
   1144 				if (smiNode) {
   1145 				        if (ndo->ndo_vflag) {
   1146 						ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
   1147 					}
   1148 					ND_PRINT((ndo, "%s", smiNode->name));
   1149 					if (smiNode->oidlen < oidlen) {
   1150 					        for (i = smiNode->oidlen;
   1151 						     i < oidlen; i++) {
   1152 						        ND_PRINT((ndo, ".%u", oid[i]));
   1153 						}
   1154 					}
   1155 					done++;
   1156 				}
   1157 			}
   1158 		}
   1159 		break;
   1160 
   1161 	case BE_INT:
   1162 	        if (smiType->basetype == SMI_BASETYPE_ENUM) {
   1163 		        for (nn = smiGetFirstNamedNumber(smiType);
   1164 			     nn;
   1165 			     nn = smiGetNextNamedNumber(nn)) {
   1166 			         if (nn->value.value.integer32
   1167 				     == elem->data.integer) {
   1168 				         ND_PRINT((ndo, "%s", nn->name));
   1169 					 ND_PRINT((ndo, "(%d)", elem->data.integer));
   1170 					 done++;
   1171 					 break;
   1172 				}
   1173 			}
   1174 		}
   1175 		break;
   1176 	}
   1177 
   1178 	if (! done) {
   1179 		return asn1_print(ndo, elem);
   1180 	}
   1181 	return 0;
   1182 }
   1183 #endif
   1184 
   1185 /*
   1186  * General SNMP header
   1187  *	SEQUENCE {
   1188  *		version INTEGER {version-1(0)},
   1189  *		community OCTET STRING,
   1190  *		data ANY	-- PDUs
   1191  *	}
   1192  * PDUs for all but Trap: (see rfc1157 from page 15 on)
   1193  *	SEQUENCE {
   1194  *		request-id INTEGER,
   1195  *		error-status INTEGER,
   1196  *		error-index INTEGER,
   1197  *		varbindlist SEQUENCE OF
   1198  *			SEQUENCE {
   1199  *				name ObjectName,
   1200  *				value ObjectValue
   1201  *			}
   1202  *	}
   1203  * PDU for Trap:
   1204  *	SEQUENCE {
   1205  *		enterprise OBJECT IDENTIFIER,
   1206  *		agent-addr NetworkAddress,
   1207  *		generic-trap INTEGER,
   1208  *		specific-trap INTEGER,
   1209  *		time-stamp TimeTicks,
   1210  *		varbindlist SEQUENCE OF
   1211  *			SEQUENCE {
   1212  *				name ObjectName,
   1213  *				value ObjectValue
   1214  *			}
   1215  *	}
   1216  */
   1217 
   1218 /*
   1219  * Decode SNMP varBind
   1220  */
   1221 static void
   1222 varbind_print(netdissect_options *ndo,
   1223               u_short pduid, const u_char *np, u_int length)
   1224 {
   1225 	struct be elem;
   1226 	int count = 0, ind;
   1227 #ifdef USE_LIBSMI
   1228 	SmiNode *smiNode = NULL;
   1229 #endif
   1230 	int status;
   1231 
   1232 	/* Sequence of varBind */
   1233 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1234 		return;
   1235 	if (elem.type != BE_SEQ) {
   1236 		ND_PRINT((ndo, "[!SEQ of varbind]"));
   1237 		asn1_print(ndo, &elem);
   1238 		return;
   1239 	}
   1240 	if ((u_int)count < length)
   1241 		ND_PRINT((ndo, "[%d extra after SEQ of varbind]", length - count));
   1242 	/* descend */
   1243 	length = elem.asnlen;
   1244 	np = (const u_char *)elem.data.raw;
   1245 
   1246 	for (ind = 1; length > 0; ind++) {
   1247 		const u_char *vbend;
   1248 		u_int vblength;
   1249 
   1250 		ND_PRINT((ndo, " "));
   1251 
   1252 		/* Sequence */
   1253 		if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1254 			return;
   1255 		if (elem.type != BE_SEQ) {
   1256 			ND_PRINT((ndo, "[!varbind]"));
   1257 			asn1_print(ndo, &elem);
   1258 			return;
   1259 		}
   1260 		vbend = np + count;
   1261 		vblength = length - count;
   1262 		/* descend */
   1263 		length = elem.asnlen;
   1264 		np = (const u_char *)elem.data.raw;
   1265 
   1266 		/* objName (OID) */
   1267 		if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1268 			return;
   1269 		if (elem.type != BE_OID) {
   1270 			ND_PRINT((ndo, "[objName!=OID]"));
   1271 			asn1_print(ndo, &elem);
   1272 			return;
   1273 		}
   1274 #ifdef USE_LIBSMI
   1275 		smiNode = smi_print_variable(ndo, &elem, &status);
   1276 #else
   1277 		status = asn1_print(ndo, &elem);
   1278 #endif
   1279 		if (status < 0)
   1280 			return;
   1281 		length -= count;
   1282 		np += count;
   1283 
   1284 		if (pduid != GETREQ && pduid != GETNEXTREQ
   1285 		    && pduid != GETBULKREQ)
   1286 			ND_PRINT((ndo, "="));
   1287 
   1288 		/* objVal (ANY) */
   1289 		if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1290 			return;
   1291 		if (pduid == GETREQ || pduid == GETNEXTREQ
   1292 		    || pduid == GETBULKREQ) {
   1293 			if (elem.type != BE_NULL) {
   1294 				ND_PRINT((ndo, "[objVal!=NULL]"));
   1295 				if (asn1_print(ndo, &elem) < 0)
   1296 					return;
   1297 			}
   1298 		} else {
   1299 		        if (elem.type != BE_NULL) {
   1300 #ifdef USE_LIBSMI
   1301 				status = smi_print_value(ndo, smiNode, pduid, &elem);
   1302 #else
   1303 				status = asn1_print(ndo, &elem);
   1304 #endif
   1305 			}
   1306 			if (status < 0)
   1307 				return;
   1308 		}
   1309 		length = vblength;
   1310 		np = vbend;
   1311 	}
   1312 }
   1313 
   1314 /*
   1315  * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
   1316  * GetBulk, Inform, V2Trap, and Report
   1317  */
   1318 static void
   1319 snmppdu_print(netdissect_options *ndo,
   1320               u_short pduid, const u_char *np, u_int length)
   1321 {
   1322 	struct be elem;
   1323 	int count = 0, error_status;
   1324 
   1325 	/* reqId (Integer) */
   1326 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1327 		return;
   1328 	if (elem.type != BE_INT) {
   1329 		ND_PRINT((ndo, "[reqId!=INT]"));
   1330 		asn1_print(ndo, &elem);
   1331 		return;
   1332 	}
   1333 	if (ndo->ndo_vflag)
   1334 		ND_PRINT((ndo, "R=%d ", elem.data.integer));
   1335 	length -= count;
   1336 	np += count;
   1337 
   1338 	/* errorStatus (Integer) */
   1339 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1340 		return;
   1341 	if (elem.type != BE_INT) {
   1342 		ND_PRINT((ndo, "[errorStatus!=INT]"));
   1343 		asn1_print(ndo, &elem);
   1344 		return;
   1345 	}
   1346 	error_status = 0;
   1347 	if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
   1348 	    || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
   1349 	    && elem.data.integer != 0) {
   1350 		char errbuf[20];
   1351 		ND_PRINT((ndo, "[errorStatus(%s)!=0]",
   1352 			DECODE_ErrorStatus(elem.data.integer)));
   1353 	} else if (pduid == GETBULKREQ) {
   1354 		ND_PRINT((ndo, " N=%d", elem.data.integer));
   1355 	} else if (elem.data.integer != 0) {
   1356 		char errbuf[20];
   1357 		ND_PRINT((ndo, " %s", DECODE_ErrorStatus(elem.data.integer)));
   1358 		error_status = elem.data.integer;
   1359 	}
   1360 	length -= count;
   1361 	np += count;
   1362 
   1363 	/* errorIndex (Integer) */
   1364 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1365 		return;
   1366 	if (elem.type != BE_INT) {
   1367 		ND_PRINT((ndo, "[errorIndex!=INT]"));
   1368 		asn1_print(ndo, &elem);
   1369 		return;
   1370 	}
   1371 	if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
   1372 	    || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
   1373 	    && elem.data.integer != 0)
   1374 		ND_PRINT((ndo, "[errorIndex(%d)!=0]", elem.data.integer));
   1375 	else if (pduid == GETBULKREQ)
   1376 		ND_PRINT((ndo, " M=%d", elem.data.integer));
   1377 	else if (elem.data.integer != 0) {
   1378 		if (!error_status)
   1379 			ND_PRINT((ndo, "[errorIndex(%d) w/o errorStatus]", elem.data.integer));
   1380 		else
   1381 			ND_PRINT((ndo, "@%d", elem.data.integer));
   1382 	} else if (error_status) {
   1383 		ND_PRINT((ndo, "[errorIndex==0]"));
   1384 	}
   1385 	length -= count;
   1386 	np += count;
   1387 
   1388 	varbind_print(ndo, pduid, np, length);
   1389 	return;
   1390 }
   1391 
   1392 /*
   1393  * Decode SNMP Trap PDU
   1394  */
   1395 static void
   1396 trappdu_print(netdissect_options *ndo,
   1397               const u_char *np, u_int length)
   1398 {
   1399 	struct be elem;
   1400 	int count = 0, generic;
   1401 
   1402 	ND_PRINT((ndo, " "));
   1403 
   1404 	/* enterprise (oid) */
   1405 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1406 		return;
   1407 	if (elem.type != BE_OID) {
   1408 		ND_PRINT((ndo, "[enterprise!=OID]"));
   1409 		asn1_print(ndo, &elem);
   1410 		return;
   1411 	}
   1412 	if (asn1_print(ndo, &elem) < 0)
   1413 		return;
   1414 	length -= count;
   1415 	np += count;
   1416 
   1417 	ND_PRINT((ndo, " "));
   1418 
   1419 	/* agent-addr (inetaddr) */
   1420 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1421 		return;
   1422 	if (elem.type != BE_INETADDR) {
   1423 		ND_PRINT((ndo, "[agent-addr!=INETADDR]"));
   1424 		asn1_print(ndo, &elem);
   1425 		return;
   1426 	}
   1427 	if (asn1_print(ndo, &elem) < 0)
   1428 		return;
   1429 	length -= count;
   1430 	np += count;
   1431 
   1432 	/* generic-trap (Integer) */
   1433 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1434 		return;
   1435 	if (elem.type != BE_INT) {
   1436 		ND_PRINT((ndo, "[generic-trap!=INT]"));
   1437 		asn1_print(ndo, &elem);
   1438 		return;
   1439 	}
   1440 	generic = elem.data.integer;
   1441 	{
   1442 		char buf[20];
   1443 		ND_PRINT((ndo, " %s", DECODE_GenericTrap(generic)));
   1444 	}
   1445 	length -= count;
   1446 	np += count;
   1447 
   1448 	/* specific-trap (Integer) */
   1449 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1450 		return;
   1451 	if (elem.type != BE_INT) {
   1452 		ND_PRINT((ndo, "[specific-trap!=INT]"));
   1453 		asn1_print(ndo, &elem);
   1454 		return;
   1455 	}
   1456 	if (generic != GT_ENTERPRISE) {
   1457 		if (elem.data.integer != 0)
   1458 			ND_PRINT((ndo, "[specific-trap(%d)!=0]", elem.data.integer));
   1459 	} else
   1460 		ND_PRINT((ndo, " s=%d", elem.data.integer));
   1461 	length -= count;
   1462 	np += count;
   1463 
   1464 	ND_PRINT((ndo, " "));
   1465 
   1466 	/* time-stamp (TimeTicks) */
   1467 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1468 		return;
   1469 	if (elem.type != BE_UNS) {			/* XXX */
   1470 		ND_PRINT((ndo, "[time-stamp!=TIMETICKS]"));
   1471 		asn1_print(ndo, &elem);
   1472 		return;
   1473 	}
   1474 	if (asn1_print(ndo, &elem) < 0)
   1475 		return;
   1476 	length -= count;
   1477 	np += count;
   1478 
   1479 	varbind_print(ndo, TRAP, np, length);
   1480 	return;
   1481 }
   1482 
   1483 /*
   1484  * Decode arbitrary SNMP PDUs.
   1485  */
   1486 static void
   1487 pdu_print(netdissect_options *ndo,
   1488           const u_char *np, u_int length, int version)
   1489 {
   1490 	struct be pdu;
   1491 	int count = 0;
   1492 
   1493 	/* PDU (Context) */
   1494 	if ((count = asn1_parse(ndo, np, length, &pdu)) < 0)
   1495 		return;
   1496 	if (pdu.type != BE_PDU) {
   1497 		ND_PRINT((ndo, "[no PDU]"));
   1498 		return;
   1499 	}
   1500 	if ((u_int)count < length)
   1501 		ND_PRINT((ndo, "[%d extra after PDU]", length - count));
   1502 	if (ndo->ndo_vflag) {
   1503 		ND_PRINT((ndo, "{ "));
   1504 	}
   1505 	if (asn1_print(ndo, &pdu) < 0)
   1506 		return;
   1507 	ND_PRINT((ndo, " "));
   1508 	/* descend into PDU */
   1509 	length = pdu.asnlen;
   1510 	np = (const u_char *)pdu.data.raw;
   1511 
   1512 	if (version == SNMP_VERSION_1 &&
   1513 	    (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
   1514 	     pdu.id == V2TRAP || pdu.id == REPORT)) {
   1515 	        ND_PRINT((ndo, "[v2 PDU in v1 message]"));
   1516 		return;
   1517 	}
   1518 
   1519 	if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
   1520 		ND_PRINT((ndo, "[v1 PDU in v2 message]"));
   1521 		return;
   1522 	}
   1523 
   1524 	switch (pdu.id) {
   1525 	case TRAP:
   1526 		trappdu_print(ndo, np, length);
   1527 		break;
   1528 	case GETREQ:
   1529 	case GETNEXTREQ:
   1530 	case GETRESP:
   1531 	case SETREQ:
   1532 	case GETBULKREQ:
   1533 	case INFORMREQ:
   1534 	case V2TRAP:
   1535 	case REPORT:
   1536 		snmppdu_print(ndo, pdu.id, np, length);
   1537 		break;
   1538 	}
   1539 
   1540 	if (ndo->ndo_vflag) {
   1541 		ND_PRINT((ndo, " } "));
   1542 	}
   1543 }
   1544 
   1545 /*
   1546  * Decode a scoped SNMP PDU.
   1547  */
   1548 static void
   1549 scopedpdu_print(netdissect_options *ndo,
   1550                 const u_char *np, u_int length, int version)
   1551 {
   1552 	struct be elem;
   1553 	int count = 0;
   1554 
   1555 	/* Sequence */
   1556 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1557 		return;
   1558 	if (elem.type != BE_SEQ) {
   1559 		ND_PRINT((ndo, "[!scoped PDU]"));
   1560 		asn1_print(ndo, &elem);
   1561 		return;
   1562 	}
   1563 	length = elem.asnlen;
   1564 	np = (const u_char *)elem.data.raw;
   1565 
   1566 	/* contextEngineID (OCTET STRING) */
   1567 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1568 		return;
   1569 	if (elem.type != BE_STR) {
   1570 		ND_PRINT((ndo, "[contextEngineID!=STR]"));
   1571 		asn1_print(ndo, &elem);
   1572 		return;
   1573 	}
   1574 	length -= count;
   1575 	np += count;
   1576 
   1577 	ND_PRINT((ndo, "E="));
   1578 	if (asn1_print_octets(ndo, &elem) == -1)
   1579 		return;
   1580 	ND_PRINT((ndo, " "));
   1581 
   1582 	/* contextName (OCTET STRING) */
   1583 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1584 		return;
   1585 	if (elem.type != BE_STR) {
   1586 		ND_PRINT((ndo, "[contextName!=STR]"));
   1587 		asn1_print(ndo, &elem);
   1588 		return;
   1589 	}
   1590 	length -= count;
   1591 	np += count;
   1592 
   1593 	ND_PRINT((ndo, "C="));
   1594 	if (asn1_print_string(ndo, &elem) == -1)
   1595 		return;
   1596 	ND_PRINT((ndo, " "));
   1597 
   1598 	pdu_print(ndo, np, length, version);
   1599 }
   1600 
   1601 /*
   1602  * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
   1603  */
   1604 static void
   1605 community_print(netdissect_options *ndo,
   1606                 const u_char *np, u_int length, int version)
   1607 {
   1608 	struct be elem;
   1609 	int count = 0;
   1610 
   1611 	/* Community (String) */
   1612 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1613 		return;
   1614 	if (elem.type != BE_STR) {
   1615 		ND_PRINT((ndo, "[comm!=STR]"));
   1616 		asn1_print(ndo, &elem);
   1617 		return;
   1618 	}
   1619 	/* default community */
   1620 	if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
   1621 	    strncmp((const char *)elem.data.str, DEF_COMMUNITY,
   1622 	            sizeof(DEF_COMMUNITY) - 1) == 0)) {
   1623 		/* ! "public" */
   1624 		ND_PRINT((ndo, "C="));
   1625 		if (asn1_print_string(ndo, &elem) == -1)
   1626 			return;
   1627 		ND_PRINT((ndo, " "));
   1628 	}
   1629 	length -= count;
   1630 	np += count;
   1631 
   1632 	pdu_print(ndo, np, length, version);
   1633 }
   1634 
   1635 /*
   1636  * Decode SNMPv3 User-based Security Message Header (SNMPv3)
   1637  */
   1638 static void
   1639 usm_print(netdissect_options *ndo,
   1640           const u_char *np, u_int length)
   1641 {
   1642         struct be elem;
   1643 	int count = 0;
   1644 
   1645 	/* Sequence */
   1646 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1647 		return;
   1648 	if (elem.type != BE_SEQ) {
   1649 		ND_PRINT((ndo, "[!usm]"));
   1650 		asn1_print(ndo, &elem);
   1651 		return;
   1652 	}
   1653 	length = elem.asnlen;
   1654 	np = (const u_char *)elem.data.raw;
   1655 
   1656 	/* msgAuthoritativeEngineID (OCTET STRING) */
   1657 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1658 		return;
   1659 	if (elem.type != BE_STR) {
   1660 		ND_PRINT((ndo, "[msgAuthoritativeEngineID!=STR]"));
   1661 		asn1_print(ndo, &elem);
   1662 		return;
   1663 	}
   1664 	length -= count;
   1665 	np += count;
   1666 
   1667 	/* msgAuthoritativeEngineBoots (INTEGER) */
   1668 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1669 		return;
   1670 	if (elem.type != BE_INT) {
   1671 		ND_PRINT((ndo, "[msgAuthoritativeEngineBoots!=INT]"));
   1672 		asn1_print(ndo, &elem);
   1673 		return;
   1674 	}
   1675 	if (ndo->ndo_vflag)
   1676 		ND_PRINT((ndo, "B=%d ", elem.data.integer));
   1677 	length -= count;
   1678 	np += count;
   1679 
   1680 	/* msgAuthoritativeEngineTime (INTEGER) */
   1681 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1682 		return;
   1683 	if (elem.type != BE_INT) {
   1684 		ND_PRINT((ndo, "[msgAuthoritativeEngineTime!=INT]"));
   1685 		asn1_print(ndo, &elem);
   1686 		return;
   1687 	}
   1688 	if (ndo->ndo_vflag)
   1689 		ND_PRINT((ndo, "T=%d ", elem.data.integer));
   1690 	length -= count;
   1691 	np += count;
   1692 
   1693 	/* msgUserName (OCTET STRING) */
   1694 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1695 		return;
   1696 	if (elem.type != BE_STR) {
   1697 		ND_PRINT((ndo, "[msgUserName!=STR]"));
   1698 		asn1_print(ndo, &elem);
   1699 		return;
   1700 	}
   1701 	length -= count;
   1702         np += count;
   1703 
   1704 	ND_PRINT((ndo, "U="));
   1705 	if (asn1_print_string(ndo, &elem) == -1)
   1706 		return;
   1707 	ND_PRINT((ndo, " "));
   1708 
   1709 	/* msgAuthenticationParameters (OCTET STRING) */
   1710 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1711 		return;
   1712 	if (elem.type != BE_STR) {
   1713 		ND_PRINT((ndo, "[msgAuthenticationParameters!=STR]"));
   1714 		asn1_print(ndo, &elem);
   1715 		return;
   1716 	}
   1717 	length -= count;
   1718         np += count;
   1719 
   1720 	/* msgPrivacyParameters (OCTET STRING) */
   1721 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1722 		return;
   1723 	if (elem.type != BE_STR) {
   1724 		ND_PRINT((ndo, "[msgPrivacyParameters!=STR]"));
   1725 		asn1_print(ndo, &elem);
   1726 		return;
   1727 	}
   1728 	length -= count;
   1729         np += count;
   1730 
   1731 	if ((u_int)count < length)
   1732 		ND_PRINT((ndo, "[%d extra after usm SEQ]", length - count));
   1733 }
   1734 
   1735 /*
   1736  * Decode SNMPv3 Message Header (SNMPv3)
   1737  */
   1738 static void
   1739 v3msg_print(netdissect_options *ndo,
   1740             const u_char *np, u_int length)
   1741 {
   1742 	struct be elem;
   1743 	int count = 0;
   1744 	u_char flags;
   1745 	int model;
   1746 	const u_char *xnp = np;
   1747 	int xlength = length;
   1748 
   1749 	/* Sequence */
   1750 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1751 		return;
   1752 	if (elem.type != BE_SEQ) {
   1753 		ND_PRINT((ndo, "[!message]"));
   1754 		asn1_print(ndo, &elem);
   1755 		return;
   1756 	}
   1757 	length = elem.asnlen;
   1758 	np = (const u_char *)elem.data.raw;
   1759 
   1760 	if (ndo->ndo_vflag) {
   1761 		ND_PRINT((ndo, "{ "));
   1762 	}
   1763 
   1764 	/* msgID (INTEGER) */
   1765 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1766 		return;
   1767 	if (elem.type != BE_INT) {
   1768 		ND_PRINT((ndo, "[msgID!=INT]"));
   1769 		asn1_print(ndo, &elem);
   1770 		return;
   1771 	}
   1772 	length -= count;
   1773 	np += count;
   1774 
   1775 	/* msgMaxSize (INTEGER) */
   1776 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1777 		return;
   1778 	if (elem.type != BE_INT) {
   1779 		ND_PRINT((ndo, "[msgMaxSize!=INT]"));
   1780 		asn1_print(ndo, &elem);
   1781 		return;
   1782 	}
   1783 	length -= count;
   1784 	np += count;
   1785 
   1786 	/* msgFlags (OCTET STRING) */
   1787 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1788 		return;
   1789 	if (elem.type != BE_STR) {
   1790 		ND_PRINT((ndo, "[msgFlags!=STR]"));
   1791 		asn1_print(ndo, &elem);
   1792 		return;
   1793 	}
   1794 	if (elem.asnlen != 1) {
   1795 		ND_PRINT((ndo, "[msgFlags size %d]", elem.asnlen));
   1796 		return;
   1797 	}
   1798 	flags = elem.data.str[0];
   1799 	if (flags != 0x00 && flags != 0x01 && flags != 0x03
   1800 	    && flags != 0x04 && flags != 0x05 && flags != 0x07) {
   1801 		ND_PRINT((ndo, "[msgFlags=0x%02X]", flags));
   1802 		return;
   1803 	}
   1804 	length -= count;
   1805 	np += count;
   1806 
   1807 	ND_PRINT((ndo, "F=%s%s%s ",
   1808 	          flags & 0x01 ? "a" : "",
   1809 	          flags & 0x02 ? "p" : "",
   1810 	          flags & 0x04 ? "r" : ""));
   1811 
   1812 	/* msgSecurityModel (INTEGER) */
   1813 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1814 		return;
   1815 	if (elem.type != BE_INT) {
   1816 		ND_PRINT((ndo, "[msgSecurityModel!=INT]"));
   1817 		asn1_print(ndo, &elem);
   1818 		return;
   1819 	}
   1820 	model = elem.data.integer;
   1821 	length -= count;
   1822 	np += count;
   1823 
   1824 	if ((u_int)count < length)
   1825 		ND_PRINT((ndo, "[%d extra after message SEQ]", length - count));
   1826 
   1827 	if (ndo->ndo_vflag) {
   1828 		ND_PRINT((ndo, "} "));
   1829 	}
   1830 
   1831 	if (model == 3) {
   1832 	    if (ndo->ndo_vflag) {
   1833 		ND_PRINT((ndo, "{ USM "));
   1834 	    }
   1835 	} else {
   1836 	    ND_PRINT((ndo, "[security model %d]", model));
   1837             return;
   1838 	}
   1839 
   1840 	np = xnp + (np - xnp);
   1841 	length = xlength - (np - xnp);
   1842 
   1843 	/* msgSecurityParameters (OCTET STRING) */
   1844 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1845 		return;
   1846 	if (elem.type != BE_STR) {
   1847 		ND_PRINT((ndo, "[msgSecurityParameters!=STR]"));
   1848 		asn1_print(ndo, &elem);
   1849 		return;
   1850 	}
   1851 	length -= count;
   1852 	np += count;
   1853 
   1854 	if (model == 3) {
   1855 	    usm_print(ndo, elem.data.str, elem.asnlen);
   1856 	    if (ndo->ndo_vflag) {
   1857 		ND_PRINT((ndo, "} "));
   1858 	    }
   1859 	}
   1860 
   1861 	if (ndo->ndo_vflag) {
   1862 	    ND_PRINT((ndo, "{ ScopedPDU "));
   1863 	}
   1864 
   1865 	scopedpdu_print(ndo, np, length, 3);
   1866 
   1867 	if (ndo->ndo_vflag) {
   1868 		ND_PRINT((ndo, "} "));
   1869 	}
   1870 }
   1871 
   1872 /*
   1873  * Decode SNMP header and pass on to PDU printing routines
   1874  */
   1875 void
   1876 snmp_print(netdissect_options *ndo,
   1877            const u_char *np, u_int length)
   1878 {
   1879 	struct be elem;
   1880 	int count = 0;
   1881 	int version = 0;
   1882 
   1883 	ND_PRINT((ndo, " "));
   1884 
   1885 	/* initial Sequence */
   1886 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1887 		return;
   1888 	if (elem.type != BE_SEQ) {
   1889 		ND_PRINT((ndo, "[!init SEQ]"));
   1890 		asn1_print(ndo, &elem);
   1891 		return;
   1892 	}
   1893 	if ((u_int)count < length)
   1894 		ND_PRINT((ndo, "[%d extra after iSEQ]", length - count));
   1895 	/* descend */
   1896 	length = elem.asnlen;
   1897 	np = (const u_char *)elem.data.raw;
   1898 
   1899 	/* Version (INTEGER) */
   1900 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
   1901 		return;
   1902 	if (elem.type != BE_INT) {
   1903 		ND_PRINT((ndo, "[version!=INT]"));
   1904 		asn1_print(ndo, &elem);
   1905 		return;
   1906 	}
   1907 
   1908 	switch (elem.data.integer) {
   1909 	case SNMP_VERSION_1:
   1910 	case SNMP_VERSION_2:
   1911 	case SNMP_VERSION_3:
   1912 		if (ndo->ndo_vflag)
   1913 			ND_PRINT((ndo, "{ %s ", SnmpVersion[elem.data.integer]));
   1914 		break;
   1915 	default:
   1916 	        ND_PRINT((ndo, "SNMP [version = %d]", elem.data.integer));
   1917 		return;
   1918 	}
   1919 	version = elem.data.integer;
   1920 	length -= count;
   1921 	np += count;
   1922 
   1923 	switch (version) {
   1924 	case SNMP_VERSION_1:
   1925         case SNMP_VERSION_2:
   1926 		community_print(ndo, np, length, version);
   1927 		break;
   1928 	case SNMP_VERSION_3:
   1929 		v3msg_print(ndo, np, length);
   1930 		break;
   1931 	default:
   1932 		ND_PRINT((ndo, "[version = %d]", elem.data.integer));
   1933 		break;
   1934 	}
   1935 
   1936 	if (ndo->ndo_vflag) {
   1937 		ND_PRINT((ndo, "} "));
   1938 	}
   1939 }
   1940