Upgrade to tcpdump 4.9.0.

From CHANGES:

  Wednesday January 18, 2017 devel.fx.lebail@orange.fr
  Summary for 4.9.0 tcpdump release
    General updates:
    Improve separation frontend/backend (tcpdump/libnetdissect)
    Don't require IPv6 library support in order to support IPv6 addresses
    Introduce data types to use for integral values in packet structures
    Fix display of timestamps with -tt, -ttt and -ttttt options
    Fix some heap overflows found with American Fuzzy Lop by Hanno Boeck and others
        (More information in the log with CVE-2016-* and CVE-2017-*)
    Change the way protocols print link-layer addresses (Fix heap overflows
        in CALM-FAST and GeoNetworking printers)
    Pass correct caplen value to ether_print() and some other functions
    Fix lookup_nsap() to match what isonsap_string() expects
    Clean up relative time stamp printing (Fix an array overflow)
    Fix some alignment issues with GCC on Solaris 10 SPARC
    Add some ND_TTEST_/ND_TCHECK_ macros to simplify writing bounds checks
    Add a fn_printztn() which returns the number of bytes processed
    Add nd_init() and nd_cleanup() functions. Improve libsmi support
    Add CONTRIBUTING file
    Add a summary comment in all printers
    Compile with more warning options in devel mode if supported (-Wcast-qual, ...)
    Fix some leaks found by Valgrind/Memcheck
    Fix a bunch of de-constifications
    Squelch some Coverity warnings and some compiler warnings
    Update Coverity and Travis-CI setup
    Update Visual Studio files

    Frontend:
    Fix capsicum support to work with zerocopy buffers in bpf
    Try opening interfaces by name first, then by name-as-index
    Work around pcap_create() failures fetching time stamp type lists
    Fix a segmentation fault with 'tcpdump -J'
    Improve addrtostr6() bounds checking
    Add exit_tcpdump() function
    Don't drop CAP_SYS_CHROOT before chrooting
    Fixes issue where statistics not reported when -G and -W options used

    New printers supporting:
    Generic Protocol Extension for VXLAN (VXLAN-GPE)
    Home Networking Control Protocol (HNCP), RFCs 7787 and 7788
    Locator/Identifier Separation Protocol (LISP), type 3 and type 4 packets
    Marvell Extended Distributed Switch Architecture header (MEDSA)
    Network Service Header (NSH)
    REdis Serialization Protocol (RESP)

    Updated printers:
    802.11: Beginnings of 11ac radiotap support
    802.11: Check the Protected bit for management frames
    802.11: Do bounds checking on last_presentp before dereferencing it (Fix a heap overflow)
    802.11: Fix the radiotap printer to handle the special bits correctly
    802.11: If we have the MCS field, it's 11n
    802.11: Only print unknown frame type or subtype messages once
    802.11: Radiotap dBm values get printed as dB; Update a test output accordingly
    802.11: Source and destination addresses were backwards
    AH: Add a bounds check
    AH: Report to our caller that dissection failed if a bounds check fails
    AP1394: Print src > dst, not dst > src
    ARP: Don't assume the target hardware address is <= 6 octets long (Fix a heap overflow)
    ATALK: Add bounds and length checks (Fix heap overflows)
    ATM: Add some bounds checks (Fix a heap overflow)
    ATM: Fix an incorrect bounds check
    BFD: Update specification from draft to RFC 5880
    BFD: Update to print optional authentication field
    BGP: Add decoding of ADD-PATH capability
    BGP: Add support for the AIGP attribute (RFC7311)
    BGP: Print LARGE_COMMUNITY Path Attribute
    BGP: Update BGP numbers from IANA; Print minor values for FSM notification
    BOOTP: Add a bounds check
    Babel: Add decoder for source-specific extension
    CDP: Filter out non-printable characters
    CFM: Fixes to match the IEEE standard, additional bounds and length checks
    CSLIP: Add more bounds checks (Fix a heap overflow)
    ClassicalIPoATM: Add a bounds check on LLC+SNAP header (Fix a heap overflow)
    DHCP: Fix MUDURL and TZ options
    DHCPv6: Process MUDURL and TZ options
    DHCPv6: Update Status Codes with RFCs/IANA names
    DNS: Represent the "DNSSEC OK" bit as "DO" instead of "OK". Add a test case
    DTP: Improve packet integrity checks
    EGP: Fix bounds checks
    ESP: Don't use OpenSSL_add_all_algorithms() in OpenSSL 1.1.0 or later
    ESP: Handle OpenSSL 1.1.x
    Ethernet: Add some bounds checking before calling isoclns_print (Fix a heap overflow)
    Ethernet: Print the Length/Type field as length when needed
    FDDI: Fix -e output for FDDI
    FR: Add some packet-length checks and improve Q.933 printing (Fix heap overflows)
    GRE: Add some bounds checks (Fix heap overflows)
    Geneve: Fix error message with invalid option length; Update list option classes
    HNCP: Fix incorrect time interval format. Fix handling of IPv4 prefixes
    ICMP6: Fetch a 32-bit big-endian quantity with EXTRACT_32BITS()
    ICMP6: dagid is always an IPv6 address, not an opaque 128-bit string
    IGMP: Add a length check
    IP: Add a bounds check (Fix a heap overflow)
    IP: Check before fetching the protocol version (Fix a heap overflow)
    IP: Don't try to dissect if IP version != 4 (Fix a heap overflow)
    IP: Stop processing IPPROTO_ values once we hit IPPROTO_IPCOMP
    IPComp: Check whether we have the CPI before we fetch it (Fix a heap overflow)
    IPoFC: Fix -e output (IP-over-Fibre Channel)
    IPv6: Don't overwrite the destination IPv6 address for routing headers
    IPv6: Fix header printing
    IPv6: Stop processing IPPROTO_ values once we hit IPPROTO_IPCOMP
    ISAKMP: Clean up parsing of IKEv2 Security Associations
    ISOCLNS/IS-IS: Add support for Purge Originator Identifier (RFC6232) and test cases
    ISOCLNS/IS-IS: Don't overwrite packet data when checking the signature
    ISOCLNS/IS-IS: Filter out non-printable characters
    ISOCLNS/IS-IS: Fix segmentation faults
    ISOCLNS/IS-IS: Have signature_verify() do the copying and clearing
    ISOCLNS: Add some bounds checks
    Juniper: Make sure a Juniper header TLV isn't bigger than what's left in the packet (Fix a heap overflow)
    LLC/SNAP: With -e, print the LLC header before the SNAP header; without it, cut the SNAP header
    LLC: Add a bounds check (Fix a heap overflow)
    LLC: Clean up printing of LLC packets
    LLC: Fix the printing of RFC 948-style IP packets
    LLC: Skip the LLC and SNAP headers with -x for 802.11 and some other protocols
    LLDP: Implement IANA OUI and LLDP MUD option
    MPLS LSP ping: Update printing for RFC 4379, bug fixes, more bounds checks
    MPLS: "length" is now the *remaining* packet length
    MPLS: Add bounds and length checks (Fix a heap overflow)
    NFS: Add a test that makes unaligned accesses
    NFS: Don't assume the ONC RPC header is nicely aligned
    NFS: Don't overflow the Opaque_Handle buffer (Fix a segmentation fault)
    NFS: Don't run past the end of an NFSv3 file handle
    OLSR: Add a test to cover a HNA sgw case
    OLSR: Fix 'Advertised networks' count
    OLSR: Fix printing of smart-gateway HNAs in IPv4
    OSPF: Add a bounds check for the Hello packet options
    OSPF: Do more bounds checking
    OSPF: Fix a segmentation fault
    OSPF: Fix printing 'ospf_topology_values' default
    OTV: Add missing bounds checks
    PGM: Print the formatted IP address, not the raw binary address, as a string
    PIM: Add some bounds checking (Fix a heap overflow)
    PIMv2: Fix checksumming of Register messages
    PPI: Pass an adjusted struct pcap_pkthdr to the sub-printer
    PPP: Add some bounds checks (Fix a heap overflow)
    PPP: Report invalid PAP AACK/ANAK packets
    Q.933: Add a missing bounds check
    RADIUS: Add Value 13 "VLAN" to Tunnel-Type attribute
    RADIUS: Filter out non-printable characters
    RADIUS: Translate UDP/1700 as RADIUS
    RESP: Do better checking of RESP packets
    RPKI-RTR: Add a return value check for "fn_printn" call
    RPKI-RTR: Remove printing when truncated condition already detected
    RPL: Fix 'Consistency Check' control code
    RPL: Fix suboption print
    RSVP: An INTEGRITY object in a submessage covers only the submessage
    RSVP: Fix an infinite loop; Add bounds and length checks
    RSVP: Fix some if statements missing brackets
    RSVP: Have signature_verify() do the copying and clearing
    RTCP: Add some bounds checks
    RTP: Add some bounds checks, fix two segmentation faults
    SCTP: Do more bounds checking
    SFLOW: Fix bounds checking
    SLOW: Fix bugs, add checks
    SMB: Before fetching the flags2 field, make sure we have it
    SMB: Do bounds checks on NBNS resource types and resource data lengths
    SNMP: Clean up the "have libsmi but no modules loaded" case
    SNMP: Clean up the object abbreviation list and fix the code to match them
    SNMP: Do bounds checks when printing character and octet strings
    SNMP: Improve ASN.1 bounds checks
    SNMP: More bounds and length checks
    STP: Add a bunch of bounds checks, and fix some printing (Fix heap overflows)
    STP: Filter out non-printable characters
    TCP: Add bounds and length checks for packets with TCP option 20
    TCP: Correct TCP option Kind value for TCP Auth and add SCPS-TP
    TCP: Fix two bounds checks (Fix heap overflows)
    TCP: Make sure we have the data offset field before fetching it (Fix a heap overflow)
    TCP: Put TCP-AO option decoding right
    TFTP: Don't use strchr() to scan packet data (Fix a heap overflow)
    Telnet: Add some bounds checks
    TokenRing: Fix -e output
    UDLD: Fix an infinite loop
    UDP: Add a bounds check (Fix a heap overflow)
    UDP: Check against the packet length first
    UDP: Don't do the DDP-over-UDP heuristic check up front
    VAT: Add some bounds checks
    VTP: Add a test on Mgmt Domain Name length
    VTP: Add bounds checks and filter out non-printable characters
    VXLAN: Add a bound check and a test case
    ZeroMQ: Fix an infinite loop

  Tuesday April 14, 2015 guy@alum.mit.edu
  Summary for 4.8.0 tcpdump release
        Fix "-x" for Apple PKTAP and PPI packets

