Ethereal-dev: Re: [ethereal-dev] packet-snmp.c and libsmi

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Sun, 25 Jun 2000 13:56:24 -0700
On Sat, Jun 24, 2000 at 01:14:06PM -0700, Guy Harris wrote:
> On Fri, Jun 23, 2000 at 11:38:12PM -0700, Guy Harris wrote:
> > This is a patch to the current "packet-snmp.c" in the CVS tree.
> 
> ...and this is a slightly better one (again, a patch to the code in the
> CVS tree), that doesn't reintroduce the no-longer-necessary
> commented-out examples of "hf_register_info" entries (no longer
> necessary because there are *real* entries now for some of the SNMP V3
> stuff).

...and this one is even better (again, a patch to the stuff in the CVS
tree; update your CVS tree first), as it gets rid of a string-size
#define that is no longer used.
Index: packet-snmp.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-snmp.c,v
retrieving revision 1.38
diff -c -r1.38 packet-snmp.c
*** packet-snmp.c	2000/06/25 20:55:09	1.38
--- packet-snmp.c	2000/06/25 20:57:37
***************
*** 45,193 ****
  # include <netinet/in.h>
  #endif
  
! #define MAX_STRING_LEN 2048	/* TBC */
  
! #ifdef linux
! #include <dlfcn.h>
  #endif
  
- #include <glib.h>
- 
  #include "packet.h"
  #include "etypes.h"
  #include "packet-ipx.h"
- 
- #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
-  /*
-   * UCD or CMU SNMP?
-   */
- # if defined(HAVE_UCD_SNMP_SNMP_H)
-    /*
-     * UCD SNMP.
-     */
- #  include <ucd-snmp/asn1.h>
- #  include <ucd-snmp/snmp_api.h>
- #  include <ucd-snmp/snmp_impl.h>
- #  include <ucd-snmp/mib.h>
- 
-    /*
-     * Sigh.  UCD SNMP 4.1.1 makes "snmp_set_suffix_only()" a macro
-     * that calls "ds_set_int()" with the first two arguments
-     * being DS_LIBRARY_ID and DS_LIB_PRINT_SUFFIX_ONLY; this means that,
-     * when building with 4.1.1, we need to arrange that
-     * <ucd-snmp/default_store.h> is included, to define those two values
-     * and to declare "ds_int()".
-     *
-     * However:
-     *
-     *	1) we can't include it on earlier versions (at least not 3.6.2),
-     *	   as it doesn't exist in those versions;
-     *
-     *	2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
-     *	   as that includes <ucd-snmp/snmp.h>, and that defines a whole
-     *	   bunch of values that we also define ourselves.
-     *
-     * So we only include it if "snmp_set_full_objid" is defined as
-     * a macro.
-     */
- #  ifdef snmp_set_suffix_only
- #   include <ucd-snmp/default_store.h>
- #  endif
- 
-    /*
-     * XXX - for now, we assume all versions of UCD SNMP have it.
-     */
- #  define HAVE_SPRINT_VALUE
- 
-    /*
-     * Define values "sprint_value()" expects.
-     */
- #  define VALTYPE_INTEGER	ASN_INTEGER
- #  define VALTYPE_COUNTER	ASN_COUNTER
- #  define VALTYPE_GAUGE		ASN_GAUGE
- #  define VALTYPE_TIMETICKS	ASN_TIMETICKS
- #  define VALTYPE_STRING	ASN_OCTET_STR
- #  define VALTYPE_IPADDR	ASN_IPADDRESS
- #  define VALTYPE_OPAQUE	ASN_OPAQUE
- #  define VALTYPE_NSAP		ASN_NSAP
- #  define VALTYPE_OBJECTID	ASN_OBJECT_ID
- #  define VALTYPE_BITSTR	ASN_BIT_STR
- #  define VALTYPE_COUNTER64	ASN_COUNTER64
- # elif defined(HAVE_SNMP_SNMP_H)
-    /*
-     * CMU SNMP.
-     */
- #  include <snmp/snmp.h>
- 
-    /*
-     * Some older versions of CMU SNMP may lack these values (e.g., the
-     * "libsnmp3.6" package for Debian, which is based on some old
-     * CMU SNMP, perhaps 1.0); for now, we assume they also lack
-     * "sprint_value()".
-     */
- #  ifdef SMI_INTEGER
- #   define HAVE_SPRINT_VALUE
-     /*
-      * Define values "sprint_value()" expects.
-      */
- #   define VALTYPE_INTEGER	SMI_INTEGER
- #   define VALTYPE_COUNTER	SMI_COUNTER32
- #   define VALTYPE_GAUGE	SMI_GAUGE32
- #   define VALTYPE_TIMETICKS	SMI_TIMETICKS
- #   define VALTYPE_STRING	SMI_STRING
- #   define VALTYPE_IPADDR	SMI_IPADDRESS
- #   define VALTYPE_OPAQUE	SMI_OPAQUE
- #   define VALTYPE_NSAP		SMI_STRING
- #   define VALTYPE_OBJECTID	SMI_OBJID
- #   define VALTYPE_BITSTR	ASN_BIT_STR
- #   define VALTYPE_COUNTER64	SMI_COUNTER64
- #  endif
-   /*
-    * Now undo all the definitions they "helpfully" gave us, so we don't get
-    * complaints about redefining them.
-    *
-    * Why, oh why, is there no library that provides code to
-    *
-    *	1) read MIB files;
-    *
-    *	2) translate object IDs into names;
-    *
-    *	3) let you find out, for a given object ID, what the type, enum
-    *	   values, display hint, etc. are;
-    *
-    * in a *simple* fashion, without assuming that your code is part of an
-    * SNMP agent or client that wants a pile of definitions of PDU types,
-    * etc.?  Is it just that 99 44/100% of the code that uses an SNMP library
-    * *is* part of an agent or client, and really *does* need that stuff,
-    * and *doesn't* need the interfaces we want?
-    */
- #  undef SNMP_ERR_NOERROR
- #  undef SNMP_ERR_TOOBIG
- #  undef SNMP_ERR_NOSUCHNAME
- #  undef SNMP_ERR_BADVALUE
- #  undef SNMP_ERR_READONLY
- #  undef SNMP_ERR_NOACCESS
- #  undef SNMP_ERR_WRONGTYPE
- #  undef SNMP_ERR_WRONGLENGTH
- #  undef SNMP_ERR_WRONGENCODING
- #  undef SNMP_ERR_WRONGVALUE
- #  undef SNMP_ERR_NOCREATION
- #  undef SNMP_ERR_INCONSISTENTVALUE
- #  undef SNMP_ERR_RESOURCEUNAVAILABLE
- #  undef SNMP_ERR_COMMITFAILED
- #  undef SNMP_ERR_UNDOFAILED
- #  undef SNMP_ERR_AUTHORIZATIONERROR
- #  undef SNMP_ERR_NOTWRITABLE
- #  undef SNMP_ERR_INCONSISTENTNAME
- #  undef SNMP_TRAP_COLDSTART
- #  undef SNMP_TRAP_WARMSTART
- #  undef SNMP_TRAP_LINKDOWN
- #  undef SNMP_TRAP_LINKUP
- #  undef SNMP_TRAP_EGPNEIGHBORLOSS
- #  undef SNMP_TRAP_ENTERPRISESPECIFIC
- # endif
- #endif
- 
  #include "asn1.h"
  
  #include "packet-snmp.h"
