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