Bug: N/A
Test: "adb shell tcpdump"
Change-Id: I81df72cf1ebdbe61c5b6069d8532ae817570f23f
diff --git a/print-snmp.c b/print-snmp.c
index f550158..1b096dc 100644
--- a/print-snmp.c
+++ b/print-snmp.c
@@ -56,12 +56,13 @@
  #	@(#)snmp.awk.x	1.1 (LANL) 1/15/90
  */
 
-#define NETDISSECT_REWORKED
+/* \summary: Simple Network Management Protocol (SNMP) printer */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include <tcpdump-stdinc.h>
+#include <netdissect-stdinc.h>
 
 #include <stdio.h>
 #include <string.h>
@@ -70,7 +71,7 @@
 #include <smi.h>
 #endif
 
-#include "interface.h"
+#include "netdissect.h"
 
 #undef OPAQUE  /* defined in <wingdi.h> */
 
@@ -253,7 +254,7 @@
  * A structure for the OID tree for the compiled-in MIB.
  * This is stored as a general-order tree.
  */
-struct obj {
+static struct obj {
 	const char	*desc;		/* name of object */
 	u_char	oid;			/* sub-id following parent */
 	u_char	type;			/* object type (unused) */
@@ -275,28 +276,46 @@
  * Currently, this includes the prefixes for the Internet MIB, the
  * private enterprises tree, and the experimental tree.
  */
+#define OID_FIRST_OCTET(x, y)	(((x)*40) + (y))	/* X.690 8.19.4 */
+
+#ifndef NO_ABREV_MIB
+static const uint8_t mib_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 2, 1 };
+#endif
+#ifndef NO_ABREV_ENTER
+static const uint8_t enterprises_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 4, 1 };
+#endif
+#ifndef NO_ABREV_EXPERI
+static const uint8_t experimental_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 3 };
+#endif
+#ifndef NO_ABBREV_SNMPMODS
+static const uint8_t snmpModules_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 6, 3 };
+#endif
+
+#define OBJ_ABBREV_ENTRY(prefix, obj) \
+	{ prefix, &_ ## obj ## _obj, obj ## _oid, sizeof (obj ## _oid) }
 static const struct obj_abrev {
 	const char *prefix;		/* prefix for this abrev */
 	struct obj *node;		/* pointer into object table */
-	const char *oid;		/* ASN.1 encoded OID */
+	const uint8_t *oid;		/* ASN.1 encoded OID */
+	size_t oid_len;			/* length of OID */
 } obj_abrev_list[] = {
 #ifndef NO_ABREV_MIB
 	/* .iso.org.dod.internet.mgmt.mib */
-	{ "",	&_mib_obj,		"\53\6\1\2\1" },
+	OBJ_ABBREV_ENTRY("",	mib),
 #endif
 #ifndef NO_ABREV_ENTER
 	/* .iso.org.dod.internet.private.enterprises */
-	{ "E:",	&_enterprises_obj,	"\53\6\1\4\1" },
+	OBJ_ABBREV_ENTRY("E:",	enterprises),
 #endif
 #ifndef NO_ABREV_EXPERI
 	/* .iso.org.dod.internet.experimental */
-	{ "X:",	&_experimental_obj,	"\53\6\1\3" },
+	OBJ_ABBREV_ENTRY("X:",	experimental),
 #endif
 #ifndef NO_ABBREV_SNMPMODS
 	/* .iso.org.dod.internet.snmpV2.snmpModules */
-        { "S:", &_snmpModules_obj,      "\53\6\1\6\3" },
+	OBJ_ABBREV_ENTRY("S:",	snmpModules),
 #endif
-	{ 0,0,0 }
+	{ 0,0,0,0 }
 };
 
 /*
@@ -325,14 +344,11 @@
 struct be {
 	uint32_t asnlen;
 	union {
-		caddr_t raw;
+		const uint8_t *raw;
 		int32_t integer;
 		uint32_t uns;
 		const u_char *str;
-	        struct {
-		        uint32_t high;
-		        uint32_t low;
-		} uns64;
+		uint64_t uns64;
 	} data;
 	u_short id;
 	u_char form, class;		/* tag info */
@@ -446,13 +462,18 @@
 		 * bit set.  XXX - this doesn't handle a value
 		 * that won't fit in 32 bits.
 		 */
-		for (id = 0; *p & ASN_BIT8; len--, hdr++, p++) {
+		id = 0;
+		ND_TCHECK(*p);
+		while (*p & ASN_BIT8) {
 			if (len < 1) {
 				ND_PRINT((ndo, "[Xtagfield?]"));
 				return -1;
 			}
-			ND_TCHECK(*p);
 			id = (id << 7) | (*p & ~ASN_BIT8);
+			len--;
+			hdr++;
+			p++;
+			ND_TCHECK(*p);
 		}
 		if (len < 1) {
 			ND_PRINT((ndo, "[Xtagfield?]"));
@@ -498,6 +519,7 @@
 		ND_PRINT((ndo, "[id?%c/%s/%d]", *Form[form], Class[class].name, id));
 		return -1;
 	}
+	ND_TCHECK2(*p, elem->asnlen);
 
 	switch (form) {
 	case PRIMITIVE:
@@ -514,7 +536,10 @@
 				elem->type = BE_INT;
 				data = 0;
 
-				ND_TCHECK2(*p, elem->asnlen);
+				if (elem->asnlen == 0) {
+					ND_PRINT((ndo, "[asnlen=0]"));
+					return -1;
+				}
 				if (*p & ASN_BIT8)	/* negative */
 					data = -1;
 				for (i = elem->asnlen; i-- > 0; p++)
@@ -525,7 +550,7 @@
 
 			case OBJECTID:
 				elem->type = BE_OID;
-				elem->data.raw = (caddr_t)p;
+				elem->data.raw = (const uint8_t *)p;
 				break;
 
 			case ASN_NULL:
@@ -535,7 +560,7 @@
 
 			default:
 				elem->type = BE_OCTET;
-				elem->data.raw = (caddr_t)p;
+				elem->data.raw = (const uint8_t *)p;
 				ND_PRINT((ndo, "[P/U/%s]", Class[class].Id[id]));
 				break;
 			}
@@ -545,14 +570,13 @@
 			switch (id) {
 			case IPADDR:
 				elem->type = BE_INETADDR;
-				elem->data.raw = (caddr_t)p;
+				elem->data.raw = (const uint8_t *)p;
 				break;
 
 			case COUNTER:
 			case GAUGE:
 			case TIMETICKS: {
 				register uint32_t data;
-				ND_TCHECK2(*p, elem->asnlen);
 				elem->type = BE_UNS;
 				data = 0;
 				for (i = elem->asnlen; i-- > 0; p++)
@@ -562,23 +586,18 @@
 			}
 
 			case COUNTER64: {
-				register uint32_t high, low;
-				ND_TCHECK2(*p, elem->asnlen);
+				register uint64_t data64;
 			        elem->type = BE_UNS64;
-				high = 0, low = 0;
-				for (i = elem->asnlen; i-- > 0; p++) {
-				        high = (high << 8) |
-					    ((low & 0xFF000000) >> 24);
-					low = (low << 8) | *p;
-				}
-				elem->data.uns64.high = high;
-				elem->data.uns64.low = low;
+				data64 = 0;
+				for (i = elem->asnlen; i-- > 0; p++)
+					data64 = (data64 << 8) + *p;
+				elem->data.uns64 = data64;
 				break;
 			}
 
 			default:
 				elem->type = BE_OCTET;
-				elem->data.raw = (caddr_t)p;
+				elem->data.raw = (const uint8_t *)p;
 				ND_PRINT((ndo, "[P/A/%s]",
 					Class[class].Id[id]));
 				break;
@@ -606,9 +625,8 @@
 
 		default:
 			ND_PRINT((ndo, "[P/%s/%s]", Class[class].name, Class[class].Id[id]));
-			ND_TCHECK2(*p, elem->asnlen);
 			elem->type = BE_OCTET;
-			elem->data.raw = (caddr_t)p;
+			elem->data.raw = (const uint8_t *)p;
 			break;
 		}
 		break;
@@ -619,12 +637,12 @@
 			switch (id) {
 			case SEQUENCE:
 				elem->type = BE_SEQ;
-				elem->data.raw = (caddr_t)p;
+				elem->data.raw = (const uint8_t *)p;
 				break;
 
 			default:
 				elem->type = BE_OCTET;
-				elem->data.raw = (caddr_t)p;
+				elem->data.raw = (const uint8_t *)p;
 				ND_PRINT((ndo, "C/U/%s", Class[class].Id[id]));
 				break;
 			}
@@ -632,12 +650,12 @@
 
 		case CONTEXT:
 			elem->type = BE_PDU;
-			elem->data.raw = (caddr_t)p;
+			elem->data.raw = (const uint8_t *)p;
 			break;
 
 		default:
 			elem->type = BE_OCTET;
-			elem->data.raw = (caddr_t)p;
+			elem->data.raw = (const uint8_t *)p;
 			ND_PRINT((ndo, "C/%s/%s", Class[class].name, Class[class].Id[id]));
 			break;
 		}
@@ -652,6 +670,56 @@
 	return -1;
 }
 
