auto import from //depot/cupcake/@135843
diff --git a/print-snmp.c b/print-snmp.c
new file mode 100644
index 0000000..0686b62
--- /dev/null
+++ b/print-snmp.c
@@ -0,0 +1,1904 @@
+/*
+ * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
+ *     John Robert LoVerso. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * This implementation has been influenced by the CMU SNMP release,
+ * by Steve Waldbusser.  However, this shares no code with that system.
+ * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
+ * Earlier forms of this implementation were derived and/or inspired by an
+ * awk script originally written by C. Philip Wood of LANL (but later
+ * heavily modified by John Robert LoVerso).  The copyright notice for
+ * that work is preserved below, even though it may not rightly apply
+ * to this file.
+ *
+ * Support for SNMPv2c/SNMPv3 and the ability to link the module against
+ * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
+ *
+ * This started out as a very simple program, but the incremental decoding
+ * (into the BE structure) complicated things.
+ *
+ #			Los Alamos National Laboratory
+ #
+ #	Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
+ #	This software was produced under a U.S. Government contract
+ #	(W-7405-ENG-36) by Los Alamos National Laboratory, which is
+ #	operated by the	University of California for the U.S. Department
+ #	of Energy.  The U.S. Government is licensed to use, reproduce,
+ #	and distribute this software.  Permission is granted to the
+ #	public to copy and use this software without charge, provided
+ #	that this Notice and any statement of authorship are reproduced
+ #	on all copies.  Neither the Government nor the University makes
+ #	any warranty, express or implied, or assumes any liability or
+ #	responsibility for the use of this software.
+ #	@(#)snmp.awk.x	1.1 (LANL) 1/15/90
+ */
+
+#ifndef lint
+static const char rcsid[] _U_ =
+    "@(#) $Header: /tcpdump/master/tcpdump/print-snmp.c,v 1.62.2.2 2005/05/06 07:57:19 guy Exp $ (LBL)";
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <tcpdump-stdinc.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_SMI_H
+#include <smi.h>
+#endif
+
+#include "interface.h"
+#include "addrtoname.h"
+
+#undef OPAQUE  /* defined in <wingdi.h> */
+
+/*
+ * Universal ASN.1 types
+ * (we only care about the tag values for those allowed in the Internet SMI)
+ */
+const char *Universal[] = {
+	"U-0",
+	"Boolean",
+	"Integer",
+#define INTEGER 2
+	"Bitstring",
+	"String",
+#define STRING 4
+	"Null",
+#define ASN_NULL 5
+	"ObjID",
+#define OBJECTID 6
+	"ObjectDes",
+	"U-8","U-9","U-10","U-11",	/* 8-11 */
+	"U-12","U-13","U-14","U-15",	/* 12-15 */
+	"Sequence",
+#define SEQUENCE 16
+	"Set"
+};
+
+/*
+ * Application-wide ASN.1 types from the Internet SMI and their tags
+ */
+const char *Application[] = {
+	"IpAddress",
+#define IPADDR 0
+	"Counter",
+#define COUNTER 1
+	"Gauge",
+#define GAUGE 2
+	"TimeTicks",
+#define TIMETICKS 3
+	"Opaque",
+#define OPAQUE 4
+	"C-5",
+	"Counter64"
+#define COUNTER64 6
+};
+
+/*
+ * Context-specific ASN.1 types for the SNMP PDUs and their tags
+ */
+const char *Context[] = {
+	"GetRequest",
+#define GETREQ 0
+	"GetNextRequest",
+#define GETNEXTREQ 1
+	"GetResponse",
+#define GETRESP 2
+	"SetRequest",
+#define SETREQ 3
+	"Trap",
+#define TRAP 4
+	"GetBulk",
+#define GETBULKREQ 5
+	"Inform",
+#define INFORMREQ 6
+	"V2Trap",
+#define V2TRAP 7
+	"Report"
+#define REPORT 8
+};
+
+#define NOTIFY_CLASS(x)	    (x == TRAP || x == V2TRAP || x == INFORMREQ)
+#define READ_CLASS(x)       (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
+#define WRITE_CLASS(x)	    (x == SETREQ)
+#define RESPONSE_CLASS(x)   (x == GETRESP)
+#define INTERNAL_CLASS(x)   (x == REPORT)
+
+/*
+ * Context-specific ASN.1 types for the SNMP Exceptions and their tags
+ */
+const char *Exceptions[] = {
+	"noSuchObject",
+#define NOSUCHOBJECT 0
+	"noSuchInstance",
+#define NOSUCHINSTANCE 1
+	"endOfMibView",
+#define ENDOFMIBVIEW 2
+};
+
+/*
+ * Private ASN.1 types
+ * The Internet SMI does not specify any
+ */
+const char *Private[] = {
+	"P-0"
+};
+
+/*
+ * error-status values for any SNMP PDU
+ */
+const char *ErrorStatus[] = {
+	"noError",
+	"tooBig",
+	"noSuchName",
+	"badValue",
+	"readOnly",
+	"genErr",
+	"noAccess",
+	"wrongType",
+	"wrongLength",
+	"wrongEncoding",
+	"wrongValue",
+	"noCreation",
+	"inconsistentValue",
+	"resourceUnavailable",
+	"commitFailed",
+	"undoFailed",
+	"authorizationError",
+	"notWritable",
+	"inconsistentName"
+};
+#define DECODE_ErrorStatus(e) \
+	( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
+		? ErrorStatus[e] \
+		: (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
+
+/*
+ * generic-trap values in the SNMP Trap-PDU
+ */
+const char *GenericTrap[] = {
+	"coldStart",
+	"warmStart",
+	"linkDown",
+	"linkUp",
+	"authenticationFailure",
+	"egpNeighborLoss",
+	"enterpriseSpecific"
+#define GT_ENTERPRISE 6
+};
+#define DECODE_GenericTrap(t) \
+	( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
+		? GenericTrap[t] \
+		: (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
+
+/*
+ * ASN.1 type class table
+ * Ties together the preceding Universal, Application, Context, and Private
+ * type definitions.
+ */
+#define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
+struct {
+	const char	*name;
+	const char	**Id;
+	    int	numIDs;
+    } Class[] = {
+	defineCLASS(Universal),
+#define	UNIVERSAL	0
+	defineCLASS(Application),
+#define	APPLICATION	1
+	defineCLASS(Context),
+#define	CONTEXT		2
+	defineCLASS(Private),
+#define	PRIVATE		3
+	defineCLASS(Exceptions),
+#define EXCEPTIONS	4
+};
+
+/*
+ * defined forms for ASN.1 types
+ */
+const char *Form[] = {
+	"Primitive",
+#define PRIMITIVE	0
+	"Constructed",
+#define CONSTRUCTED	1
+};
+
+/*
+ * A structure for the OID tree for the compiled-in MIB.
+ * This is stored as a general-order tree.
+ */
+struct obj {
+	const char	*desc;		/* name of object */
+	u_char	oid;			/* sub-id following parent */
+	u_char	type;			/* object type (unused) */
+	struct obj *child, *next;	/* child and next sibling pointers */
+} *objp = NULL;
+
+/*
+ * Include the compiled in SNMP MIB.  "mib.h" is produced by feeding
+ * RFC-1156 format files into "makemib".  "mib.h" MUST define at least
+ * a value for `mibroot'.
+ *
+ * In particular, this is gross, as this is including initialized structures,
+ * and by right shouldn't be an "include" file.
+ */
+#include "mib.h"
+
+/*
+ * This defines a list of OIDs which will be abbreviated on output.
+ * Currently, this includes the prefixes for the Internet MIB, the
+ * private enterprises tree, and the experimental tree.
+ */
+struct obj_abrev {
+	const char *prefix;		/* prefix for this abrev */
+	struct obj *node;		/* pointer into object table */
+	const char *oid;		/* ASN.1 encoded OID */
+} obj_abrev_list[] = {
+#ifndef NO_ABREV_MIB
+	/* .iso.org.dod.internet.mgmt.mib */
+	{ "",	&_mib_obj,		"\53\6\1\2\1" },
+#endif
+#ifndef NO_ABREV_ENTER
+	/* .iso.org.dod.internet.private.enterprises */
+	{ "E:",	&_enterprises_obj,	"\53\6\1\4\1" },
+#endif
+#ifndef NO_ABREV_EXPERI
+	/* .iso.org.dod.internet.experimental */
+	{ "X:",	&_experimental_obj,	"\53\6\1\3" },
+#endif
+#ifndef NO_ABBREV_SNMPMODS
+	/* .iso.org.dod.internet.snmpV2.snmpModules */
+        { "S:", &_snmpModules_obj,      "\53\6\1\6\3" },
+#endif
+	{ 0,0,0 }
+};
+
+/*
+ * This is used in the OID print routine to walk down the object tree
+ * rooted at `mibroot'.
+ */
+#define OBJ_PRINT(o, suppressdot) \
+{ \
+	if (objp) { \
+		do { \
+			if ((o) == objp->oid) \
+				break; \
+		} while ((objp = objp->next) != NULL); \
+	} \
+	if (objp) { \
+		printf(suppressdot?"%s":".%s", objp->desc); \
+		objp = objp->child; \
+	} else \
+		printf(suppressdot?"%u":".%u", (o)); \
+}
+
+/*
+ * This is the definition for the Any-Data-Type storage used purely for
+ * temporary internal representation while decoding an ASN.1 data stream.
+ */
+struct be {
+	u_int32_t asnlen;
+	union {
+		caddr_t raw;
+		int32_t integer;
+		u_int32_t uns;
+		const u_char *str;
+	        struct {
+		        u_int32_t high;
+		        u_int32_t low;
+		} uns64;
+	} data;
+	u_short id;
+	u_char form, class;		/* tag info */
+	u_char type;
+#define BE_ANY		255
+#define BE_NONE		0
+#define BE_NULL		1
+#define BE_OCTET	2
+#define BE_OID		3
+#define BE_INT		4
+#define BE_UNS		5
+#define BE_STR		6
+#define BE_SEQ		7
+#define BE_INETADDR	8
+#define BE_PDU		9
+#define BE_UNS64	10
+#define BE_NOSUCHOBJECT	128
+#define BE_NOSUCHINST	129
+#define BE_ENDOFMIBVIEW	130
+};
+
+/*
+ * SNMP versions recognized by this module
+ */
+const char *SnmpVersion[] = {
+	"SNMPv1",
+#define SNMP_VERSION_1	0
+	"SNMPv2c",
+#define SNMP_VERSION_2	1
+	"SNMPv2u",
+#define SNMP_VERSION_2U	2
+	"SNMPv3"
+#define SNMP_VERSION_3	3
+};
+
+/*
+ * Defaults for SNMP PDU components
+ */
+#define DEF_COMMUNITY "public"
+
+/*
+ * constants for ASN.1 decoding
+ */
+#define OIDMUX 40
+#define ASNLEN_INETADDR 4
+#define ASN_SHIFT7 7
+#define ASN_SHIFT8 8
+#define ASN_BIT8 0x80
+#define ASN_LONGLEN 0x80
+
+#define ASN_ID_BITS 0x1f
+#define ASN_FORM_BITS 0x20
+#define ASN_FORM_SHIFT 5
+#define ASN_CLASS_BITS 0xc0
+#define ASN_CLASS_SHIFT 6
+
+#define ASN_ID_EXT 0x1f		/* extension ID in tag field */
+
+/*
+ * This decodes the next ASN.1 object in the stream pointed to by "p"
+ * (and of real-length "len") and stores the intermediate data in the
+ * provided BE object.
+ *
+ * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
+ * O/w, this returns the number of bytes parsed from "p".
+ */
+static int
+asn1_parse(register const u_char *p, u_int len, struct be *elem)
+{
+	u_char form, class, id;
+	int i, hdr;
+
+	elem->asnlen = 0;
+	elem->type = BE_ANY;
+	if (len < 1) {
+		fputs("[nothing to parse]", stdout);
+		return -1;
+	}
+	TCHECK(*p);
+
+	/*
+	 * it would be nice to use a bit field, but you can't depend on them.
+	 *  +---+---+---+---+---+---+---+---+
+	 *  + class |frm|        id         |
+	 *  +---+---+---+---+---+---+---+---+
+	 *    7   6   5   4   3   2   1   0
+	 */
+	id = *p & ASN_ID_BITS;		/* lower 5 bits, range 00-1f */
+#ifdef notdef
+	form = (*p & 0xe0) >> 5;	/* move upper 3 bits to lower 3 */
+	class = form >> 1;		/* bits 7&6 -> bits 1&0, range 0-3 */
+	form &= 0x1;			/* bit 5 -> bit 0, range 0-1 */
+#else
+	form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
+	class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
+#endif
+	elem->form = form;
+	elem->class = class;
+	elem->id = id;
+	p++; len--; hdr = 1;
+	/* extended tag field */
+	if (id == ASN_ID_EXT) {
+		/*
+		 * The ID follows, as a sequence of octets with the
+		 * 8th bit set and the remaining 7 bits being
+		 * the next 7 bits of the value, terminated with
+		 * an octet with the 8th bit not set.
+		 *
+		 * First, assemble all the octets with the 8th
+		 * bit set.  XXX - this doesn't handle a value
+		 * that won't fit in 32 bits.
+		 */
+		for (id = 0; *p & ASN_BIT8; len--, hdr++, p++) {
+			if (len < 1) {
+				fputs("[Xtagfield?]", stdout);
+				return -1;
+			}
+			TCHECK(*p);
+			id = (id << 7) | (*p & ~ASN_BIT8);
+		}
+		if (len < 1) {
+			fputs("[Xtagfield?]", stdout);
+			return -1;
+		}
+		TCHECK(*p);
+		elem->id = id = (id << 7) | *p;
+		--len;
+		++hdr;
+		++p;
+	}
+	if (len < 1) {
+		fputs("[no asnlen]", stdout);
+		return -1;
+	}
+	TCHECK(*p);
+	elem->asnlen = *p;
+	p++; len--; hdr++;
+	if (elem->asnlen & ASN_BIT8) {
+		u_int32_t noct = elem->asnlen % ASN_BIT8;
+		elem->asnlen = 0;
+		if (len < noct) {
+			printf("[asnlen? %d<%d]", len, noct);
+			return -1;
+		}
+		TCHECK2(*p, noct);
+		for (; noct-- > 0; len--, hdr++)
+			elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
+	}
+	if (len < elem->asnlen) {
+		printf("[len%d<asnlen%u]", len, elem->asnlen);
+		return -1;
+	}
+	if (form >= sizeof(Form)/sizeof(Form[0])) {
+		printf("[form?%d]", form);
+		return -1;
+	}
+	if (class >= sizeof(Class)/sizeof(Class[0])) {
+		printf("[class?%c/%d]", *Form[form], class);
+		return -1;
+	}
+	if ((int)id >= Class[class].numIDs) {
+		printf("[id?%c/%s/%d]", *Form[form], Class[class].name, id);
+		return -1;
+	}
+
+	switch (form) {
+	case PRIMITIVE:
+		switch (class) {
+		case UNIVERSAL:
+			switch (id) {
+			case STRING:
+				elem->type = BE_STR;
+				elem->data.str = p;
+				break;
+
+			case INTEGER: {
+				register int32_t data;
+				elem->type = BE_INT;
+				data = 0;
+
+				TCHECK2(*p, elem->asnlen);
+				if (*p & ASN_BIT8)	/* negative */
+					data = -1;
+				for (i = elem->asnlen; i-- > 0; p++)
+					data = (data << ASN_SHIFT8) | *p;
+				elem->data.integer = data;
+				break;
+			}
+
+			case OBJECTID:
+				elem->type = BE_OID;
+				elem->data.raw = (caddr_t)p;
+				break;
+
+			case ASN_NULL:
+				elem->type = BE_NULL;
+				elem->data.raw = NULL;
+				break;
+
+			default:
+				elem->type = BE_OCTET;
+				elem->data.raw = (caddr_t)p;
+				printf("[P/U/%s]",
+					Class[class].Id[id]);
+				break;
+			}
+			break;
+
+		case APPLICATION:
+			switch (id) {
+			case IPADDR:
+				elem->type = BE_INETADDR;
+				elem->data.raw = (caddr_t)p;
+				break;
+
+			case COUNTER:
+			case GAUGE:
+			case TIMETICKS: {
+				register u_int32_t data;
+				TCHECK2(*p, elem->asnlen);
+				elem->type = BE_UNS;
+				data = 0;
+				for (i = elem->asnlen; i-- > 0; p++)
+					data = (data << 8) + *p;
+				elem->data.uns = data;
+				break;
+			}
+
+			case COUNTER64: {
+				register u_int32_t high, low;
+				TCHECK2(*p, elem->asnlen);
+			        elem->type = BE_UNS64;
+				high = 0, low = 0;
+				for (i = elem->asnlen; i-- > 0; p++) {
+				        high = (high << 8) |
+					    ((low & 0xFF000000) >> 24);
+					low = (low << 8) | *p;
+				}
+				elem->data.uns64.high = high;
+				elem->data.uns64.low = low;
+				break;
+			}
+
+			default:
+				elem->type = BE_OCTET;
+				elem->data.raw = (caddr_t)p;
+				printf("[P/A/%s]",
+					Class[class].Id[id]);
+				break;
+			}
+			break;
+
+		case CONTEXT:
+			switch (id) {
+			case NOSUCHOBJECT:
+				elem->type = BE_NOSUCHOBJECT;
+				elem->data.raw = NULL;
+				break;
+
+			case NOSUCHINSTANCE:
+				elem->type = BE_NOSUCHINST;
+				elem->data.raw = NULL;
+				break;
+
+			case ENDOFMIBVIEW:
+				elem->type = BE_ENDOFMIBVIEW;
+				elem->data.raw = NULL;
+				break;
+			}
+			break;
+
+		default:
+			printf("[P/%s/%s]",
+				Class[class].name, Class[class].Id[id]);
+			TCHECK2(*p, elem->asnlen);
+			elem->type = BE_OCTET;
+			elem->data.raw = (caddr_t)p;
+			break;
+		}
+		break;
+
+	case CONSTRUCTED:
+		switch (class) {
+		case UNIVERSAL:
+			switch (id) {
+			case SEQUENCE:
+				elem->type = BE_SEQ;
+				elem->data.raw = (caddr_t)p;
+				break;
+
+			default:
+				elem->type = BE_OCTET;
+				elem->data.raw = (caddr_t)p;
+				printf("C/U/%s", Class[class].Id[id]);
+				break;
+			}
+			break;
+
+		case CONTEXT:
+			elem->type = BE_PDU;
+			elem->data.raw = (caddr_t)p;
+			break;
+
+		default:
+			elem->type = BE_OCTET;
+			elem->data.raw = (caddr_t)p;
+			printf("C/%s/%s",
+				Class[class].name, Class[class].Id[id]);
+			break;
+		}
+		break;
+	}
+	p += elem->asnlen;
+	len -= elem->asnlen;
+	return elem->asnlen + hdr;
+
+trunc:
+	fputs("[|snmp]", stdout);
+	return -1;
+}
+
+/*
+ * Display the ASN.1 object represented by the BE object.
+ * This used to be an integral part of asn1_parse() before the intermediate
+ * BE form was added.
+ */
+static int
+asn1_print(struct be *elem)
+{
+	u_char *p = (u_char *)elem->data.raw;
+	u_int32_t asnlen = elem->asnlen;
+	u_int32_t i;
+
+	switch (elem->type) {
+
+	case BE_OCTET:
+		TCHECK2(*p, asnlen);
+		for (i = asnlen; i-- > 0; p++)
+			printf("_%.2x", *p);
+		break;
+
+	case BE_NULL:
+		break;
+
+	case BE_OID: {
+		int o = 0, first = -1, i = asnlen;
+
+		if (!sflag && !nflag && asnlen > 2) {
+			struct obj_abrev *a = &obj_abrev_list[0];
+			size_t a_len = strlen(a->oid);
+			for (; a->node; a++) {
+				TCHECK2(*p, a_len);
+				if (memcmp(a->oid, (char *)p, a_len) == 0) {
+					objp = a->node->child;
+					i -= strlen(a->oid);
+					p += strlen(a->oid);
+					fputs(a->prefix, stdout);
+					first = 1;
+					break;
+				}
+			}
+		}
+
+		for (; !sflag && i-- > 0; p++) {
+			TCHECK(*p);
+			o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
+			if (*p & ASN_LONGLEN)
+			        continue;
+
+			/*
+			 * first subitem encodes two items with 1st*OIDMUX+2nd
+			 * (see X.690:1997 clause 8.19 for the details)
+			 */
+			if (first < 0) {
+			        int s;
+				if (!nflag)
+					objp = mibroot;
+				first = 0;
+				s = o / OIDMUX;
+				if (s > 2) s = 2;
+				OBJ_PRINT(s, first);
+				o -= s * OIDMUX;
+			}
+			OBJ_PRINT(o, first);
+			if (--first < 0)
+				first = 0;
+			o = 0;
+		}
+		break;
+	}
+
+	case BE_INT:
+		printf("%d", elem->data.integer);
+		break;
+
+	case BE_UNS:
+		printf("%u", elem->data.uns);
+		break;
+
+	case BE_UNS64: {	/* idea borrowed from by Marshall Rose */
+	        double d;
+		int j, carry;
+		char *cpf, *cpl, last[6], first[30];
+		if (elem->data.uns64.high == 0) {
+		        printf("%u", elem->data.uns64.low);
+		        break;
+		}
+		d = elem->data.uns64.high * 4294967296.0;	/* 2^32 */
+		if (elem->data.uns64.high <= 0x1fffff) {
+		        d += elem->data.uns64.low;
+#if 0 /*is looks illegal, but what is the intention?*/
+			printf("%.f", d);
+#else
+			printf("%f", d);
+#endif
+			break;
+		}
+		d += (elem->data.uns64.low & 0xfffff000);
+#if 0 /*is looks illegal, but what is the intention?*/
+		snprintf(first, sizeof(first), "%.f", d);
+#else
+		snprintf(first, sizeof(first), "%f", d);
+#endif
+		snprintf(last, sizeof(last), "%5.5d",
+		    elem->data.uns64.low & 0xfff);
+		for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
+		     cpl >= last;
+		     cpf--, cpl--) {
+		        j = carry + (*cpf - '0') + (*cpl - '0');
+			if (j > 9) {
+			        j -= 10;
+				carry = 1;
+			} else {
+			        carry = 0;
+		        }
+			*cpf = j + '0';
+		}
+		fputs(first, stdout);
+		break;
+	}
+
+	case BE_STR: {
+		register int printable = 1, first = 1;
+		const u_char *p = elem->data.str;
+		TCHECK2(*p, asnlen);
+		for (i = asnlen; printable && i-- > 0; p++)
+			printable = isprint(*p) || isspace(*p);
+		p = elem->data.str;
+		if (printable) {
+			putchar('"');
+			if (fn_printn(p, asnlen, snapend)) {
+				putchar('"');
+				goto trunc;
+			}
+			putchar('"');
+		} else
+			for (i = asnlen; i-- > 0; p++) {
+				printf(first ? "%.2x" : "_%.2x", *p);
+				first = 0;
+			}
+		break;
+	}
+
+	case BE_SEQ:
+		printf("Seq(%u)", elem->asnlen);
+		break;
+
+	case BE_INETADDR:
+		if (asnlen != ASNLEN_INETADDR)
+			printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
+		TCHECK2(*p, asnlen);
+		for (i = asnlen; i-- != 0; p++) {
+			printf((i == asnlen-1) ? "%u" : ".%u", *p);
+		}
+		break;
+
+	case BE_NOSUCHOBJECT:
+	case BE_NOSUCHINST:
+	case BE_ENDOFMIBVIEW:
+	        printf("[%s]", Class[EXCEPTIONS].Id[elem->id]);
+		break;
+
+	case BE_PDU:
+		printf("%s(%u)",
+			Class[CONTEXT].Id[elem->id], elem->asnlen);
+		break;
+
+	case BE_ANY:
+		fputs("[BE_ANY!?]", stdout);
+		break;
+
+	default:
+		fputs("[be!?]", stdout);
+		break;
+	}
+	return 0;
+
+trunc:
+	fputs("[|snmp]", stdout);
+	return -1;
+}
+
+#ifdef notdef
+/*
+ * This is a brute force ASN.1 printer: recurses to dump an entire structure.
+ * This will work for any ASN.1 stream, not just an SNMP PDU.
+ *
+ * By adding newlines and spaces at the correct places, this would print in
+ * Rose-Normal-Form.
+ *
+ * This is not currently used.
+ */
+static void
+asn1_decode(u_char *p, u_int length)
+{
+	struct be elem;
+	int i = 0;
+
+	while (i >= 0 && length > 0) {
+		i = asn1_parse(p, length, &elem);
+		if (i >= 0) {
+			fputs(" ", stdout);
+			if (asn1_print(&elem) < 0)
+				return;
+			if (elem.type == BE_SEQ || elem.type == BE_PDU) {
+				fputs(" {", stdout);
+				asn1_decode(elem.data.raw, elem.asnlen);
+				fputs(" }", stdout);
+			}
+			length -= i;
+			p += i;
+		}
+	}
+}
+#endif
+
+#ifdef LIBSMI
+
+struct smi2be {
+    SmiBasetype basetype;
+    int be;
+};
+
+static struct smi2be smi2betab[] = {
+    { SMI_BASETYPE_INTEGER32,		BE_INT },
+    { SMI_BASETYPE_OCTETSTRING,		BE_STR },
+    { SMI_BASETYPE_OCTETSTRING,		BE_INETADDR },
+    { SMI_BASETYPE_OBJECTIDENTIFIER,	BE_OID },
+    { SMI_BASETYPE_UNSIGNED32,		BE_UNS },
+    { SMI_BASETYPE_INTEGER64,		BE_NONE },
+    { SMI_BASETYPE_UNSIGNED64,		BE_UNS64 },
+    { SMI_BASETYPE_FLOAT32,		BE_NONE },
+    { SMI_BASETYPE_FLOAT64,		BE_NONE },
+    { SMI_BASETYPE_FLOAT128,		BE_NONE },
+    { SMI_BASETYPE_ENUM,		BE_INT },
+    { SMI_BASETYPE_BITS,		BE_STR },
+    { SMI_BASETYPE_UNKNOWN,		BE_NONE }
+};
+
+static int
+smi_decode_oid(struct be *elem, unsigned int *oid,
+	       unsigned int oidsize, unsigned int *oidlen)
+{
+	u_char *p = (u_char *)elem->data.raw;
+	u_int32_t asnlen = elem->asnlen;
+	int o = 0, first = -1, i = asnlen;
+
+	for (*oidlen = 0; sflag && i-- > 0; p++) {
+		TCHECK(*p);
+	        o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
+		if (*p & ASN_LONGLEN)
+		    continue;
+
+		/*
+		 * first subitem encodes two items with 1st*OIDMUX+2nd
+		 * (see X.690:1997 clause 8.19 for the details)
+		 */
+		if (first < 0) {
+		        first = 0;
+			if (*oidlen < oidsize) {
+			    oid[*oidlen] = o / OIDMUX;
+			    if (oid[*oidlen] > 2) oid[*oidlen] = 2;
+			}
+			o -= oid[*oidlen] * OIDMUX;
+			if (*oidlen < oidsize) (*oidlen)++;
+		}
+		if (*oidlen < oidsize) {
+			oid[(*oidlen)++] = o;
+		}
+		o = 0;
+	}
+	return 0;
+
+trunc:
+	fputs("[|snmp]", stdout);
+	return -1;
+}
+
+static int smi_check_type(SmiBasetype basetype, int be)
+{
+    int i;
+
+    for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
+	if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
+	    return 1;
+	}
+    }
+
+    return 0;
+}
+
+static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
+			     struct be *elem)
+{
+    int ok = 1;
+
+    switch (smiType->basetype) {
+    case SMI_BASETYPE_OBJECTIDENTIFIER:
+    case SMI_BASETYPE_OCTETSTRING:
+	if (smiRange->minValue.value.unsigned32
+	    == smiRange->maxValue.value.unsigned32) {
+	    ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
+	} else {
+	    ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
+		  && elem->asnlen <= smiRange->maxValue.value.unsigned32);
+	}
+	break;
+
+    case SMI_BASETYPE_INTEGER32:
+	ok = (elem->data.integer >= smiRange->minValue.value.integer32
+	      && elem->data.integer <= smiRange->maxValue.value.integer32);
+	break;
+
+    case SMI_BASETYPE_UNSIGNED32:
+	ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
+	      && elem->data.uns <= smiRange->maxValue.value.unsigned32);
+	break;
+
+    case SMI_BASETYPE_UNSIGNED64:
+	/* XXX */
+	break;
+
+	/* case SMI_BASETYPE_INTEGER64: SMIng */
+	/* case SMI_BASETYPE_FLOAT32: SMIng */
+	/* case SMI_BASETYPE_FLOAT64: SMIng */
+	/* case SMI_BASETYPE_FLOAT128: SMIng */
+
+    case SMI_BASETYPE_ENUM:
+    case SMI_BASETYPE_BITS:
+    case SMI_BASETYPE_UNKNOWN:
+	ok = 1;
+	break;
+
+    default:
+	ok = 0;
+	break;
+    }
+
+    return ok;
+}
+
+static int smi_check_range(SmiType *smiType, struct be *elem)
+{
+        SmiRange *smiRange;
+	int ok = 1;
+
+	for (smiRange = smiGetFirstRange(smiType);
+	     smiRange;
+	     smiRange = smiGetNextRange(smiRange)) {
+
+	    ok = smi_check_a_range(smiType, smiRange, elem);
+
+	    if (ok) {
+		break;
+	    }
+	}
+
+	if (ok) {
+	    SmiType *parentType;
+	    parentType = smiGetParentType(smiType);
+	    if (parentType) {
+		ok = smi_check_range(parentType, elem);
+	    }
+	}
+
+	return ok;
+}
+
+static SmiNode *smi_print_variable(struct be *elem, int *status)
+{
+	unsigned int oid[128], oidlen;
+	SmiNode *smiNode = NULL;
+	unsigned int i;
+
+	*status = smi_decode_oid(elem, oid, sizeof(oid)/sizeof(unsigned int),
+	    &oidlen);
+	if (*status < 0)
+		return NULL;
+	smiNode = smiGetNodeByOID(oidlen, oid);
+	if (! smiNode) {
+		*status = asn1_print(elem);
+		return NULL;
+	}
+	if (vflag) {
+		fputs(smiGetNodeModule(smiNode)->name, stdout);
+		fputs("::", stdout);
+	}
+	fputs(smiNode->name, stdout);
+	if (smiNode->oidlen < oidlen) {
+	        for (i = smiNode->oidlen; i < oidlen; i++) {
+		        printf(".%u", oid[i]);
+		}
+	}
+	*status = 0;
+	return smiNode;
+}
+
+static int
+smi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem)
+{
+	unsigned int i, oid[128], oidlen;
+	SmiType *smiType;
+	SmiNamedNumber *nn;
+	int done = 0;
+
+	if (! smiNode || ! (smiNode->nodekind
+			    & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
+	    return asn1_print(elem);
+	}
+
+	if (elem->type == BE_NOSUCHOBJECT
+	    || elem->type == BE_NOSUCHINST
+	    || elem->type == BE_ENDOFMIBVIEW) {
+	    return asn1_print(elem);
+	}
+
+	if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
+	    fputs("[notNotifyable]", stdout);
+	}
+
+	if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
+	    fputs("[notReadable]", stdout);
+	}
+
+	if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
+	    fputs("[notWritable]", stdout);
+	}
+
+	if (RESPONSE_CLASS(pduid)
+	    && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
+	    fputs("[noAccess]", stdout);
+	}
+
+	smiType = smiGetNodeType(smiNode);
+	if (! smiType) {
+	    return asn1_print(elem);
+	}
+
+	if (! smi_check_type(smiType->basetype, elem->type)) {
+	    fputs("[wrongType]", stdout);
+	}
+
+	if (! smi_check_range(smiType, elem)) {
+	    fputs("[outOfRange]", stdout);
+	}
+
+	/* resolve bits to named bits */
+
+	/* check whether instance identifier is valid */
+
+	/* apply display hints (integer, octetstring) */
+
+	/* convert instance identifier to index type values */
+
+	switch (elem->type) {
+	case BE_OID:
+	        if (smiType->basetype == SMI_BASETYPE_BITS) {
+		        /* print bit labels */
+		} else {
+		        smi_decode_oid(elem, oid,
+				       sizeof(oid)/sizeof(unsigned int),
+				       &oidlen);
+			smiNode = smiGetNodeByOID(oidlen, oid);
+			if (smiNode) {
+			        if (vflag) {
+					fputs(smiGetNodeModule(smiNode)->name, stdout);
+					fputs("::", stdout);
+				}
+				fputs(smiNode->name, stdout);
+				if (smiNode->oidlen < oidlen) {
+				        for (i = smiNode->oidlen;
+					     i < oidlen; i++) {
+					        printf(".%u", oid[i]);
+					}
+				}
+				done++;
+			}
+		}
+		break;
+
+	case BE_INT:
+	        if (smiType->basetype == SMI_BASETYPE_ENUM) {
+		        for (nn = smiGetFirstNamedNumber(smiType);
+			     nn;
+			     nn = smiGetNextNamedNumber(nn)) {
+			         if (nn->value.value.integer32
+				     == elem->data.integer) {
+				         fputs(nn->name, stdout);
+					 printf("(%d)", elem->data.integer);
+					 done++;
+					 break;
+				}
+			}
+		}
+		break;
+	}
+
+	if (! done) {
+		return asn1_print(elem);
+	}
+	return 0;
+}
+#endif
+
+/*
+ * General SNMP header
+ *	SEQUENCE {
+ *		version INTEGER {version-1(0)},
+ *		community OCTET STRING,
+ *		data ANY	-- PDUs
+ *	}
+ * PDUs for all but Trap: (see rfc1157 from page 15 on)
+ *	SEQUENCE {
+ *		request-id INTEGER,
+ *		error-status INTEGER,
+ *		error-index INTEGER,
+ *		varbindlist SEQUENCE OF
+ *			SEQUENCE {
+ *				name ObjectName,
+ *				value ObjectValue
+ *			}
+ *	}
+ * PDU for Trap:
+ *	SEQUENCE {
+ *		enterprise OBJECT IDENTIFIER,
+ *		agent-addr NetworkAddress,
+ *		generic-trap INTEGER,
+ *		specific-trap INTEGER,
+ *		time-stamp TimeTicks,
+ *		varbindlist SEQUENCE OF
+ *			SEQUENCE {
+ *				name ObjectName,
+ *				value ObjectValue
+ *			}
+ *	}
+ */
+
+/*
+ * Decode SNMP varBind
+ */
+static void
+varbind_print(u_char pduid, const u_char *np, u_int length)
+{
+	struct be elem;
+	int count = 0, ind;
+#ifdef LIBSMI
+	SmiNode *smiNode = NULL;
+#endif
+	int status;
+
+	/* Sequence of varBind */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_SEQ) {
+		fputs("[!SEQ of varbind]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if ((u_int)count < length)
+		printf("[%d extra after SEQ of varbind]", length - count);
+	/* descend */
+	length = elem.asnlen;
+	np = (u_char *)elem.data.raw;
+
+	for (ind = 1; length > 0; ind++) {
+		const u_char *vbend;
+		u_int vblength;
+
+		fputs(" ", stdout);
+
+		/* Sequence */
+		if ((count = asn1_parse(np, length, &elem)) < 0)
+			return;
+		if (elem.type != BE_SEQ) {
+			fputs("[!varbind]", stdout);
+			asn1_print(&elem);
+			return;
+		}
+		vbend = np + count;
+		vblength = length - count;
+		/* descend */
+		length = elem.asnlen;
+		np = (u_char *)elem.data.raw;
+
+		/* objName (OID) */
+		if ((count = asn1_parse(np, length, &elem)) < 0)
+			return;
+		if (elem.type != BE_OID) {
+			fputs("[objName!=OID]", stdout);
+			asn1_print(&elem);
+			return;
+		}
+#ifdef LIBSMI
+		smiNode = smi_print_variable(&elem, &status);
+#else
+		status = asn1_print(&elem);
+#endif
+		if (status < 0)
+			return;
+		length -= count;
+		np += count;
+
+		if (pduid != GETREQ && pduid != GETNEXTREQ
+		    && pduid != GETBULKREQ)
+			fputs("=", stdout);
+
+		/* objVal (ANY) */
+		if ((count = asn1_parse(np, length, &elem)) < 0)
+			return;
+		if (pduid == GETREQ || pduid == GETNEXTREQ
+		    || pduid == GETBULKREQ) {
+			if (elem.type != BE_NULL) {
+				fputs("[objVal!=NULL]", stdout);
+				if (asn1_print(&elem) < 0)
+					return;
+			}
+		} else {
+		        if (elem.type != BE_NULL) {
+#ifdef LIBSMI
+				status = smi_print_value(smiNode, pduid, &elem);
+#else
+				status = asn1_print(&elem);
+#endif
+			}
+			if (status < 0)
+				return;
+		}
+		length = vblength;
+		np = vbend;
+	}
+}
+
+/*
+ * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
+ * GetBulk, Inform, V2Trap, and Report
+ */
+static void
+snmppdu_print(u_short pduid, const u_char *np, u_int length)
+{
+	struct be elem;
+	int count = 0, error;
+
+	/* reqId (Integer) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[reqId!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if (vflag)
+		printf("R=%d ", elem.data.integer);
+	length -= count;
+	np += count;
+
+	/* errorStatus (Integer) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[errorStatus!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	error = 0;
+	if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
+	    || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
+	    && elem.data.integer != 0) {
+		char errbuf[20];
+		printf("[errorStatus(%s)!=0]",
+			DECODE_ErrorStatus(elem.data.integer));
+	} else if (pduid == GETBULKREQ) {
+	        printf(" N=%d", elem.data.integer);
+	} else if (elem.data.integer != 0) {
+		char errbuf[20];
+		printf(" %s", DECODE_ErrorStatus(elem.data.integer));
+		error = elem.data.integer;
+	}
+	length -= count;
+	np += count;
+
+	/* errorIndex (Integer) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[errorIndex!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
+	    || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
+	    && elem.data.integer != 0)
+		printf("[errorIndex(%d)!=0]", elem.data.integer);
+	else if (pduid == GETBULKREQ)
+	        printf(" M=%d", elem.data.integer);
+	else if (elem.data.integer != 0) {
+		if (!error)
+			printf("[errorIndex(%d) w/o errorStatus]",
+				elem.data.integer);
+		else {
+			printf("@%d", elem.data.integer);
+			error = elem.data.integer;
+		}
+	} else if (error) {
+		fputs("[errorIndex==0]", stdout);
+		error = 0;
+	}
+	length -= count;
+	np += count;
+
+	varbind_print(pduid, np, length);
+	return;
+}
+
+/*
+ * Decode SNMP Trap PDU
+ */
+static void
+trappdu_print(const u_char *np, u_int length)
+{
+	struct be elem;
+	int count = 0, generic;
+
+	putchar(' ');
+
+	/* enterprise (oid) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_OID) {
+		fputs("[enterprise!=OID]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if (asn1_print(&elem) < 0)
+		return;
+	length -= count;
+	np += count;
+
+	putchar(' ');
+
+	/* agent-addr (inetaddr) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INETADDR) {
+		fputs("[agent-addr!=INETADDR]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if (asn1_print(&elem) < 0)
+		return;
+	length -= count;
+	np += count;
+
+	/* generic-trap (Integer) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[generic-trap!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	generic = elem.data.integer;
+	{
+		char buf[20];
+		printf(" %s", DECODE_GenericTrap(generic));
+	}
+	length -= count;
+	np += count;
+
+	/* specific-trap (Integer) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[specific-trap!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if (generic != GT_ENTERPRISE) {
+		if (elem.data.integer != 0)
+			printf("[specific-trap(%d)!=0]", elem.data.integer);
+	} else
+		printf(" s=%d", elem.data.integer);
+	length -= count;
+	np += count;
+
+	putchar(' ');
+
+	/* time-stamp (TimeTicks) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_UNS) {			/* XXX */
+		fputs("[time-stamp!=TIMETICKS]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if (asn1_print(&elem) < 0)
+		return;
+	length -= count;
+	np += count;
+
+	varbind_print (TRAP, np, length);
+	return;
+}
+
+/*
+ * Decode arbitrary SNMP PDUs.
+ */
+static void
+pdu_print(const u_char *np, u_int length, int version)
+{
+	struct be pdu;
+	int count = 0;
+
+	/* PDU (Context) */
+	if ((count = asn1_parse(np, length, &pdu)) < 0)
+		return;
+	if (pdu.type != BE_PDU) {
+		fputs("[no PDU]", stdout);
+		return;
+	}
+	if ((u_int)count < length)
+		printf("[%d extra after PDU]", length - count);
+	if (vflag) {
+		fputs("{ ", stdout);
+	}
+	if (asn1_print(&pdu) < 0)
+		return;
+	fputs(" ", stdout);
+	/* descend into PDU */
+	length = pdu.asnlen;
+	np = (u_char *)pdu.data.raw;
+
+	if (version == SNMP_VERSION_1 &&
+	    (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
+	     pdu.id == V2TRAP || pdu.id == REPORT)) {
+	        printf("[v2 PDU in v1 message]");
+		return;
+	}
+
+	if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
+	        printf("[v1 PDU in v2 message]");
+		return;
+	}
+
+	switch (pdu.id) {
+	case TRAP:
+		trappdu_print(np, length);
+		break;
+	case GETREQ:
+	case GETNEXTREQ:
+	case GETRESP:
+	case SETREQ:
+	case GETBULKREQ:
+	case INFORMREQ:
+	case V2TRAP:
+	case REPORT:
+		snmppdu_print(pdu.id, np, length);
+		break;
+	}
+
+	if (vflag) {
+		fputs(" } ", stdout);
+	}
+}
+
+/*
+ * Decode a scoped SNMP PDU.
+ */
+static void
+scopedpdu_print(const u_char *np, u_int length, int version)
+{
+	struct be elem;
+	int i, count = 0;
+
+	/* Sequence */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_SEQ) {
+		fputs("[!scoped PDU]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length = elem.asnlen;
+	np = (u_char *)elem.data.raw;
+
+	/* contextEngineID (OCTET STRING) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_STR) {
+		fputs("[contextEngineID!=STR]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length -= count;
+	np += count;
+
+	fputs("E= ", stdout);
+	for (i = 0; i < (int)elem.asnlen; i++) {
+            printf("0x%02X", elem.data.str[i]);
+        }
+	fputs(" ", stdout);
+
+	/* contextName (OCTET STRING) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_STR) {
+		fputs("[contextName!=STR]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length -= count;
+	np += count;
+
+	printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
+
+	pdu_print(np, length, version);
+}
+
+/*
+ * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
+ */
+static void
+community_print(const u_char *np, u_int length, int version)
+{
+	struct be elem;
+	int count = 0;
+
+	/* Community (String) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_STR) {
+		fputs("[comm!=STR]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	/* default community */
+	if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
+	    strncmp((char *)elem.data.str, DEF_COMMUNITY,
+	            sizeof(DEF_COMMUNITY) - 1) == 0))
+		/* ! "public" */
+		printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
+	length -= count;
+	np += count;
+
+	pdu_print(np, length, version);
+}
+
+/*
+ * Decode SNMPv3 User-based Security Message Header (SNMPv3)
+ */
+static void
+usm_print(const u_char *np, u_int length)
+{
+        struct be elem;
+	int count = 0;
+
+	/* Sequence */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_SEQ) {
+		fputs("[!usm]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length = elem.asnlen;
+	np = (u_char *)elem.data.raw;
+
+	/* msgAuthoritativeEngineID (OCTET STRING) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_STR) {
+		fputs("[msgAuthoritativeEngineID!=STR]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length -= count;
+	np += count;
+
+	/* msgAuthoritativeEngineBoots (INTEGER) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[msgAuthoritativeEngineBoots!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if (vflag)
+	        printf("B=%d ", elem.data.integer);
+	length -= count;
+	np += count;
+
+	/* msgAuthoritativeEngineTime (INTEGER) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[msgAuthoritativeEngineTime!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if (vflag)
+	        printf("T=%d ", elem.data.integer);
+	length -= count;
+	np += count;
+
+	/* msgUserName (OCTET STRING) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_STR) {
+		fputs("[msgUserName!=STR]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length -= count;
+        np += count;
+
+	printf("U=%.*s ", (int)elem.asnlen, elem.data.str);
+
+	/* msgAuthenticationParameters (OCTET STRING) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_STR) {
+		fputs("[msgAuthenticationParameters!=STR]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length -= count;
+        np += count;
+
+	/* msgPrivacyParameters (OCTET STRING) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_STR) {
+		fputs("[msgPrivacyParameters!=STR]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length -= count;
+        np += count;
+
+	if ((u_int)count < length)
+		printf("[%d extra after usm SEQ]", length - count);
+}
+
+/*
+ * Decode SNMPv3 Message Header (SNMPv3)
+ */
+static void
+v3msg_print(const u_char *np, u_int length)
+{
+	struct be elem;
+	int count = 0;
+	u_char flags;
+	int model;
+	const u_char *xnp = np;
+	int xlength = length;
+
+	/* Sequence */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_SEQ) {
+		fputs("[!message]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length = elem.asnlen;
+	np = (u_char *)elem.data.raw;
+
+	if (vflag) {
+		fputs("{ ", stdout);
+	}
+
+	/* msgID (INTEGER) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[msgID!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length -= count;
+	np += count;
+
+	/* msgMaxSize (INTEGER) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[msgMaxSize!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length -= count;
+	np += count;
+
+	/* msgFlags (OCTET STRING) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_STR) {
+		fputs("[msgFlags!=STR]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if (elem.asnlen != 1) {
+	        printf("[msgFlags size %d]", elem.asnlen);
+		return;
+	}
+	flags = elem.data.str[0];
+	if (flags != 0x00 && flags != 0x01 && flags != 0x03
+	    && flags != 0x04 && flags != 0x05 && flags != 0x07) {
+		printf("[msgFlags=0x%02X]", flags);
+		return;
+	}
+	length -= count;
+	np += count;
+
+	fputs("F=", stdout);
+	if (flags & 0x01) fputs("a", stdout);
+	if (flags & 0x02) fputs("p", stdout);
+	if (flags & 0x04) fputs("r", stdout);
+	fputs(" ", stdout);
+
+	/* msgSecurityModel (INTEGER) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[msgSecurityModel!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	model = elem.data.integer;
+	length -= count;
+	np += count;
+
+	if ((u_int)count < length)
+		printf("[%d extra after message SEQ]", length - count);
+
+	if (vflag) {
+		fputs("} ", stdout);
+	}
+
+	if (model == 3) {
+	    if (vflag) {
+		fputs("{ USM ", stdout);
+	    }
+	} else {
+	    printf("[security model %d]", model);
+            return;
+	}
+
+	np = xnp + (np - xnp);
+	length = xlength - (np - xnp);
+
+	/* msgSecurityParameters (OCTET STRING) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_STR) {
+		fputs("[msgSecurityParameters!=STR]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	length -= count;
+	np += count;
+
+	if (model == 3) {
+	    usm_print(elem.data.str, elem.asnlen);
+	    if (vflag) {
+		fputs("} ", stdout);
+	    }
+	}
+
+	if (vflag) {
+	    fputs("{ ScopedPDU ", stdout);
+	}
+
+	scopedpdu_print(np, length, 3);
+
+	if (vflag) {
+		fputs("} ", stdout);
+	}
+}
+
+/*
+ * Decode SNMP header and pass on to PDU printing routines
+ */
+void
+snmp_print(const u_char *np, u_int length)
+{
+	struct be elem;
+	int count = 0;
+	int version = 0;
+
+	putchar(' ');
+
+	/* initial Sequence */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_SEQ) {
+		fputs("[!init SEQ]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+	if ((u_int)count < length)
+		printf("[%d extra after iSEQ]", length - count);
+	/* descend */
+	length = elem.asnlen;
+	np = (u_char *)elem.data.raw;
+
+	/* Version (INTEGER) */
+	if ((count = asn1_parse(np, length, &elem)) < 0)
+		return;
+	if (elem.type != BE_INT) {
+		fputs("[version!=INT]", stdout);
+		asn1_print(&elem);
+		return;
+	}
+
+	switch (elem.data.integer) {
+	case SNMP_VERSION_1:
+	case SNMP_VERSION_2:
+	case SNMP_VERSION_3:
+	        if (vflag)
+		        printf("{ %s ", SnmpVersion[elem.data.integer]);
+		break;
+	default:
+	        printf("[version = %d]", elem.data.integer);
+		return;
+	}
+	version = elem.data.integer;
+	length -= count;
+	np += count;
+
+	switch (version) {
+	case SNMP_VERSION_1:
+        case SNMP_VERSION_2:
+		community_print(np, length, version);
+		break;
+	case SNMP_VERSION_3:
+		v3msg_print(np, length);
+		break;
+	default:
+	        printf("[version = %d]", elem.data.integer);
+		break;
+	}
+
+	if (vflag) {
+		fputs("} ", stdout);
+	}
+}