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