+static int
+asn1_print_octets(netdissect_options *ndo, struct be *elem)
+{
+	const u_char *p = (const u_char *)elem->data.raw;
+	uint32_t asnlen = elem->asnlen;
+	uint32_t i;
+
+	ND_TCHECK2(*p, asnlen);
+	for (i = asnlen; i-- > 0; p++)
+		ND_PRINT((ndo, "_%.2x", *p));
+	return 0;
+
+trunc:
+	ND_PRINT((ndo, "%s", tstr));
+	return -1;
+}
+
+static int
+asn1_print_string(netdissect_options *ndo, struct be *elem)
+{
+	register int printable = 1, first = 1;
+	const u_char *p;
+	uint32_t asnlen = elem->asnlen;
+	uint32_t i;
+
+	p = elem->data.str;
+	ND_TCHECK2(*p, asnlen);
+	for (i = asnlen; printable && i-- > 0; p++)
+		printable = ND_ISPRINT(*p);
+	p = elem->data.str;
+	if (printable) {
+		ND_PRINT((ndo, "\""));
+		if (fn_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
+			ND_PRINT((ndo, "\""));
+			goto trunc;
+		}
+		ND_PRINT((ndo, "\""));
+	} else {
+		for (i = asnlen; i-- > 0; p++) {
+			ND_PRINT((ndo, first ? "%.2x" : "_%.2x", *p));
+			first = 0;
+		}
+	}
+	return 0;
+
+trunc:
+	ND_PRINT((ndo, "%s", tstr));
+	return -1;
+}
+
 /*
  * Display the ASN.1 object represented by the BE object.
  * This used to be an integral part of asn1_parse() before the intermediate
@@ -661,33 +729,36 @@
 asn1_print(netdissect_options *ndo,
            struct be *elem)
 {
-	u_char *p = (u_char *)elem->data.raw;
+	const u_char *p;
 	uint32_t asnlen = elem->asnlen;
 	uint32_t i;
 
 	switch (elem->type) {
 
 	case BE_OCTET:
-		ND_TCHECK2(*p, asnlen);
-		for (i = asnlen; i-- > 0; p++)
-			ND_PRINT((ndo, "_%.2x", *p));
+		if (asn1_print_octets(ndo, elem) == -1)
+			return -1;
 		break;
 
 	case BE_NULL:
 		break;
 
 	case BE_OID: {
-		int o = 0, first = -1, i = asnlen;
+		int o = 0, first = -1;
 
-		if (!ndo->ndo_sflag && !ndo->ndo_nflag && asnlen > 2) {
+		p = (const u_char *)elem->data.raw;
+		i = asnlen;
+		if (!ndo->ndo_nflag && asnlen > 2) {
 			const struct obj_abrev *a = &obj_abrev_list[0];
-			size_t a_len = strlen(a->oid);
 			for (; a->node; a++) {
-				ND_TCHECK2(*p, a_len);
-				if (memcmp(a->oid, (char *)p, a_len) == 0) {
+				if (i < a->oid_len)
+					continue;
+				if (!ND_TTEST2(*p, a->oid_len))
+					continue;
+				if (memcmp(a->oid, p, a->oid_len) == 0) {
 					objp = a->node->child;
-					i -= strlen(a->oid);
-					p += strlen(a->oid);
+					i -= a->oid_len;
+					p += a->oid_len;
 					ND_PRINT((ndo, "%s", a->prefix));
 					first = 1;
 					break;
@@ -695,14 +766,15 @@
 			}
 		}
 
-		for (; !ndo->ndo_sflag && i-- > 0; p++) {
+		for (; i-- > 0; p++) {
 			ND_TCHECK(*p);
 			o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
 			if (*p & ASN_LONGLEN)
 			        continue;
 
 			/*
-			 * first subitem encodes two items with 1st*OIDMUX+2nd
+			 * first subitem encodes two items with
+			 * 1st*OIDMUX+2nd
 			 * (see X.690:1997 clause 8.19 for the details)
 			 */
 			if (first < 0) {
@@ -731,69 +803,14 @@
 		ND_PRINT((ndo, "%u", elem->data.uns));
 		break;
 
-	case BE_UNS64: {	/* idea borrowed from by Marshall Rose */
-	        double d;
-		int j, carry;
-		char *cpf, *cpl, last[6], first[30];
-		if (elem->data.uns64.high == 0) {
-			ND_PRINT((ndo, "%u", elem->data.uns64.low));
-			break;
-		}
-		d = elem->data.uns64.high * 4294967296.0;	/* 2^32 */
-		if (elem->data.uns64.high <= 0x1fffff) {
-		        d += elem->data.uns64.low;
-#if 0 /*is looks illegal, but what is the intention?*/
-			ND_PRINT((ndo, "%.f", d));
-#else
-			ND_PRINT((ndo, "%f", d));
-#endif
-			break;
-		}
-		d += (elem->data.uns64.low & 0xfffff000);
-#if 0 /*is looks illegal, but what is the intention?*/
-		snprintf(first, sizeof(first), "%.f", d);
-#else
-		snprintf(first, sizeof(first), "%f", d);
-#endif
-		snprintf(last, sizeof(last), "%5.5d",
-		    elem->data.uns64.low & 0xfff);
-		for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
-		     cpl >= last;
-		     cpf--, cpl--) {
-		        j = carry + (*cpf - '0') + (*cpl - '0');
-			if (j > 9) {
-			        j -= 10;
-				carry = 1;
-			} else {
-			        carry = 0;
-		        }
-			*cpf = j + '0';
-		}
-		ND_PRINT((ndo, "%s", first));
+	case BE_UNS64:
+		ND_PRINT((ndo, "%" PRIu64, elem->data.uns64));
 		break;
-	}
 