--- 45,61 ----
  # include <netinet/in.h>
  #endif
  
! #include <glib.h>
  
! #ifdef HAVE_SMI_H
! #include <smi.h>
! #else
! typedef void SmiNode;
  #endif
  
  #include "packet.h"
  #include "etypes.h"
  #include "packet-ipx.h"
  #include "asn1.h"
  
  #include "packet-snmp.h"
***************
*** 554,635 ****
  	dissect_data(pd, offset, fd, tree);
  }
  
! static void
! format_oid(gchar *buf, subid_t *oid, guint oid_length)
  {
! 	int i;
! 	int len;
  
  	len = sprintf(buf, "%lu", (unsigned long)oid[0]);
  	buf += len;
  	for (i = 1; i < oid_length;i++) {
  		len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
  		buf += len;
  	}
  }
  
! #ifdef HAVE_SPRINT_VALUE
! static void
! format_value(gchar *buf, struct variable_list *variable, subid_t *variable_oid,
!     guint variable_oid_length, gushort vb_type, guint vb_length)
  {
! 	variable->next_variable = NULL;
! 	variable->name = variable_oid;
! 	variable->name_length = variable_oid_length;
  	switch (vb_type) {
  
  	case SNMP_INTEGER:
! 		variable->type = VALTYPE_INTEGER;
  		break;
  
  	case SNMP_COUNTER:
- 		variable->type = VALTYPE_COUNTER;
- 		break;
- 
  	case SNMP_GAUGE:
- 		variable->type = VALTYPE_GAUGE;
- 		break;
- 
  	case SNMP_TIMETICKS:
! 		variable->type = VALTYPE_TIMETICKS;
  		break;
  
  	case SNMP_OCTETSTR:
- 		variable->type = VALTYPE_STRING;
- 		break;
- 
  	case SNMP_IPADDR:
- 		variable->type = VALTYPE_IPADDR;
- 		break;
- 
  	case SNMP_OPAQUE:
- 		variable->type = VALTYPE_OPAQUE;
- 		break;
- 
  	case SNMP_NSAP:
- 		variable->type = VALTYPE_NSAP;
- 		break;
- 
- 	case SNMP_OBJECTID:
- 		variable->type = VALTYPE_OBJECTID;
- 		break;
- 
  	case SNMP_BITSTR:
! 		variable->type = VALTYPE_BITSTR;
  		break;
  
! 	case SNMP_COUNTER64:
! 		variable->type = VALTYPE_COUNTER64;
  		break;
  	}
! 	variable->val_len = vb_length;
! 	sprint_value(buf, variable_oid, variable_oid_length, variable);
  }
- #endif
  
  static int
  snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
!     guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp)
  {
  	const guchar *start;
  	guint length;
--- 422,967 ----
  	dissect_data(pd, offset, fd, tree);
  }
  
