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