-	case BE_STR: {
-		register int printable = 1, first = 1;
-		const u_char *p = elem->data.str;
-		ND_TCHECK2(*p, asnlen);
-		for (i = asnlen; printable && i-- > 0; p++)
-			printable = ND_ISPRINT(*p);
-		p = elem->data.str;
-		if (printable) {
-			ND_PRINT((ndo, "\""));
-			if (fn_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
-				ND_PRINT((ndo, "\""));
-				goto trunc;
-			}
-			ND_PRINT((ndo, "\""));
-		} else
-			for (i = asnlen; i-- > 0; p++) {
-				ND_PRINT((ndo, first ? "%.2x" : "_%.2x", *p));
-				first = 0;
-			}
+	case BE_STR:
+		if (asn1_print_string(ndo, elem) == -1)
+			return -1;
 		break;
-	}
 
 	case BE_SEQ:
 		ND_PRINT((ndo, "Seq(%u)", elem->asnlen));
@@ -802,6 +819,7 @@
 	case BE_INETADDR:
 		if (asnlen != ASNLEN_INETADDR)
 			ND_PRINT((ndo, "[inetaddr len!=%d]", ASNLEN_INETADDR));
+		p = (const u_char *)elem->data.raw;
 		ND_TCHECK2(*p, asnlen);
 		for (i = asnlen; i-- != 0; p++) {
 			ND_PRINT((ndo, (i == asnlen-1) ? "%u" : ".%u", *p));
@@ -895,12 +913,12 @@
                struct be *elem, unsigned int *oid,
                unsigned int oidsize, unsigned int *oidlen)
 {
-	u_char *p = (u_char *)elem->data.raw;
+	const u_char *p = (const u_char *)elem->data.raw;
 	uint32_t asnlen = elem->asnlen;
 	int o = 0, first = -1, i = asnlen;
 	unsigned int firstval;
 
-	for (*oidlen = 0; ndo->ndo_sflag && i-- > 0; p++) {
+	for (*oidlen = 0; i-- > 0; p++) {
 		ND_TCHECK(*p);
 	        o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
 		if (*p & ASN_LONGLEN)
@@ -911,7 +929,7 @@
 		 * (see X.690:1997 clause 8.19 for the details)
 		 */
 		if (first < 0) {
-		        first = 0;
+	        	first = 0;
 			firstval = o / OIDMUX;
 			if (firstval > 2) firstval = 2;
 			o -= firstval * OIDMUX;
@@ -1029,6 +1047,10 @@
 	SmiNode *smiNode = NULL;
 	unsigned int i;
 
+	if (!nd_smi_module_loaded) {
+		*status = asn1_print(ndo, elem);
+		return NULL;
+	}
 	*status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
 	    &oidlen);
 	if (*status < 0)
@@ -1053,7 +1075,7 @@
 
 static int
 smi_print_value(netdissect_options *ndo,
-                SmiNode *smiNode, u_char pduid, struct be *elem)
+                SmiNode *smiNode, u_short pduid, struct be *elem)
 {
 	unsigned int i, oid[128], oidlen;
 	SmiType *smiType;
@@ -1114,22 +1136,24 @@
 	        if (smiType->basetype == SMI_BASETYPE_BITS) {
 		        /* print bit labels */
 		} else {
-		        smi_decode_oid(ndo, elem, oid,
-				       sizeof(oid)/sizeof(unsigned int),
-				       &oidlen);
-			smiNode = smiGetNodeByOID(oidlen, oid);
-			if (smiNode) {
-			        if (ndo->ndo_vflag) {
-					ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
-				}
-				ND_PRINT((ndo, "%s", smiNode->name));
-				if (smiNode->oidlen < oidlen) {
-				        for (i = smiNode->oidlen;
-					     i < oidlen; i++) {
-					        ND_PRINT((ndo, ".%u", oid[i]));
+			if (nd_smi_module_loaded &&
+			    smi_decode_oid(ndo, elem, oid,
+					   sizeof(oid)/sizeof(unsigned int),
+					   &oidlen) == 0) {
+				smiNode = smiGetNodeByOID(oidlen, oid);
+				if (smiNode) {
+				        if (ndo->ndo_vflag) {
+						ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
 					}
+					ND_PRINT((ndo, "%s", smiNode->name));
+					if (smiNode->oidlen < oidlen) {
+					        for (i = smiNode->oidlen;
+						     i < oidlen; i++) {
+						        ND_PRINT((ndo, ".%u", oid[i]));
+						}
+					}
+					done++;
 				}
-				done++;
 			}
 		}
 		break;
@@ -1196,7 +1220,7 @@
  */
 static void
 varbind_print(netdissect_options *ndo,
-              u_char pduid, const u_char *np, u_int length)
+              u_short pduid, const u_char *np, u_int length)
 {
 	struct be elem;
 	int count = 0, ind;
@@ -1217,7 +1241,7 @@
 		ND_PRINT((ndo, "[%d extra after SEQ of varbind]", length - count));
 	/* descend */
 	length = elem.asnlen;
-	np = (u_char *)elem.data.raw;
+	np = (const u_char *)elem.data.raw;
 
 	for (ind = 1; length > 0; ind++) {
 		const u_char *vbend;
@@ -1237,7 +1261,7 @@
 		vblength = length - count;
 		/* descend */
 		length = elem.asnlen;
-		np = (u_char *)elem.data.raw;
+		np = (const u_char *)elem.data.raw;
 
 		/* objName (OID) */
 		if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
@@ -1296,7 +1320,7 @@
               u_short pduid, const u_char *np, u_int length)
 {
 	struct be elem;
-	int count = 0, error;
+	int count = 0, error_status;
 
 	/* reqId (Integer) */
 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
@@ -1319,7 +1343,7 @@
 		asn1_print(ndo, &elem);
 		return;
 	}
-	error = 0;
+	error_status = 0;
 	if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
 	    || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
 	    && elem.data.integer != 0) {
@@ -1331,7 +1355,7 @@
 	} else if (elem.data.integer != 0) {
 		char errbuf[20];
 		ND_PRINT((ndo, " %s", DECODE_ErrorStatus(elem.data.integer)));
-		error = elem.data.integer;
+		error_status = elem.data.integer;
 	}
 	length -= count;
 	np += count;
@@ -1351,15 +1375,12 @@
 	else if (pduid == GETBULKREQ)
 		ND_PRINT((ndo, " M=%d", elem.data.integer));
 	else if (elem.data.integer != 0) {
-		if (!error)
+		if (!error_status)
 			ND_PRINT((ndo, "[errorIndex(%d) w/o errorStatus]", elem.data.integer));
-		else {
+		else
 			ND_PRINT((ndo, "@%d", elem.data.integer));
-			error = elem.data.integer;
-		}
-	} else if (error) {
+	} else if (error_status) {
 		ND_PRINT((ndo, "[errorIndex==0]"));
-		error = 0;
 	}
 	length -= count;
 	np += count;
@@ -1486,7 +1507,7 @@
 	ND_PRINT((ndo, " "));
 	/* descend into PDU */
 	length = pdu.asnlen;
-	np = (u_char *)pdu.data.raw;
+	np = (const u_char *)pdu.data.raw;
 
 	if (version == SNMP_VERSION_1 &&
 	    (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
@@ -1529,7 +1550,7 @@
                 const u_char *np, u_int length, int version)
 {
 	struct be elem;
-	int i, count = 0;
+	int count = 0;
 
 	/* Sequence */
 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
@@ -1540,7 +1561,7 @@
 		return;
 	}
 	length = elem.asnlen;
-	np = (u_char *)elem.data.raw;
+	np = (const u_char *)elem.data.raw;
 
 	/* contextEngineID (OCTET STRING) */
 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
@@ -1553,10 +1574,9 @@
 	length -= count;
 	np += count;
 
-	ND_PRINT((ndo, "E= "));
-	for (i = 0; i < (int)elem.asnlen; i++) {
-		ND_PRINT((ndo, "0x%02X", elem.data.str[i]));
-	}
+	ND_PRINT((ndo, "E="));
+	if (asn1_print_octets(ndo, &elem) == -1)
+		return;
 	ND_PRINT((ndo, " "));
 
 	/* contextName (OCTET STRING) */
@@ -1570,7 +1590,10 @@
 	length -= count;
 	np += count;
 
-	ND_PRINT((ndo, "C=%.*s ", (int)elem.asnlen, elem.data.str));
+	ND_PRINT((ndo, "C="));
+	if (asn1_print_string(ndo, &elem) == -1)
+		return;
+	ND_PRINT((ndo, " "));
 
 	pdu_print(ndo, np, length, version);
 }
@@ -1595,10 +1618,14 @@
 	}
 	/* default community */
 	if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
-	    strncmp((char *)elem.data.str, DEF_COMMUNITY,
-	            sizeof(DEF_COMMUNITY) - 1) == 0))
+	    strncmp((const char *)elem.data.str, DEF_COMMUNITY,
+	            sizeof(DEF_COMMUNITY) - 1) == 0)) {
 		/* ! "public" */
-		ND_PRINT((ndo, "C=%.*s ", (int)elem.asnlen, elem.data.str));
+		ND_PRINT((ndo, "C="));
+		if (asn1_print_string(ndo, &elem) == -1)
+			return;
+		ND_PRINT((ndo, " "));
+	}
 	length -= count;
 	np += count;
 