! static gint
! int_div(guchar *buffer, gint radix, gint *len, gint *nul)
  {
!   gint dividend, i, mod;
! 
!   *nul = 1;
!   while (*len && (*buffer == 0))
!     {
!       for (i=1; i<*len; i++)
!         buffer[i-1] = buffer[i];
!       (*len)--;
!     }
!   if (!*len) 
!     return 0;
! 
!   dividend = 0;
!   mod = 0;
!   for (i=0; i<*len; i++)
!     {
!       dividend = mod * 256 + buffer[i];
!       mod = dividend % radix;
!       buffer[i] = dividend / radix;
!     }
!   while (*len && (*buffer == 0))
!     {
!       for (i=1; i<*len; i++)
!         buffer[i-1] = buffer[i];
!       (*len)--;
!     }
!   if (*len) *nul=0;
!   return mod;
! }
! 
! /**
!  * print_radix:
!  * @buffer: integer value
!  * @len: length of integer
!  * @radix: base
!  * @shift: decimal shift
!  *
!  */
! static gchar *
! print_radix(gpointer buffer, gint len, gint radix, gboolean sign, gint shift)
! {
!   guchar *result, *temp;
!   gint size, neg, i, nul;
!   gchar digit[] = "0123456789ABCDEF";
! 
!   if (radix<2) radix=2;
!   if (radix>16) radix=16;
! 
!   size = len*8 + 2; /* worst case + sign + trailing 0 */
!   if (shift) size++; /* decimal point */
!   if (size<shift+4) size=shift+4; /* additional leading 0 */
! 
!   result = g_malloc(size+1);
!   temp = g_malloc(len);
! 
!   neg = 0;
! 
!   g_memmove(temp, buffer, len);
! 
!   if (sign && (temp[0] & 0x80))
!     {
!       neg = 1;
!       for (i=0; i<len; i++)
! 	temp[i] = ~temp[i];
!       i=len-1;
!       while (i>=0)
! 	{
! 	  temp[i]++;
! 	  if (temp[i]) break;
! 	  i--;
! 	}
!     }
!   i=size;
!   result[i--] = '\0';
!   nul=0;
!   while ((!nul || (shift && size-i-3 < shift)) && (i>=0))
!     {
!       if ((shift == size-i-1) && shift)
! 	result[i--] = '.';
!       else
! 	result[i--] = digit[int_div(temp, radix, &len, &nul)];
!     }
!   if (i && neg)
!     result[i--] = '-';
!   g_free(temp);
!   temp = g_strdup(result+i+1);
!   g_free(result);
!   return temp;
! }
! 
! /** 
!  * format_integer:
!  * @buffer: integer value as received from SNMP node
!  * @len: length of integer
!  * @format: Format as taken from DISPLAY HINT parameter of MIB file.
!  *
!  * Formats an INTEGER value according to a provided DISPLAY HINT.
!  *
!  * When the syntax has an underlying primitive type of INTEGER, the hint
!  * consists of an integer-format specification, containing two parts.
!  * The first part is a single character suggesting a display format,
!  * either: `x' for hexadecimal, or `d' for decimal, or `o' for octal, or
!  * `b' for binary.  For all types, when rendering the value, leading
!  * zeros are omitted, and for negative values, a minus sign is rendered
!  * immediately before the digits.  The second part is always omitted for
!  * `x', `o' and `b', and need not be present for `d'.  If present, the
!  * second part starts with a hyphen and is followed by a decimal number,
!  * which defines the implied decimal point when rendering the value.
!  * 
!  * Return value: Formatted string.
!  **/
! static gchar*
! format_integer(gpointer buffer, gint len, gboolean sign, gchar *format)
! {
!   gint shift;
! 
!   shift = 0;
!   switch(format[0])
!     {
!       case 'x':
! 	return print_radix(buffer, len, 16, sign, 0);
! 	break;
!       case 'o':
! 	return print_radix(buffer, len, 8, sign, 0);
! 	break;
!       case 'b':
! 	return print_radix(buffer, len, 2, sign, 0);
! 	break;
!       case 'd':
! 	if (format[1] == '-')
! 	  shift = atoi(&(format[2]));
! 	if (shift < 0)
! 	  shift = 0;
!       default:
! 	return print_radix(buffer, len, 10, sign, shift);
!     }
! }
! 
! /** 
!  * format_string:
!  * @buffer: octet string as received from SNMP node
!  * @len: length of octet string
!  * @format: Format as taken from DISPLAY HINT parameter of MIB file.
!  *
!  * Formats an OCTET STRING value according to a provided DISPLAY HINT.
!  *
!  * When the syntax has an underlying primitive type of OCTET STRING, the
!  * hint consists of one or more octet-format specifications.  Each
!  * specification consists of five parts, with each part using and
!  * removing zero or more of the next octets from the value and producing
!  * the next zero or more characters to be displayed.  The octets within
!  * the value are processed in order of significance, most significant
!  * first.
!  *
!  * The five parts of a octet-format specification are:
!  *
!  * (1)  the (optional) repeat indicator; if present, this part is a `*',
!  *      and indicates that the current octet of the value is to be used as
!  *      the repeat count.  The repeat count is an unsigned integer (which
!  *      may be zero) which specifies how many times the remainder of this
!  *      octet-format specification should be successively applied.  If the
!  *      repeat indicator is not present, the repeat count is one.
!  *
!  * (2)  the octet length: one or more decimal digits specifying the number
!  *      of octets of the value to be used and formatted by this octet-
!  *      specification.  Note that the octet length can be zero.  If less
!  *      than this number of octets remain in the value, then the lesser
!  *      number of octets are used.
!  *
!  * (3)  the display format, either:  `x' for hexadecimal, `d' for decimal,
!  *      `o' for octal, `a' for ascii, or `t' for UTF-8.  If the octet
!  *      length part is greater than one, and the display format part refers
!  *      to a numeric format, then network-byte ordering (big-endian
!  *      encoding) is used interpreting the octets in the value.  The octets
!  *      processed by the `t' display format do not necessarily form an
!  *      integral number of UTF-8 characters.  Trailing octets which do not
!  *      form a valid UTF-8 encoded character are discarded.
!  *
!  * (4)  the (optional) display separator character; if present, this part
!  *      is a single character which is produced for display after each
!  *      application of this octet-specification; however, this character is
!  *      not produced for display if it would be immediately followed by the
!  *      display of the repeat terminator character for this octet-
!  *      specification.  This character can be any character other than a
!  *      decimal digit and a `*'.
!  *
!  * (5)  the (optional) repeat terminator character, which can be present
!  *      only if the display separator character is present and this octet-
!  *      specification begins with a repeat indicator; if present, this part
!  *      is a single character which is produced after all the zero or more
!  *      repeated applications (as given by the repeat count) of this
!  *      octet-specification.  This character can be any character other
!  *      than a decimal digit and a `*'.
!  *
!  * Output of a display separator character or a repeat terminator
!  * character is suppressed if it would occur as the last character of
!  * the display.
!  *
!  * If the octets of the value are exhausted before all the octet-format
!  * specification have been used, then the excess specifications are
!  * ignored.  If additional octets remain in the value after interpreting
!  * all the octet-format specifications, then the last octet-format
!  * specification is re-interpreted to process the additional octets,
!  * until no octets remain in the value.
!  * 
!  * Return value: Formatted string.
!  **/
! static gchar*
! format_string(gpointer buffer, gint len, gchar *format)
! {
!   int repeat, count, size;
!   gchar seperator, terminator, formtype;
!   gchar *ptr;
!   guchar *bufptr;
!   gchar *result;
!   int pos;
!   gchar *numstr;
!   int numstrlen;
! 
!   if (!len)
!     return g_strdup("NULL");
! 
!   ptr = format;
!   bufptr = (guchar *)buffer;
! 
!   size = len * 3 * strlen(format);
!   result = g_malloc(size);
! 
!   pos = 0;
! 
!   while (len)
!     {
!     /* Read format string */
!       if (!*ptr)
!         ptr = format;
!       repeat = 1;
!       count = 0;
!       seperator = '\0';
!       terminator = '\0';
!       formtype = '\0';
!       if (*ptr == '*')
!         {
!           repeat = *bufptr++;
! 	  len--;
! 	  ptr++;
! 	}
!       while (*ptr >= '0' && *ptr <= '9')
!         {
! 	  count = 10 * count + (*ptr++ & 0xf);
! 	}
!       if (count == 0)
!         count = 1;
! 
!       if (*ptr && (*ptr != '*') && ((*ptr < '0') || (*ptr > '9')))
!         formtype = *ptr++;
!       if (*ptr && (*ptr != '*') && ((*ptr < '0') || (*ptr > '9')))
!         seperator = *ptr++;
!       if (*ptr && (*ptr != '*') && ((*ptr < '0') || (*ptr > '9')))
!         terminator = *ptr++;
! 
!       while(repeat && len)
!         {
!           if (count > len) count = len;
!           switch (formtype)
!             {
! 	      case 'x':
! 	        numstr = print_radix(bufptr, count, 16, FALSE, 0);
! 	        numstrlen = strlen(numstr);
! 		g_assert(pos + numstrlen < size);
! 	        strcpy(result + pos, numstr);
! 	        pos += numstrlen;
! 	        g_free(numstr);
! 	        break;
! 	      case 'd':
! 	        numstr = print_radix(bufptr, count, 10, FALSE, 0);
! 	        numstrlen = strlen(numstr);
! 		g_assert(pos + numstrlen < size);
! 	        strcpy(result + pos, numstr);
! 	        pos += numstrlen;
! 	        g_free(numstr);
! 	        break;
! 	      case 'o':
! 	        numstr = print_radix(bufptr, count, 8, FALSE, 0);
! 	        numstrlen = strlen(numstr);
! 		g_assert(pos + numstrlen < size);
! 	        strcpy(result + pos, numstr);
! 	        pos += numstrlen;
! 	        g_free(numstr);
! 	        break;
! 	      case 'a':
! 	        g_assert(pos + count < size);
! 	        g_memmove(result + pos, bufptr, count);
! 	        pos += count;
! 		break;
!             }
! 	   
!           len = len - count;
!           bufptr = bufptr + count;
! 	  repeat--;
! 	  if (!repeat && len)
! 	    {
! 	      if (terminator)
! 	        {
! 		  g_assert(pos + 1 < size);
! 	          result[pos++] = terminator;
! 	        }
! 	      else if (seperator)
! 	        {
! 		  g_assert(pos + 1 < size);
! 	          result[pos++] = seperator;
! 	        }
!             }
! 	  else if (seperator && len)
! 	    {
! 	      g_assert(pos + 1 < size);
! 	      result[pos++] = seperator;
! 	    }
! 	}
!     }
!   result[pos] = 0;
!   ptr = g_strdup(result);
!   g_free(result);
!   return ptr;
! }
  
+ static gchar *
+ format_oid(subid_t *oid, guint oid_length, SmiNode* node)
+ {
+ 	char *result;
+ 	int result_len;
+ 	int len, i;
+ 	char *buf;
+ #ifdef HAVE_SMI_H
+ 	SmiModule *module = NULL;
+ #endif
+ 
+ 	result_len = oid_length * 22;
+ #ifdef HAVE_SMI_H
+ 	if (node) {
+ 		module = smiGetNodeModule(node);
+ 		result_len += 5 + strlen(module->name) + strlen(node->name);
+ 		result_len += (oid_length - node->oidlen)*22;
+ 	}
+ #endif
+ 	result = g_malloc(result_len + 1);
+ 	buf = result;
  	len = sprintf(buf, "%lu", (unsigned long)oid[0]);
  	buf += len;
  	for (i = 1; i < oid_length;i++) {
  		len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
  		buf += len;
  	}
+ 
+ #ifdef HAVE_SMI_H
+ 	if (node) {
+ 		len = sprintf(buf, " (%s::%s", module->name, node->name);
+ 		buf += len;
+ 		for (i = node->oidlen; i < oid_length; i++) {
+ 			len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
+ 			buf += len;
+ 		}
+ 		strcpy(buf, ")");
+ 	}
+ #endif
+ 	return result;
  }
  
! static gchar*
! format_var(gushort vb_type, guint8 *vb_octet_string, guint vb_length,
!     SmiNode *node)
  {
! #ifdef HAVE_SMI_H
! 	SmiType *typ;
! #endif
! 	gchar *string;
! 	char *format;
! 	int i;
! #ifdef HAVE_SMI_H
! 	SmiInteger32 integer32;
! 	SmiUnsigned32 unsigned32;
! 	SmiNamedNumber *named_number;
! 	gchar *enumstring;
! #endif
! 
! #ifdef HAVE_SMI_H
! 	typ = smiGetNodeType(node);
! 	if (typ != NULL)
! 		format = typ->format;
! 	else
! 		format = NULL;
! #else
! 	format = NULL;
! #endif
! 
! 	if (format == NULL) {
! 		switch (vb_type) {
! 
! 		case SNMP_INTEGER:
! 		case SNMP_COUNTER:
! 		case SNMP_GAUGE:
! 		case SNMP_TIMETICKS:
! 		    /* XXX - display as "(X) N days, HH:MM:SS.SS"? */
! 		case SNMP_COUNTER64:
! 			format = "d";
! 			break;
! 
! 		case SNMP_OCTETSTR:
! 		case SNMP_OPAQUE:
! 		case SNMP_NSAP:
! 		case SNMP_BITSTR:
! 			format = "1a";
! 			for (i = 0; i < vb_length; i++) {
! 				if (!(isprint(vb_octet_string[i])
! 				    || isspace(vb_octet_string[i]))) {
! 					/*
! 					 * Oh, dear, it's binary.
! 					 */
! 					format = "1x ";
! 					break;
! 				}
! 			}
! 			break;
! 
! 		case SNMP_IPADDR:
! 			format = "d.";
! 			break;
! 
! 		default:
! 			format = NULL;
! 			break;
! 		}
! 	}
! 
  	switch (vb_type) {
  
  	case SNMP_INTEGER:
! 		string = format_integer(vb_octet_string, vb_length, TRUE,
! 		    format);
! #ifdef HAVE_SMI_H
! 		if (typ != NULL && vb_length <= 4) {
! 			/*
! 			 * OK, we have a module, and the number fits in
! 			 * an "SmiInteger32".  Check if there's an enum
! 			 * for this.
! 			 *
! 			 * XXX - handle "SmiInteger64"?
! 			 */
! 			integer32 = 0;
! 			i = 0;
! 			while (vb_length != 0) {
! 				integer32 =
! 				    (integer32 << 8) | vb_octet_string[i];
! 				i++;
! 				vb_length--;
! 			}
! 			for (named_number = smiGetFirstNamedNumber(typ);
! 			    named_number != NULL;
! 			    named_number = smiGetNextNamedNumber(named_number)) {
! 				if (named_number->value.basetype == SMI_BASETYPE_INTEGER32
! 				    && named_number->value.value.integer32 == integer32)
! 					break;
! 			}
! 			if (named_number != NULL) {
! 				enumstring = g_malloc(
! 				    strlen(named_number->name) + 1 +
! 				    strlen(string) + 1 + 1);
! 				sprintf(enumstring, "%s(%s)",
! 				    named_number->name, string);
! 				g_free(string);
! 				string = enumstring;
! 			}
! 		}
! #endif
  		break;
  
  	case SNMP_COUNTER:
  	case SNMP_GAUGE:
  	case SNMP_TIMETICKS:
! 	case SNMP_COUNTER64:
! 		string = format_integer(vb_octet_string, vb_length, FALSE,
! 		    format);
! #ifdef HAVE_SMI_H
! 		if (typ != NULL && vb_length <= 4) {
! 			/*
! 			 * OK, we have a module, and the number fits in
! 			 * an "SmiUnsigned32".  Check if there's an enum
! 			 * for this.
! 			 *
! 			 * XXX - handle "SmiUnsigned64"?
! 			 */
! 			unsigned32 = 0;
! 			i = 0;
! 			while (vb_length != 0) {
! 				unsigned32 =
! 				    (unsigned32 << 8) | vb_octet_string[i];
! 				i++;
! 				vb_length--;
! 			}
! 			for (named_number = smiGetFirstNamedNumber(typ);
! 			    named_number != NULL;
! 			    named_number = smiGetNextNamedNumber(named_number)) {
! 				if (named_number->value.basetype == SMI_BASETYPE_UNSIGNED32
! 				    && named_number->value.value.unsigned32 == unsigned32)
! 					break;
! 			}
! 			if (named_number != NULL) {
! 				enumstring = g_malloc(
! 				    strlen(named_number->name) + 1 +
! 				    strlen(string) + 1 + 1);
! 				sprintf(enumstring, "%s(%s)",
! 				    named_number->name, string);
! 				g_free(string);
! 				string = enumstring;
! 			}
! 		}
! #endif
  		break;
  
  	case SNMP_OCTETSTR:
  	case SNMP_IPADDR:
  	case SNMP_OPAQUE:
  	case SNMP_NSAP:
  	case SNMP_BITSTR:
! 		string = format_string(vb_octet_string, vb_length, format);
  		break;
  
! 	default:
! 		string = NULL;
  		break;
  	}
! 	return string;
  }
  
  static int
  snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