@@ -1624,7 +1651,7 @@
 		return;
 	}
 	length = elem.asnlen;
-	np = (u_char *)elem.data.raw;
+	np = (const u_char *)elem.data.raw;
 
 	/* msgAuthoritativeEngineID (OCTET STRING) */
 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
@@ -1674,7 +1701,10 @@
 	length -= count;
         np += count;
 
-	ND_PRINT((ndo, "U=%.*s ", (int)elem.asnlen, elem.data.str));
+	ND_PRINT((ndo, "U="));
+	if (asn1_print_string(ndo, &elem) == -1)
+		return;
+	ND_PRINT((ndo, " "));
 
 	/* msgAuthenticationParameters (OCTET STRING) */
 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
@@ -1725,7 +1755,7 @@
 		return;
 	}
 	length = elem.asnlen;
-	np = (u_char *)elem.data.raw;
+	np = (const u_char *)elem.data.raw;
 
 	if (ndo->ndo_vflag) {
 		ND_PRINT((ndo, "{ "));
@@ -1864,7 +1894,7 @@
 		ND_PRINT((ndo, "[%d extra after iSEQ]", length - count));
 	/* descend */
 	length = elem.asnlen;
-	np = (u_char *)elem.data.raw;
+	np = (const u_char *)elem.data.raw;
 
 	/* Version (INTEGER) */
 	if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
@@ -1883,7 +1913,7 @@
 			ND_PRINT((ndo, "{ %s ", SnmpVersion[elem.data.integer]));
 		break;
 	default:
-	        ND_PRINT((ndo, "[version = %d]", elem.data.integer));
+	        ND_PRINT((ndo, "SNMP [version = %d]", elem.data.integer));
 		return;
 	}
 	version = elem.data.integer;