!     guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp, 
!     SmiNode *node)
  {
  	const guchar *start;
  	guint length;
***************
*** 640,665 ****
  	int ret;
  	guint cls, con, tag;
  
- 	gint32 vb_integer_value;
- 	guint32 vb_uinteger_value;
- 
  	guint8 *vb_octet_string;
  
  	subid_t *vb_oid;
  	guint vb_oid_length;
  
! 	gchar vb_display_string[MAX_STRING_LEN]; /* TBC */
  
! #ifdef HAVE_SPRINT_VALUE
! 	struct variable_list variable;
! #if defined(HAVE_UCD_SNMP_SNMP_H)
! 	long value;
! #endif
! #else	/* HAVE_SPRINT_VALUE */
! 	int i;
! 	gchar *buf;
! 	int len;
! #endif	/* HAVE_SPRINT_VALUE */
  
  	/* parse the type of the object */
  	start = asn1->pointer;
--- 972,986 ----
  	int ret;
  	guint cls, con, tag;
  
  	guint8 *vb_octet_string;
  
  	subid_t *vb_oid;
  	guint vb_oid_length;
  
! 	gchar *vb_display_string;
  
! 	SmiNode *oid_node;
! 	gchar *oid_string;
  
  	/* parse the type of the object */
  	start = asn1->pointer;
***************
*** 684,796 ****
  	switch (vb_type) {
  
  	case SNMP_INTEGER:
- 		ret = asn1_int32_value_decode(asn1, vb_length,
- 		    &vb_integer_value);
- 		if (ret != ASN1_ERR_NOERROR)
- 			return ret;
- 		length = asn1->pointer - start;
- 		if (snmp_tree) {
- #ifdef HAVE_SPRINT_VALUE
- #if defined(HAVE_UCD_SNMP_SNMP_H)
- 			value = vb_integer_value;
- 			variable.val.integer = &value;
- #elif defined(HAVE_SNMP_SNMP_H)
- 			variable.val.integer = &vb_integer_value;
- #endif
- 			format_value(vb_display_string, &variable,
- 			    variable_oid, variable_oid_length, vb_type,
- 			    vb_length);
- 			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
- 			    "Value: %s", vb_display_string);
- #else
- 			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
- 			    "Value: %s: %d (%#x)", vb_type_name,
- 			    vb_integer_value, vb_integer_value);
- #endif
- 		}
- 		break;
- 
  	case SNMP_COUNTER:
  	case SNMP_GAUGE:
  	case SNMP_TIMETICKS:
! 		ret = asn1_uint32_value_decode(asn1, vb_length,
! 		    &vb_uinteger_value);
! 		if (ret != ASN1_ERR_NOERROR)
! 			return ret;
! 		length = asn1->pointer - start;
! 		if (snmp_tree) {
! #ifdef HAVE_SPRINT_VALUE
! #if defined(HAVE_UCD_SNMP_SNMP_H)
! 			value = vb_uinteger_value;
! 			variable.val.integer = &value;
! #elif defined(HAVE_SNMP_SNMP_H)
! 			variable.val.integer = &vb_uinteger_value;
! #endif
! 			format_value(vb_display_string, &variable,
! 			    variable_oid, variable_oid_length, vb_type,
! 			    vb_length);
! 			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
! 			    "Value: %s", vb_display_string);
! #else
! 			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
! 			    "Value: %s: %u (%#x)", vb_type_name,
! 			    vb_uinteger_value, vb_uinteger_value);
! #endif
! 		}
! 		break;
! 
  	case SNMP_OCTETSTR:
  	case SNMP_IPADDR:
  	case SNMP_OPAQUE:
  	case SNMP_NSAP:
  	case SNMP_BITSTR:
- 	case SNMP_COUNTER64:
  		ret = asn1_octet_string_value_decode (asn1, vb_length,
  		    &vb_octet_string);
  		if (ret != ASN1_ERR_NOERROR)
  			return ret;
  		length = asn1->pointer - start;
  		if (snmp_tree) {
! #ifdef HAVE_SPRINT_VALUE
! 			variable.val.string = vb_octet_string;
! 			format_value(vb_display_string, &variable,
! 			    variable_oid, variable_oid_length, vb_type,
! 			    vb_length);
  			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
! 			    "Value: %s", vb_display_string);
! #else
! 			/*
! 			 * If some characters are not printable, display
! 			 * the string as bytes.
! 			 */
! 			for (i = 0; i < vb_length; i++) {
! 				if (!(isprint(vb_octet_string[i])
! 				    || isspace(vb_octet_string[i])))
! 					break;
! 			}
! 			if (i < vb_length) {
! 				/*
! 				 * We stopped, due to a non-printable
! 				 * character, before we got to the end
! 				 * of the string.
! 				 */
! 				buf = &vb_display_string[0];
! 				len = sprintf(buf, "%03u", vb_octet_string[0]);
! 				buf += len;
! 				for (i = 1; i < vb_length; i++) {
! 					len = sprintf(buf, ".%03u",
! 					    vb_octet_string[i]);
! 					buf += len;
! 				}
! 				proto_tree_add_text(snmp_tree, NullTVB, offset, length,
! 				    "Value: %s: %s", vb_type_name,
! 				    vb_display_string);
! 			} else {
! 				proto_tree_add_text(snmp_tree, NullTVB, offset, length,
! 				    "Value: %s: %.*s", vb_type_name,
! 				    (int)vb_length, vb_octet_string);
! 			}
! #endif
  		}
  		g_free(vb_octet_string);
  		break;
--- 1005,1031 ----
  	switch (vb_type) {
  
  	case SNMP_INTEGER:
  	case SNMP_COUNTER:
  	case SNMP_GAUGE:
  	case SNMP_TIMETICKS:
! 	case SNMP_COUNTER64:
  	case SNMP_OCTETSTR:
  	case SNMP_IPADDR:
  	case SNMP_OPAQUE:
  	case SNMP_NSAP:
  	case SNMP_BITSTR:
  		ret = asn1_octet_string_value_decode (asn1, vb_length,
  		    &vb_octet_string);
  		if (ret != ASN1_ERR_NOERROR)
  			return ret;
  		length = asn1->pointer - start;
  		if (snmp_tree) {
! 			vb_display_string = format_var(vb_type, vb_octet_string,
! 			    vb_length, node);
  			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
! 			    "Value: %s: %s", vb_type_name,
! 			    vb_display_string);
! 			g_free(vb_display_string);
  		}
  		g_free(vb_octet_string);
  		break;
***************
*** 813,830 ****
  			return ret;
  		length = asn1->pointer - start;
  		if (snmp_tree) {
! #ifdef HAVE_SPRINT_VALUE
! 			variable.val.objid = vb_oid;
! 			format_value(vb_display_string, &variable,
! 			    variable_oid, variable_oid_length, vb_type,
! 			    vb_length*sizeof (subid_t));
! 			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
! 			    "Value: %s", vb_display_string);
  #else
! 			format_oid(vb_display_string, vb_oid, vb_oid_length);
! 			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
! 			    "Value: %s: %s", vb_type_name, vb_display_string);
  #endif
  		}
  		g_free(vb_oid);
  		break;
--- 1048,1064 ----
  			return ret;
  		length = asn1->pointer - start;
  		if (snmp_tree) {
! #ifdef HAVE_SMI_H
! 			oid_node = smiGetNodeByOID(vb_oid_length,
! 				       (SmiSubid *)vb_oid);
  #else
! 			oid_node = NULL;
  #endif
+ 			oid_string = format_oid(vb_oid, vb_oid_length,
+ 			    oid_node);
+ 			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
+ 			    "Value: %s: %s", vb_type_name, oid_string);
+ 			g_free(oid_string);
  		}
  		g_free(vb_oid);
  		break;
***************
*** 890,896 ****
  	guint timestamp;
  	guint timestamp_length;
  
! 	gchar oid_string[MAX_STRING_LEN]; /* TBC */
  
  	guint variable_bindings_length;
  
--- 1124,1130 ----
  	guint timestamp;
  	guint timestamp_length;
  
! 	gchar *oid_string;
  
  	guint variable_bindings_length;
  
***************
*** 898,910 ****
  	guint variable_length;
  	subid_t *variable_oid;
  	guint variable_oid_length;
- #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
- 	gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
- #endif
  
  	int ret;
  	guint cls, con, tag;
  
  	pdu_type_string = val_to_str(pdu_type, pdu_types,
  	    "Unknown PDU type %#x");
  	if (check_col(fd, COL_INFO))
--- 1132,1143 ----
  	guint variable_length;
  	subid_t *variable_oid;
  	guint variable_oid_length;
  
  	int ret;
  	guint cls, con, tag;
  
+ 	SmiNode *node;
+ 
  	pdu_type_string = val_to_str(pdu_type, pdu_types,
  	    "Unknown PDU type %#x");
  	if (check_col(fd, COL_INFO))
***************
*** 993,1001 ****
  			return;
  		}
  		if (tree) {
! 			format_oid(oid_string, enterprise, enterprise_length);
  			proto_tree_add_text(tree, NullTVB, offset, length,
  			    "Enterprise: %s", oid_string);
  		}
  		g_free(enterprise);
  		offset += length;
--- 1226,1242 ----
  			return;
  		}
  		if (tree) {
! #ifdef HAVE_SMI_H
! 			node = smiGetNodeByOID(enterprise_length, 
! 			    (SmiSubid *)enterprise);
! #else
! 			node = NULL;
! #endif
! 			oid_string = format_oid(enterprise, enterprise_length,
! 			    node);
  			proto_tree_add_text(tree, NullTVB, offset, length,
  			    "Enterprise: %s", oid_string);
+ 			g_free(oid_string);
  		}
  		g_free(enterprise);
  		offset += length;
***************
*** 1132,1160 ****
  		}
  		sequence_length += length;
  
! 		if (tree) {
! 			format_oid(oid_string, variable_oid,
! 			    variable_oid_length);
! 			
! #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
! 			sprint_objid(vb_oid_string, variable_oid,
! 			    variable_oid_length);
! 			proto_tree_add_text(tree, NullTVB, offset, sequence_length,
! 			    "Object identifier %d: %s (%s)", vb_index,
! 			    oid_string, vb_oid_string);
  #else
! 			
! 			proto_tree_add_text(tree, NullTVB, offset, sequence_length,
! 			    "Object identifier %d: %s", vb_index,
! 			    oid_string);
  #endif
  		}
  		offset += sequence_length;
  		variable_bindings_length -= sequence_length;
  				
  		/* Parse the variable's value */
  		ret = snmp_variable_decode(tree, variable_oid,
! 		    variable_oid_length, &asn1, offset, &length);
  		if (ret != ASN1_ERR_NOERROR) {
  			dissect_snmp_parse_error(pd, offset, fd, tree,
  			    "variable", ret);
--- 1373,1398 ----
  		}
  		sequence_length += length;
  
! #ifdef HAVE_SMI_H
! 		node = smiGetNodeByOID(variable_oid_length, 
! 				       (SmiSubid *)variable_oid);
  #else
! 		node = NULL;
  #endif
+ 		if (tree) {
+ 			oid_string = format_oid(variable_oid,
+ 			    variable_oid_length, node);
+ 			proto_tree_add_text(tree, NullTVB, offset,
+ 			    sequence_length,
+ 			    "Object identifier %d: %s", vb_index, oid_string);
+ 			g_free(oid_string);
  		}
  		offset += sequence_length;
  		variable_bindings_length -= sequence_length;
  				
  		/* Parse the variable's value */
  		ret = snmp_variable_decode(tree, variable_oid,
! 		    variable_oid_length, &asn1, offset, &length, node);
  		if (ret != ASN1_ERR_NOERROR) {
  			dissect_snmp_parse_error(pd, offset, fd, tree,
  			    "variable", ret);
***************
*** 1205,1210 ****
--- 1443,1453 ----
  	int authpar_length;
  	int privpar_length;
  
+ 	guchar *cengineid_string;
+ 	guchar *aengineid_string;
+ 	guchar *authpar_string;
+ 	guchar *privpar_string;
+ 
  	guint pdu_type;
  	guint pdu_length;
  
***************
*** 1410,1418 ****
  				return;
  			}
  			if (secur_tree) {
  				proto_tree_add_text(secur_tree, NullTVB, offset,
  				    length, "Authoritative Engine ID: %s",
! 				    bytes_to_str(aengineid, aengineid_length));
  			}
  			g_free(aengineid);
  			offset += length;
--- 1653,1664 ----
  				return;
  			}
  			if (secur_tree) {
+ 				aengineid_string = format_string(aengineid,
+ 				    aengineid_length, "1x ");
  				proto_tree_add_text(secur_tree, NullTVB, offset,
  				    length, "Authoritative Engine ID: %s",
! 				    aengineid_string);
! 				g_free(aengineid_string);
  			}
  			g_free(aengineid);
  			offset += length;
***************
*** 1462,1470 ****
  				return;
  			}
  			if (secur_tree) {
  				proto_tree_add_text(secur_tree, NullTVB, offset,
  				    length, "Authentication Parameter: %s",
! 				    bytes_to_str(authpar, authpar_length));
  			}
  			g_free(authpar);
  			offset += length;
--- 1708,1719 ----
  				return;
  			}
  			if (secur_tree) {
+ 				authpar_string = format_string(authpar,
+ 				    authpar_length, "1x ");
  				proto_tree_add_text(secur_tree, NullTVB, offset,
  				    length, "Authentication Parameter: %s",
! 				    authpar_string);
! 				g_free(authpar_string);
  			}
  			g_free(authpar);
  			offset += length;
***************
*** 1476,1484 ****
  				return;
  			}
  			if (secur_tree) {
  				proto_tree_add_text(secur_tree, NullTVB, offset,
  				    length, "Privacy Parameter: %s",
! 				    bytes_to_str(privpar, privpar_length));
  			}
  			g_free(privpar);
  			offset += length;
--- 1725,1736 ----
  				return;
  			}
  			if (secur_tree) {
+ 				privpar_string = format_string(privpar,
+ 				    privpar_length, "1x ");
  				proto_tree_add_text(secur_tree, NullTVB, offset,
  				    length, "Privacy Parameter: %s",
! 				    privpar_string);
! 				g_free(privpar_string);
  			}
  			g_free(privpar);
  			offset += length;
***************
*** 1532,1540 ****
  			return;
  		}
  		if (snmp_tree) {
  			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
! 			    "Context Engine ID: %s",
! 			    bytes_to_str(cengineid, cengineid_length));
  		}
  		g_free(cengineid);
  		offset += length;
--- 1784,1794 ----
  			return;
  		}
  		if (snmp_tree) {
+ 			cengineid_string = format_string(cengineid,
+ 			    cengineid_length, "1x ");
  			proto_tree_add_text(snmp_tree, NullTVB, offset, length,
! 			    "Context Engine ID: %s", cengineid_string);
! 			g_free(cengineid_string);
  		}
  		g_free(cengineid);
  		offset += length;
***************
*** 1602,1614 ****
  	subid_t *regid;
  	guint regid_length;
  
! 	gchar oid_string[MAX_STRING_LEN]; /* TBC */
  
  	proto_tree *smux_tree = NULL;
  	proto_item *item = NULL;
  	int ret;
  	guint cls, con;
  
  	if (check_col(fd, COL_PROTOCOL))
  		col_add_str(fd, COL_PROTOCOL, "SMUX");
  
--- 1856,1870 ----
  	subid_t *regid;
  	guint regid_length;
  
! 	gchar *oid_string;
  
  	proto_tree *smux_tree = NULL;
  	proto_item *item = NULL;
  	int ret;
  	guint cls, con;
  
+ 	SmiNode *node;
+ 
  	if (check_col(fd, COL_PROTOCOL))
  		col_add_str(fd, COL_PROTOCOL, "SMUX");
  
***************
*** 1663,1671 ****
  			return;
  		}
  		if (tree) {
! 			format_oid(oid_string, regid, regid_length);
  			proto_tree_add_text(smux_tree, NullTVB, offset, length,
  			    "Registration: %s", oid_string);
  		}
  		g_free(regid);
  		offset += length;
--- 1919,1934 ----
  			return;
  		}
  		if (tree) {
! #ifdef HAVE_SMI_H
! 			node = smiGetNodeByOID(regid_length,
! 			    (SmiSubid *)regid);
! #else
! 			node = NULL;
! #endif
! 			oid_string = format_oid(regid, regid_length, node);
  			proto_tree_add_text(smux_tree, NullTVB, offset, length,
  			    "Registration: %s", oid_string);
+ 			g_free(oid_string);
  		}
  		g_free(regid);
  		offset += length;
***************
*** 1744,1752 ****
  			return;
  		}
  		if (tree) {
! 			format_oid(oid_string, regid, regid_length);
  			proto_tree_add_text(smux_tree, NullTVB, offset, length,
  			    "Registration: %s", oid_string);
  		}
  		g_free(regid);
  		offset += length;
--- 2007,2022 ----
  			return;
  		}
  		if (tree) {
! #ifdef HAVE_SMI_H
! 			node = smiGetNodeByOID(regid_length,
! 			    (SmiSubid *)regid);
! #else
! 			node = NULL;
! #endif
! 			oid_string = format_oid(regid, regid_length, node);
  			proto_tree_add_text(smux_tree, NullTVB, offset, length,
  			    "Registration: %s", oid_string);
+ 			g_free(oid_string);
  		}
  		g_free(regid);
  		offset += length;
***************
*** 1853,1864 ****
  void
  proto_register_snmp(void)
  {
- #ifdef linux
- 	void *libsnmp_handle;
- 	int (*snmp_set_suffix_only_p)(int);
- 	int (*ds_set_int_p)(int, int, int);
- #endif
- 
          static hf_register_info hf[] = {
  		{ &hf_snmpv3_flags,
  		{ "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
--- 2123,2128 ----
***************
*** 1881,1979 ****
  		&ett_secur,
  	};
  
! #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
! 	/* UCD or CMU SNMP */
! 	init_mib();
! #ifdef HAVE_UCD_SNMP_SNMP_H
! #ifdef linux
! 	/* As per the comment near the beginning of the file, UCD SNMP 4.1.1
! 	   changed "snmp_set_suffix_only()" from a function to a macro,
! 	   removing "snmp_set_suffix_only()" from the library; this means
! 	   that binaries that call "snmp_set_suffix_only()" and
! 	   that are linked against shared libraries from earlier versions
! 	   of the UCD SNMP library won't run with shared libraries from
! 	   4.1.1.
! 
! 	   This is a problem on Red Hat Linux, as pre-6.2 releases
! 	   came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
! 	   Versions of Ethereal built on pre-6.2 releases don't run
! 	   on 6.2, and the current Ethereal RPMs are built on pre-6.2
! 	   releases, causing problems when users running 6.2 download
! 	   them and try to use them.
! 
! 	   Building the releases on 6.2 isn't necessarily the answer,
! 	   as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
! 	   with a second argument not supported by at least some pre-4.1.1
! 	   versions of the library - it appears that the 4.0.1 library,
! 	   at least, checks for invalid arguments and returns an error
! 	   rather than stomping random memory, but that means that you
! 	   won't get get OIDs displayed as module-name::sub-OID.
! 
! 	   So we use a trick similar to one I've seen mentioned as
! 	   used in Windows applications to let you build binaries
! 	   that run on many different versions of Windows 9x and
! 	   Windows NT, that use features present on later versions
! 	   if run on those later versions, but that avoid calling,
! 	   when run on older versions, routines not present on those
! 	   older versions.
! 
! 	   I.e., we load "libsnmp.so" with "dlopen()", and call
! 	   "dlsym()" to try to find "snmp_set_suffix_only()"; if we
! 	   don't find it, we make the appropriate call to
! 	   "ds_set_int()" instead.
! 
! 	   We do this only on Linux, for now, as we've only seen the
! 	   problem on Red Hat; it may show up on other OSes that bundle
! 	   UCD SNMP, or on OSes where it's not bundled but for which
! 	   binary packages are built that link against a shared version
! 	   of the UCD SNMP library.  If we run into one of those, we
! 	   can do this under those OSes as well, *if* "dlopen()" makes
! 	   the run-time linker use the same search rules as it uses when
! 	   loading libraries with which the application is linked.
! 
! 	   (Perhaps we could use the GLib wrappers for run-time linking,
! 	   *if* they're thin enough; however, as this code is currently
! 	   used only on Linux, we don't worry about that for now.) */
! 
! 	libsnmp_handle = dlopen("libsnmp.so", RTLD_LAZY|RTLD_GLOBAL);
! 	if (libsnmp_handle == NULL) {
! 		/* We didn't find "libsnmp.so"; we may be linked
! 		   statically, in which case whatever call the following
! 		   line of code makes will presumably work, as
! 		   we have the routine it calls wired into our binary. */
! 		snmp_set_suffix_only(2);
! 	} else {
! 		/* OK, we have it loaded.  Do we have
! 		   "snmp_set_suffix_only()"? */
! 		snmp_set_suffix_only_p = dlsym(libsnmp_handle,
! 		    "snmp_set_suffix_only");
! 		if (snmp_set_suffix_only_p != NULL) {
! 			/* Yes - call it. */
! 			(*snmp_set_suffix_only_p)(2);
! 		} else {
! 			/* No; do we have "ds_set_int()"? */
! 			ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
! 			if (ds_set_int_p != NULL) {
! 				/* Yes - cal it with DS_LIBRARY_ID,
! 				   DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
! 				   arguments.
! 
! 				   We do *not* use DS_LIBRARY_ID or
! 				   DS_LIB_PRINT_SUFFIX_ONLY by name, so that
! 				   we don't require that Ethereal be built
! 				   with versions of UCD SNMP that include
! 				   that value; instead, we use their values
! 				   in UCD SNMP 4.1.1, which are 0 and 4,
! 				   respectively. */
! 				(*ds_set_int_p)(0, 4, 2);
! 			}
! 		}
! 	}
! #else /* linux */
! 	snmp_set_suffix_only(2);
! #endif /* linux */
! #endif /* HAVE_UCD_SNMP_SNMP_H */
! #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
          proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp");
          proto_smux = proto_register_protocol("SNMP Multiplex Protocol", "smux");
          proto_register_field_array(proto_snmp, hf, array_length(hf));
--- 2145,2153 ----
  		&ett_secur,
  	};
  
! #ifdef HAVE_SMI_H
! 	smiInit("ethereal");
! #endif
          proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp");
          proto_smux = proto_register_protocol("SNMP Multiplex Protocol", "smux");
          proto_register_field_array(proto_snmp, hf, array_length(hf));