From Michael Tuexen:
[obnox/wireshark/wip.git] / packet-snmp.c
1 /* packet-snmp.c
2  * Routines for SNMP (simple network management protocol)
3  * Copyright (C) 1998 Didier Jorand
4  *
5  * See RFC 1157 for SNMPv1.
6  *
7  * See RFCs 1901, 1905, and 1906 for SNMPv2c.
8  *
9  * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u.
10  *
11  * $Id: packet-snmp.c,v 1.79 2002/01/24 09:20:51 guy Exp $
12  *
13  * Ethereal - Network traffic analyzer
14  * By Gerald Combs <gerald@ethereal.com>
15  * Copyright 1998 Gerald Combs
16  *
17  * Some stuff from:
18  * 
19  * GXSNMP -- An snmp mangament application
20  * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
21  * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
22  *
23  * This program is free software; you can redistribute it and/or
24  * modify it under the terms of the GNU General Public License
25  * as published by the Free Software Foundation; either version 2
26  * of the License, or (at your option) any later version.
27  * 
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  * 
33  * You should have received a copy of the GNU General Public License
34  * along with this program; if not, write to the Free Software
35  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36  */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <ctype.h>
45
46 #ifdef HAVE_SYS_TYPES_H
47 # include <sys/types.h>
48 #endif
49
50 #ifdef HAVE_NETINET_IN_H
51 # include <netinet/in.h>
52 #endif
53
54 #define MAX_STRING_LEN 2048     /* TBC */
55
56 #ifdef linux
57 #include <dlfcn.h>
58 #endif
59
60 #include <glib.h>
61
62 #include <epan/packet.h>
63 #include <epan/strutil.h>
64 #include <epan/conversation.h>
65 #include "etypes.h"
66 #include "packet-ipx.h"
67
68 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
69  /*
70   * UCD or CMU SNMP?
71   */
72 # if defined(HAVE_UCD_SNMP_SNMP_H)
73    /*
74     * UCD SNMP.
75     */
76 #  include <ucd-snmp/asn1.h>
77 #  include <ucd-snmp/snmp_api.h>
78 #  include <ucd-snmp/snmp_impl.h>
79 #  include <ucd-snmp/mib.h>
80
81    /*
82     * Sigh.  UCD SNMP 4.1.1 makes "snmp_set_suffix_only()" a macro
83     * that calls "ds_set_int()" with the first two arguments
84     * being DS_LIBRARY_ID and DS_LIB_PRINT_SUFFIX_ONLY; this means that,
85     * when building with 4.1.1, we need to arrange that
86     * <ucd-snmp/default_store.h> is included, to define those two values
87     * and to declare "ds_int()".
88     *
89     * However:
90     *
91     *   1) we can't include it on earlier versions (at least not 3.6.2),
92     *      as it doesn't exist in those versions;
93     *
94     *   2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
95     *      as that includes <ucd-snmp/snmp.h>, and that defines a whole
96     *      bunch of values that we also define ourselves.
97     *
98     * So we only include it if "snmp_set_suffix_only" is defined as
99     * a macro.
100     */
101 #  ifdef snmp_set_suffix_only
102 #   include <ucd-snmp/default_store.h>
103 #  endif
104
105    /*
106     * XXX - for now, we assume all versions of UCD SNMP have it.
107     */
108 #  define HAVE_SPRINT_VALUE
109
110    /*
111     * Define values "sprint_value()" expects.
112     */
113 #  define VALTYPE_INTEGER       ASN_INTEGER
114 #  define VALTYPE_COUNTER       ASN_COUNTER
115 #  define VALTYPE_GAUGE         ASN_GAUGE
116 #  define VALTYPE_TIMETICKS     ASN_TIMETICKS
117 #  define VALTYPE_STRING        ASN_OCTET_STR
118 #  define VALTYPE_IPADDR        ASN_IPADDRESS
119 #  define VALTYPE_OPAQUE        ASN_OPAQUE
120 #  define VALTYPE_NSAP          ASN_NSAP
121 #  define VALTYPE_OBJECTID      ASN_OBJECT_ID
122 #  define VALTYPE_BITSTR        ASN_BIT_STR
123 #  define VALTYPE_COUNTER64     ASN_COUNTER64
124
125 #  ifdef RED_HAT_MODIFIED_UCD_SNMP
126 #    include <ucd-snmp/parse.h>
127 #  endif
128
129
130 # elif defined(HAVE_SNMP_SNMP_H)
131    /*
132     * CMU SNMP.
133     */
134 #  include <snmp/snmp.h>
135
136    /*
137     * Some older versions of CMU SNMP may lack these values (e.g., the
138     * "libsnmp3.6" package for Debian, which is based on some old
139     * CMU SNMP, perhaps 1.0); for now, we assume they also lack
140     * "sprint_value()".
141     */
142 #  ifdef SMI_INTEGER
143 #   define HAVE_SPRINT_VALUE
144     /*
145      * Define values "sprint_value()" expects.
146      */
147 #   define VALTYPE_INTEGER      SMI_INTEGER
148 #   define VALTYPE_COUNTER      SMI_COUNTER32
149 #   define VALTYPE_GAUGE        SMI_GAUGE32
150 #   define VALTYPE_TIMETICKS    SMI_TIMETICKS
151 #   define VALTYPE_STRING       SMI_STRING
152 #   define VALTYPE_IPADDR       SMI_IPADDRESS
153 #   define VALTYPE_OPAQUE       SMI_OPAQUE
154 #   define VALTYPE_NSAP         SMI_STRING
155 #   define VALTYPE_OBJECTID     SMI_OBJID
156 #   define VALTYPE_BITSTR       ASN_BIT_STR
157 #   define VALTYPE_COUNTER64    SMI_COUNTER64
158 #  endif
159   /*
160    * Now undo all the definitions they "helpfully" gave us, so we don't get
161    * complaints about redefining them.
162    *
163    * Why, oh why, is there no library that provides code to
164    *
165    *    1) read MIB files;
166    *
167    *    2) translate object IDs into names;
168    *
169    *    3) let you find out, for a given object ID, what the type, enum
170    *       values, display hint, etc. are;
171    *
172    * in a *simple* fashion, without assuming that your code is part of an
173    * SNMP agent or client that wants a pile of definitions of PDU types,
174    * etc.?  Is it just that 99 44/100% of the code that uses an SNMP library
175    * *is* part of an agent or client, and really *does* need that stuff,
176    * and *doesn't* need the interfaces we want?
177    */
178 #  undef SNMP_ERR_NOERROR
179 #  undef SNMP_ERR_TOOBIG
180 #  undef SNMP_ERR_NOSUCHNAME
181 #  undef SNMP_ERR_BADVALUE
182 #  undef SNMP_ERR_READONLY
183 #  undef SNMP_ERR_NOACCESS
184 #  undef SNMP_ERR_WRONGTYPE
185 #  undef SNMP_ERR_WRONGLENGTH
186 #  undef SNMP_ERR_WRONGENCODING
187 #  undef SNMP_ERR_WRONGVALUE
188 #  undef SNMP_ERR_NOCREATION
189 #  undef SNMP_ERR_INCONSISTENTVALUE
190 #  undef SNMP_ERR_RESOURCEUNAVAILABLE
191 #  undef SNMP_ERR_COMMITFAILED
192 #  undef SNMP_ERR_UNDOFAILED
193 #  undef SNMP_ERR_AUTHORIZATIONERROR
194 #  undef SNMP_ERR_NOTWRITABLE
195 #  undef SNMP_ERR_INCONSISTENTNAME
196 #  undef SNMP_TRAP_COLDSTART
197 #  undef SNMP_TRAP_WARMSTART
198 #  undef SNMP_TRAP_LINKDOWN
199 #  undef SNMP_TRAP_LINKUP
200 #  undef SNMP_TRAP_EGPNEIGHBORLOSS
201 #  undef SNMP_TRAP_ENTERPRISESPECIFIC
202 # endif
203 #endif
204
205 #include "asn1.h"
206
207 #include "packet-snmp.h"
208
209 /* Null string of type "guchar[]". */
210 static const guchar nullstring[] = "";
211
212 /* Take a pointer that may be null and return a pointer that's not null
213    by turning null pointers into pointers to the above null string. */
214 #define SAFE_STRING(s)  (((s) != NULL) ? (s) : nullstring)
215
216 static int proto_snmp = -1;
217 static int proto_smux = -1;
218
219 static gint ett_snmp = -1;
220 static gint ett_smux = -1;
221 static gint ett_parameters = -1;
222 static gint ett_parameters_qos = -1;
223 static gint ett_global = -1;
224 static gint ett_flags = -1;
225 static gint ett_secur = -1;
226
227 static int hf_snmpv3_flags = -1;
228 static int hf_snmpv3_flags_auth = -1;
229 static int hf_snmpv3_flags_crypt = -1;
230 static int hf_snmpv3_flags_report = -1;
231
232 static dissector_handle_t snmp_handle;
233 static dissector_handle_t data_handle;
234
235 #define TH_AUTH   0x01
236 #define TH_CRYPT  0x02
237 #define TH_REPORT 0x04
238
239 static const true_false_string flags_set_truth = {
240   "Set",
241   "Not set"
242 };
243
244 #define UDP_PORT_SNMP           161
245 #define UDP_PORT_SNMP_TRAP      162
246 #define TCP_PORT_SMUX           199
247
248 /* Protocol version numbers */
249 #define SNMP_VERSION_1  0
250 #define SNMP_VERSION_2c 1
251 #define SNMP_VERSION_2u 2
252 #define SNMP_VERSION_3  3
253
254 static const value_string versions[] = {
255         { SNMP_VERSION_1,       "1" },
256         { SNMP_VERSION_2c,      "2C" },
257         { SNMP_VERSION_2u,      "2U" },
258         { SNMP_VERSION_3,       "3" },
259         { 0,                    NULL },
260 };
261
262 /* PDU types */
263 #define SNMP_MSG_GET            0
264 #define SNMP_MSG_GETNEXT        1
265 #define SNMP_MSG_RESPONSE       2
266 #define SNMP_MSG_SET            3
267 #define SNMP_MSG_TRAP           4
268
269 #define SNMP_MSG_GETBULK        5
270 #define SNMP_MSG_INFORM         6
271 #define SNMP_MSG_TRAP2          7
272 #define SNMP_MSG_REPORT         8
273
274 static const value_string pdu_types[] = {
275         { SNMP_MSG_GET,         "GET" },
276         { SNMP_MSG_GETNEXT,     "GET-NEXT" },
277         { SNMP_MSG_SET,         "SET" },
278         { SNMP_MSG_RESPONSE,    "RESPONSE" },
279         { SNMP_MSG_TRAP,        "TRAP-V1" },
280         { SNMP_MSG_GETBULK,     "GETBULK" },
281         { SNMP_MSG_INFORM,      "INFORM" },
282         { SNMP_MSG_TRAP2,       "TRAP-V2" },
283         { SNMP_MSG_REPORT,      "REPORT" },
284         { 0,                    NULL }
285 };
286
287 /* SMUX PDU types */
288 #define SMUX_MSG_OPEN           0
289 #define SMUX_MSG_CLOSE          1
290 #define SMUX_MSG_RREQ           2
291 #define SMUX_MSG_RRSP           3
292 #define SMUX_MSG_SOUT           4
293
294 static const value_string smux_types[] = {
295         { SMUX_MSG_OPEN,        "Open" },
296         { SMUX_MSG_CLOSE,       "Close" },
297         { SMUX_MSG_RREQ,        "Registration Request" },
298         { SMUX_MSG_RRSP,        "Registration Response" },
299         { SMUX_MSG_SOUT,        "Commit Or Rollback" },
300         { 0,                    NULL }
301 };
302
303 /* SMUX Closing causes */
304 #define SMUX_CLOSE_DOWN                 0
305 #define SMUX_CLOSE_VERSION              1
306 #define SMUX_CLOSE_PACKET               2
307 #define SMUX_CLOSE_PROTOCOL             3
308 #define SMUX_CLOSE_INTERNAL             4
309 #define SMUX_CLOSE_NOAUTH               5
310
311 static const value_string smux_close[] = {
312         { SMUX_CLOSE_DOWN,      "Going down" },
313         { SMUX_CLOSE_VERSION,   "Unsupported Version" },
314         { SMUX_CLOSE_PACKET,    "Packet Format Error" },
315         { SMUX_CLOSE_PROTOCOL,  "Protocol Error" },
316         { SMUX_CLOSE_INTERNAL,  "Internal Error" },
317         { SMUX_CLOSE_NOAUTH,    "Unauthorized" },
318         { 0,                    NULL }
319 };
320
321 /* SMUX Request codes */
322 #define SMUX_RREQ_DELETE                0
323 #define SMUX_RREQ_READONLY              1
324 #define SMUX_RREQ_READWRITE             2
325
326 static const value_string smux_rreq[] = {
327         { SMUX_RREQ_DELETE,     "Delete" },
328         { SMUX_RREQ_READONLY,   "Read Only" },
329         { SMUX_RREQ_READWRITE,  "Read Write" },
330         { 0,                    NULL }
331 };
332
333 static const value_string smux_prio[] = {
334         { -1,                           "Failure" },
335         { 0,                            NULL }
336 };
337
338 /* SMUX SOut codes */
339 #define SMUX_SOUT_COMMIT                0
340 #define SMUX_SOUT_ROLLBACK              1
341
342 static const value_string smux_sout[] = {
343         { SMUX_SOUT_COMMIT,             "Commit" },
344         { SMUX_SOUT_ROLLBACK,           "Rollback" },
345         { 0,                            NULL }
346 };
347
348 /* Error status values */
349 #define SNMP_ERR_NOERROR                0
350 #define SNMP_ERR_TOOBIG                 1
351 #define SNMP_ERR_NOSUCHNAME             2
352 #define SNMP_ERR_BADVALUE               3
353 #define SNMP_ERR_READONLY               4
354 #define SNMP_ERR_GENERROR               5
355
356 #define SNMP_ERR_NOACCESS               6
357 #define SNMP_ERR_WRONGTYPE              7
358 #define SNMP_ERR_WRONGLENGTH            8
359 #define SNMP_ERR_WRONGENCODING          9
360 #define SNMP_ERR_WRONGVALUE             10
361 #define SNMP_ERR_NOCREATION             11
362 #define SNMP_ERR_INCONSISTENTVALUE      12
363 #define SNMP_ERR_RESOURCEUNAVAILABLE    13
364 #define SNMP_ERR_COMMITFAILED           14
365 #define SNMP_ERR_UNDOFAILED             15
366 #define SNMP_ERR_AUTHORIZATIONERROR     16
367 #define SNMP_ERR_NOTWRITABLE            17
368 #define SNMP_ERR_INCONSISTENTNAME       18
369
370 static const value_string error_statuses[] = {
371         { SNMP_ERR_NOERROR,             "NO ERROR" },
372         { SNMP_ERR_TOOBIG,              "TOOBIG" },
373         { SNMP_ERR_NOSUCHNAME,          "NO SUCH NAME" },
374         { SNMP_ERR_BADVALUE,            "BAD VALUE" },
375         { SNMP_ERR_READONLY,            "READ ONLY" },
376         { SNMP_ERR_GENERROR,            "GENERIC ERROR" },
377         { SNMP_ERR_NOACCESS,            "NO ACCESS" },
378         { SNMP_ERR_WRONGTYPE,           "WRONG TYPE" },
379         { SNMP_ERR_WRONGLENGTH,         "WRONG LENGTH" },
380         { SNMP_ERR_WRONGENCODING,       "WRONG ENCODING" },
381         { SNMP_ERR_WRONGVALUE,          "WRONG VALUE" },
382         { SNMP_ERR_NOCREATION,          "NO CREATION" },
383         { SNMP_ERR_INCONSISTENTVALUE,   "INCONSISTENT VALUE" },
384         { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
385         { SNMP_ERR_COMMITFAILED,        "COMMIT FAILED" },
386         { SNMP_ERR_UNDOFAILED,          "UNDO FAILED" },
387         { SNMP_ERR_AUTHORIZATIONERROR,  "AUTHORIZATION ERROR" },
388         { SNMP_ERR_NOTWRITABLE,         "NOT WRITABLE" },
389         { SNMP_ERR_INCONSISTENTNAME,    "INCONSISTENT NAME" },
390         { 0,                            NULL }
391 };
392
393 /* General SNMP V1 Traps */
394
395 #define SNMP_TRAP_COLDSTART             0
396 #define SNMP_TRAP_WARMSTART             1
397 #define SNMP_TRAP_LINKDOWN              2
398 #define SNMP_TRAP_LINKUP                3
399 #define SNMP_TRAP_AUTHFAIL              4
400 #define SNMP_TRAP_EGPNEIGHBORLOSS       5
401 #define SNMP_TRAP_ENTERPRISESPECIFIC    6
402
403 static const value_string trap_types[] = {
404         { SNMP_TRAP_COLDSTART,          "COLD START" },
405         { SNMP_TRAP_WARMSTART,          "WARM START" },
406         { SNMP_TRAP_LINKDOWN,           "LINK DOWN" },
407         { SNMP_TRAP_LINKUP,             "LINK UP" },
408         { SNMP_TRAP_AUTHFAIL,           "AUTHENTICATION FAILED" },
409         { SNMP_TRAP_EGPNEIGHBORLOSS,    "EGP NEIGHBORLOSS" },
410         { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
411         { 0,                            NULL }
412 };
413
414 /* Security Models */
415
416 #define SNMP_SEC_ANY                    0
417 #define SNMP_SEC_V1                     1
418 #define SNMP_SEC_V2C                    2
419 #define SNMP_SEC_USM                    3
420
421 static const value_string sec_models[] = {
422         { SNMP_SEC_ANY,                 "Any" },
423         { SNMP_SEC_V1,                  "V1" },
424         { SNMP_SEC_V2C,                 "V2C" },
425         { SNMP_SEC_USM,                 "USM" },
426         { 0,                            NULL }
427 };
428
429 /* SNMP Tags */
430
431 #define SNMP_IPA    0           /* IP Address */
432 #define SNMP_CNT    1           /* Counter (Counter32) */
433 #define SNMP_GGE    2           /* Gauge (Gauge32) */
434 #define SNMP_TIT    3           /* TimeTicks */
435 #define SNMP_OPQ    4           /* Opaque */
436 #define SNMP_NSP    5           /* NsapAddress */
437 #define SNMP_C64    6           /* Counter64 */
438 #define SNMP_U32    7           /* Uinteger32 */
439
440 #define SERR_NSO    0
441 #define SERR_NSI    1
442 #define SERR_EOM    2
443
444 /* SNMPv1 Types */
445
446 #define SNMP_NULL                0
447 #define SNMP_INTEGER             1    /* l  */
448 #define SNMP_OCTETSTR            2    /* c  */
449 #define SNMP_DISPLAYSTR          2    /* c  */
450 #define SNMP_OBJECTID            3    /* ul */
451 #define SNMP_IPADDR              4    /* uc */
452 #define SNMP_COUNTER             5    /* ul */
453 #define SNMP_GAUGE               6    /* ul */
454 #define SNMP_TIMETICKS           7    /* ul */
455 #define SNMP_OPAQUE              8    /* c  */
456
457 /* additional SNMPv2 Types */
458
459 #define SNMP_UINTEGER            5    /* ul */
460 #define SNMP_BITSTR              9    /* uc */
461 #define SNMP_NSAP               10    /* uc */
462 #define SNMP_COUNTER64          11    /* ul */
463 #define SNMP_NOSUCHOBJECT       12
464 #define SNMP_NOSUCHINSTANCE     13
465 #define SNMP_ENDOFMIBVIEW       14
466
467 typedef struct _SNMP_CNV SNMP_CNV;
468
469 struct _SNMP_CNV
470 {
471   guint class;
472   guint tag;
473   gint  syntax;
474   gchar *name;
475 };
476
477 static SNMP_CNV SnmpCnv [] =
478 {
479   {ASN1_UNI, ASN1_NUL, SNMP_NULL,      "NULL"},
480   {ASN1_UNI, ASN1_INT, SNMP_INTEGER,   "INTEGER"},
481   {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR,  "OCTET STRING"},
482   {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID,  "OBJECTID"},
483   {ASN1_APL, SNMP_IPA, SNMP_IPADDR,    "IPADDR"},
484   {ASN1_APL, SNMP_CNT, SNMP_COUNTER,   "COUNTER"},  /* Counter32 */
485   {ASN1_APL, SNMP_GGE, SNMP_GAUGE,     "GAUGE"},    /* Gauge32 == Unsigned32  */
486   {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
487   {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE,    "OPAQUE"},
488
489 /* SNMPv2 data types and errors */
490
491   {ASN1_UNI, ASN1_BTS, SNMP_BITSTR,         "BITSTR"},
492   {ASN1_APL, SNMP_C64, SNMP_COUNTER64,      "COUNTER64"},
493   {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT,   "NOSUCHOBJECT"},
494   {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
495   {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW,   "ENDOFMIBVIEW"},
496   {0,       0,         -1,                  NULL}
497 };
498
499 /*
500  * NAME:        g_snmp_tag_cls2syntax
501  * SYNOPSIS:    gboolean g_snmp_tag_cls2syntax
502  *                  (
503  *                      guint    tag,
504  *                      guint    cls,
505  *                      gushort *syntax
506  *                  )
507  * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
508  *              See SnmpCnv for conversion.
509  * RETURNS:     name on success, NULL on failure
510  */
511
512 static gchar *
513 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
514 {
515     SNMP_CNV *cnv;
516
517     cnv = SnmpCnv;
518     while (cnv->syntax != -1)
519     {
520         if (cnv->tag == tag && cnv->class == cls)
521         {
522             *syntax = cnv->syntax;
523             return cnv->name;
524         }
525         cnv++;
526     }
527     return NULL;
528 }
529
530 static void
531 dissect_snmp_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
532                    proto_tree *tree, const char *field_name, int ret)
533 {
534         const gchar *errstr;
535
536         switch (ret) {
537
538         case ASN1_ERR_EOC_MISMATCH:
539                 errstr = "EOC mismatch";
540                 break;
541
542         case ASN1_ERR_WRONG_TYPE:
543                 errstr = "Wrong type for that item";
544                 break;
545
546         case ASN1_ERR_LENGTH_NOT_DEFINITE:
547                 errstr = "Length was indefinite";
548                 break;
549
550         case ASN1_ERR_LENGTH_MISMATCH:
551                 errstr = "Length mismatch";
552                 break;
553
554         case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
555                 errstr = "Wrong length for that item's type";
556                 break;
557
558         default:
559                 errstr = "Unknown error";
560                 break;
561         }
562
563         if (check_col(pinfo->cinfo, COL_INFO)) {
564                 col_add_fstr(pinfo->cinfo, COL_INFO,
565                     "ERROR: Couldn't parse %s: %s", field_name, errstr);
566         }
567         if (tree != NULL) {
568                 proto_tree_add_text(tree, tvb, offset, 0,
569                     "ERROR: Couldn't parse %s: %s", field_name, errstr);
570                 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
571         }
572 }
573
574 static void
575 dissect_snmp_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
576                    proto_tree *tree, const char *message)
577 {
578         if (check_col(pinfo->cinfo, COL_INFO))
579                 col_add_str(pinfo->cinfo, COL_INFO, message);
580
581         if (tree != NULL) {
582                 proto_tree_add_text(tree, tvb, offset, 0, "%s", message);
583                 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
584         }
585 }
586
587 static gchar *
588 format_oid(subid_t *oid, guint oid_length)
589 {
590         char *result;
591         int result_len;
592         int len;
593         unsigned int i;
594         char *buf;
595
596         result_len = oid_length * 22;
597         result = g_malloc(result_len + 1);
598         buf = result;
599         len = sprintf(buf, "%lu", (unsigned long)oid[0]);
600         buf += len;
601         for (i = 1; i < oid_length;i++) {
602                 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
603                 buf += len;
604         }
605         return result;
606 }
607
608 #ifdef HAVE_SPRINT_VALUE
609 static gchar *
610 format_var(struct variable_list *variable, subid_t *variable_oid,
611     guint variable_oid_length, gushort vb_type, guint vb_length)
612 {
613         gchar *buf;
614
615         switch (vb_type) {
616
617         case SNMP_INTEGER:
618         case SNMP_COUNTER:
619         case SNMP_GAUGE:
620         case SNMP_TIMETICKS:
621                 /* We don't know how long this will be, but let's guess it
622                    fits within 128 characters; that should be enough for an
623                    integral value plus some sort of type indication. */
624                 buf = g_malloc(128);
625                 break;
626
627         case SNMP_OCTETSTR:
628         case SNMP_IPADDR:
629         case SNMP_OPAQUE:
630         case SNMP_NSAP:
631         case SNMP_BITSTR:
632         case SNMP_COUNTER64:
633                 /* We don't know how long this will be, but let's guess it
634                    fits within 128 characters plus 4 characters per octet. */
635                 buf = g_malloc(128 + 4*vb_length);
636                 break;
637
638         case SNMP_OBJECTID:
639                 /* We don't know how long this will be, but let's guess it
640                    fits within 128 characters plus 32 characters per subid
641                    (10 digits plus period, or a subid name). */
642                 buf = g_malloc(1024 + 32*vb_length);
643                 break;
644
645         default:
646                 /* Should not happen. */
647                 g_assert_not_reached();
648                 buf = NULL;
649                 break;
650         }
651
652         variable->next_variable = NULL;
653         variable->name = variable_oid;
654         variable->name_length = variable_oid_length;
655         switch (vb_type) {
656
657         case SNMP_INTEGER:
658                 variable->type = VALTYPE_INTEGER;
659                 break;
660
661         case SNMP_COUNTER:
662                 variable->type = VALTYPE_COUNTER;
663                 break;
664
665         case SNMP_GAUGE:
666                 variable->type = VALTYPE_GAUGE;
667                 break;
668
669         case SNMP_TIMETICKS:
670                 variable->type = VALTYPE_TIMETICKS;
671                 break;
672
673         case SNMP_OCTETSTR:
674                 variable->type = VALTYPE_STRING;
675                 break;
676
677         case SNMP_IPADDR:
678                 variable->type = VALTYPE_IPADDR;
679                 break;
680
681         case SNMP_OPAQUE:
682                 variable->type = VALTYPE_OPAQUE;
683                 break;
684
685         case SNMP_NSAP:
686                 variable->type = VALTYPE_NSAP;
687                 break;
688
689         case SNMP_OBJECTID:
690                 variable->type = VALTYPE_OBJECTID;
691                 vb_length *= sizeof (subid_t);  /* XXX - necessary? */
692                 break;
693
694         case SNMP_BITSTR:
695                 variable->type = VALTYPE_BITSTR;
696                 break;
697
698         case SNMP_COUNTER64:
699                 variable->type = VALTYPE_COUNTER64;
700                 break;
701         }
702         variable->val_len = vb_length;
703
704 # ifdef RED_HAT_MODIFIED_UCD_SNMP
705         sprint_value(binit(NULL, buf, sizeof(buf)), variable_oid,
706             variable_oid_length, variable);
707 # else
708         sprint_value(buf, variable_oid, variable_oid_length, variable);
709 # endif
710         return buf;
711 }
712 #endif
713
714 static int
715 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
716     guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp,
717     gboolean unsafe)
718 {
719         int start;
720         guint length;
721         gboolean def;
722         guint vb_length;
723         gushort vb_type;
724         gchar *vb_type_name;
725         int ret;
726         guint cls, con, tag;
727
728         gint32 vb_integer_value;
729         guint32 vb_uinteger_value;
730
731         guint8 *vb_octet_string;
732
733         subid_t *vb_oid;
734         guint vb_oid_length;
735
736         gchar *vb_display_string;
737
738 #ifdef HAVE_SPRINT_VALUE
739         struct variable_list variable;
740 #if defined(HAVE_UCD_SNMP_SNMP_H)
741         long value;
742 #endif
743 #endif  /* HAVE_SPRINT_VALUE */
744         unsigned int i;
745         gchar *buf;
746         int len;
747
748         /* parse the type of the object */
749         start = asn1->offset;
750         ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
751         if (ret != ASN1_ERR_NOERROR)
752                 return ret;
753         if (!def)
754                 return ASN1_ERR_LENGTH_NOT_DEFINITE;
755
756         /* Convert the class, constructed flag, and tag to a type. */
757         vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
758         if (vb_type_name == NULL) {
759                 /*
760                  * Unsupported type.
761                  * Dissect the value as an opaque string of octets.
762                  */
763                 vb_type_name = "unsupported type";
764                 vb_type = SNMP_OPAQUE;
765         }
766
767         /* parse the value */
768         switch (vb_type) {
769
770         case SNMP_INTEGER:
771                 ret = asn1_int32_value_decode(asn1, vb_length,
772                     &vb_integer_value);
773                 if (ret != ASN1_ERR_NOERROR)
774                         return ret;
775                 length = asn1->offset - start;
776                 if (snmp_tree) {
777 #ifdef HAVE_SPRINT_VALUE
778                         if (!unsafe) {
779 #if defined(HAVE_UCD_SNMP_SNMP_H)
780                                 value = vb_integer_value;
781                                 variable.val.integer = &value;
782 #elif defined(HAVE_SNMP_SNMP_H)
783                                 variable.val.integer = &vb_integer_value;
784 #endif
785                                 vb_display_string = format_var(&variable,
786                                     variable_oid, variable_oid_length, vb_type,
787                                     vb_length);
788                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
789                                     length,
790                                     "Value: %s", vb_display_string);
791                                 g_free(vb_display_string);
792                                 break;  /* we added formatted version to the tree */
793                         }
794 #endif /* HAVE_SPRINT_VALUE */
795                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
796                             "Value: %s: %d (%#x)", vb_type_name,
797                             vb_integer_value, vb_integer_value);
798                 }
799                 break;
800
801         case SNMP_COUNTER:
802         case SNMP_GAUGE:
803         case SNMP_TIMETICKS:
804                 ret = asn1_uint32_value_decode(asn1, vb_length,
805                     &vb_uinteger_value);
806                 if (ret != ASN1_ERR_NOERROR)
807                         return ret;
808                 length = asn1->offset - start;
809                 if (snmp_tree) {
810 #ifdef HAVE_SPRINT_VALUE
811                         if (!unsafe) {
812 #if defined(HAVE_UCD_SNMP_SNMP_H)
813                                 value = vb_uinteger_value;
814                                 variable.val.integer = &value;
815 #elif defined(HAVE_SNMP_SNMP_H)
816                                 variable.val.integer = &vb_uinteger_value;
817 #endif
818                                 vb_display_string = format_var(&variable,
819                                     variable_oid, variable_oid_length, vb_type,
820                                     vb_length);
821                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
822                                     length,
823                                     "Value: %s", vb_display_string);
824                                 g_free(vb_display_string);
825                                 break;  /* we added formatted version to the tree */
826                         }
827 #endif /* HAVE_SPRINT_VALUE */
828                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
829                             "Value: %s: %u (%#x)", vb_type_name,
830                             vb_uinteger_value, vb_uinteger_value);
831                 }
832                 break;
833
834         case SNMP_OCTETSTR:
835         case SNMP_IPADDR:
836         case SNMP_OPAQUE:
837         case SNMP_NSAP:
838         case SNMP_BITSTR:
839         case SNMP_COUNTER64:
840                 ret = asn1_string_value_decode (asn1, vb_length,
841                     &vb_octet_string);
842                 if (ret != ASN1_ERR_NOERROR)
843                         return ret;
844                 length = asn1->offset - start;
845                 if (snmp_tree) {
846 #ifdef HAVE_SPRINT_VALUE
847                         if (!unsafe) {
848                                 variable.val.string = vb_octet_string;
849                                 vb_display_string = format_var(&variable,
850                                     variable_oid, variable_oid_length, vb_type,
851                                     vb_length);
852                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
853                                     length,
854                                     "Value: %s", vb_display_string);
855                                 g_free(vb_display_string);
856                                 break;  /* we added formatted version to the tree */
857                         }
858 #endif /* HAVE_SPRINT_VALUE */
859                         /*
860                          * If some characters are not printable, display
861                          * the string as bytes.
862                          */
863                         for (i = 0; i < vb_length; i++) {
864                                 if (!(isprint(vb_octet_string[i])
865                                     || isspace(vb_octet_string[i])))
866                                         break;
867                         }
868                         if (i < vb_length) {
869                                 /*
870                                  * We stopped, due to a non-printable
871                                  * character, before we got to the end
872                                  * of the string.
873                                  */
874                                 vb_display_string = g_malloc(4*vb_length);
875                                 buf = &vb_display_string[0];
876                                 len = sprintf(buf, "%03u", vb_octet_string[0]);
877                                 buf += len;
878                                 for (i = 1; i < vb_length; i++) {
879                                         len = sprintf(buf, ".%03u",
880                                             vb_octet_string[i]);
881                                         buf += len;
882                                 }
883                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
884                                     "Value: %s: %s", vb_type_name,
885                                     vb_display_string);
886                                 g_free(vb_display_string);
887                         } else {
888                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
889                                     "Value: %s: %.*s", vb_type_name,
890                                     (int)vb_length,
891                                     SAFE_STRING(vb_octet_string));
892                         }
893                 }
894                 g_free(vb_octet_string);
895                 break;
896
897         case SNMP_NULL:
898                 ret = asn1_null_decode (asn1, vb_length);
899                 if (ret != ASN1_ERR_NOERROR)
900                         return ret;
901                 length = asn1->offset - start;
902                 if (snmp_tree) {
903                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
904                             "Value: %s", vb_type_name);
905                 }
906                 break;
907
908         case SNMP_OBJECTID:
909                 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
910                     &vb_oid_length);
911                 if (ret != ASN1_ERR_NOERROR)
912                         return ret;
913                 length = asn1->offset - start;
914                 if (snmp_tree) {
915 #ifdef HAVE_SPRINT_VALUE
916                         if (!unsafe) {
917                                 variable.val.objid = vb_oid;
918                                 vb_display_string = format_var(&variable,
919                                     variable_oid, variable_oid_length, vb_type,
920                                     vb_length);
921                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
922                                     length,
923                                     "Value: %s", vb_display_string);
924                                 break;  /* we added formatted version to the tree */
925                         }
926 #endif /* HAVE_SPRINT_VALUE */
927                         vb_display_string = format_oid(vb_oid, vb_oid_length);
928                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
929                             "Value: %s: %s", vb_type_name, vb_display_string);
930                         g_free(vb_display_string);
931                 }
932                 g_free(vb_oid);
933                 break;
934
935         case SNMP_NOSUCHOBJECT:
936                 length = asn1->offset - start;
937                 if (snmp_tree) {
938                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
939                             "Value: %s: no such object", vb_type_name);
940                 }
941                 break;
942
943         case SNMP_NOSUCHINSTANCE:
944                 length = asn1->offset - start;
945                 if (snmp_tree) {
946                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
947                             "Value: %s: no such instance", vb_type_name);
948                 }
949                 break;
950
951         case SNMP_ENDOFMIBVIEW:
952                 length = asn1->offset - start;
953                 if (snmp_tree) {
954                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
955                             "Value: %s: end of mib view", vb_type_name);
956                 }
957                 break;
958
959         default:
960                 g_assert_not_reached();
961                 return ASN1_ERR_WRONG_TYPE;
962         }
963         *lengthp = length;
964         return ASN1_ERR_NOERROR;
965 }
966
967 static void
968 dissect_common_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
969     proto_tree *tree, ASN1_SCK asn1, guint pdu_type, int start)
970 {
971         gboolean def;
972         guint length;
973         guint sequence_length;
974
975         guint32 request_id;
976
977         guint32 error_status;
978
979         guint32 error_index;
980
981         char *pdu_type_string;
982
983         subid_t *enterprise;
984         guint enterprise_length;
985
986         guint8 *agent_address;
987         guint agent_address_length;
988
989         guint32 trap_type;
990
991         guint32 specific_type;
992
993         guint timestamp;
994         guint timestamp_length;
995
996         gchar *oid_string;
997
998         guint variable_bindings_length;
999
1000         int vb_index;
1001         guint variable_length;
1002         subid_t *variable_oid;
1003         guint variable_oid_length;
1004 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1005         gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
1006 #endif
1007         gboolean unsafe;
1008
1009         int ret;
1010         guint cls, con, tag;
1011
1012         pdu_type_string = val_to_str(pdu_type, pdu_types,
1013             "Unknown PDU type %#x");
1014         if (check_col(pinfo->cinfo, COL_INFO))
1015                 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
1016         length = asn1.offset - start;
1017         if (tree) {
1018                 proto_tree_add_text(tree, tvb, offset, length,
1019                     "PDU type: %s", pdu_type_string);
1020         }
1021         offset += length;
1022
1023         /* get the fields in the PDU preceeding the variable-bindings sequence */
1024         switch (pdu_type) {
1025
1026         case SNMP_MSG_GET:
1027         case SNMP_MSG_GETNEXT:
1028         case SNMP_MSG_RESPONSE:
1029         case SNMP_MSG_SET:
1030         case SNMP_MSG_GETBULK:
1031         case SNMP_MSG_INFORM:
1032         case SNMP_MSG_TRAP2:
1033         case SNMP_MSG_REPORT:
1034                 /* request id */
1035                 ret = asn1_uint32_decode (&asn1, &request_id, &length);
1036                 if (ret != ASN1_ERR_NOERROR) {
1037                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1038                             "request ID", ret);
1039                         return;
1040                 }
1041                 if (tree) {
1042                         proto_tree_add_text(tree, tvb, offset, length,
1043                             "Request Id: %#x", request_id);
1044                 }
1045                 offset += length;
1046                 
1047                 /* error status, or getbulk non-repeaters */
1048                 ret = asn1_uint32_decode (&asn1, &error_status, &length);
1049                 if (ret != ASN1_ERR_NOERROR) {
1050                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1051                             (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
1052                                                            : "error status",
1053                             ret);
1054                         return;
1055                 }
1056                 if (tree) {
1057                         if (pdu_type == SNMP_MSG_GETBULK) {
1058                                 proto_tree_add_text(tree, tvb, offset,
1059                                     length, "Non-repeaters: %u", error_status);
1060                         } else {
1061                                 proto_tree_add_text(tree, tvb, offset,
1062                                     length, "Error Status: %s",
1063                                     val_to_str(error_status, error_statuses,
1064                                       "Unknown (%d)"));
1065                         }
1066                 }
1067                 offset += length;
1068
1069                 /* error index, or getbulk max-repetitions */
1070                 ret = asn1_uint32_decode (&asn1, &error_index, &length);
1071                 if (ret != ASN1_ERR_NOERROR) {
1072                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1073                             (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
1074                                                            : "error index",
1075                             ret);
1076                         return;
1077                 }
1078                 if (tree) {
1079                         if (pdu_type == SNMP_MSG_GETBULK) {
1080                                 proto_tree_add_text(tree, tvb, offset,
1081                                     length, "Max repetitions: %u", error_index);
1082                         } else {
1083                                 proto_tree_add_text(tree, tvb, offset,
1084                                     length, "Error Index: %u", error_index);
1085                         }
1086                 }
1087                 offset += length;
1088                 break;
1089
1090         case SNMP_MSG_TRAP:
1091                 /* enterprise */
1092                 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
1093                     &length);
1094                 if (ret != ASN1_ERR_NOERROR) {
1095                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1096                             "enterprise OID", ret);
1097                         return;
1098                 }
1099                 if (tree) {
1100                         oid_string = format_oid(enterprise, enterprise_length);
1101                         proto_tree_add_text(tree, tvb, offset, length,
1102                             "Enterprise: %s", oid_string);
1103                         g_free(oid_string);
1104                 }
1105                 g_free(enterprise);
1106                 offset += length;
1107
1108                 /* agent address */
1109                 start = asn1.offset;
1110                 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1111                     &def, &agent_address_length);
1112                 if (ret != ASN1_ERR_NOERROR) {
1113                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1114                             "agent address", ret);
1115                         return;
1116                 }
1117                 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
1118                     (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
1119                         /* GXSNMP 0.0.15 says the latter is "needed for
1120                            Banyan" */
1121                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1122                             "agent_address", ASN1_ERR_WRONG_TYPE);
1123                         return;
1124                 }
1125                 if (agent_address_length != 4) {
1126                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1127                             "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
1128                         return;
1129                 }
1130                 ret = asn1_string_value_decode (&asn1,
1131                     agent_address_length, &agent_address);
1132                 if (ret != ASN1_ERR_NOERROR) {
1133                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1134                             "agent address", ret);
1135                         return;
1136                 }
1137                 length = asn1.offset - start;
1138                 if (tree) {
1139                         if (agent_address_length != 4) {
1140                                 proto_tree_add_text(tree, tvb, offset,
1141                                     length,
1142                                     "Agent address: <length is %u, not 4>",
1143                                     agent_address_length);
1144                         } else {
1145                                 proto_tree_add_text(tree, tvb, offset,
1146                                     length,
1147                                     "Agent address: %s",
1148                                     ip_to_str(agent_address));
1149                         }
1150                 }
1151                 g_free(agent_address);
1152                 offset += length;
1153                 
1154                 /* generic trap type */
1155                 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1156                 if (ret != ASN1_ERR_NOERROR) {
1157                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1158                             "generic trap type", ret);
1159                         return;
1160                 }
1161                 if (tree) {
1162                         proto_tree_add_text(tree, tvb, offset, length,
1163                             "Trap type: %s",
1164                             val_to_str(trap_type, trap_types, "Unknown (%u)"));
1165                 }               
1166                 offset += length;
1167                 
1168                 /* specific trap type */
1169                 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1170                 if (ret != ASN1_ERR_NOERROR) {
1171                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1172                             "specific trap type", ret);
1173                         return;
1174                 }
1175                 if (tree) {
1176                         proto_tree_add_text(tree, tvb, offset, length,
1177                             "Specific trap type: %u (%#x)",
1178                             specific_type, specific_type);
1179                 }               
1180                 offset += length;
1181                 
1182                 /* timestamp */
1183                 start = asn1.offset;
1184                 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1185                     &def, &timestamp_length);
1186                 if (ret != ASN1_ERR_NOERROR) {
1187                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1188                             "timestamp", ret);
1189                         return;
1190                 }
1191                 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1192                     (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1193                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1194                             "timestamp", ASN1_ERR_WRONG_TYPE);
1195                         return;
1196                 }
1197                 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1198                     &timestamp);
1199                 if (ret != ASN1_ERR_NOERROR) {
1200                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1201                             "timestamp", ret);
1202                         return;
1203                 }
1204                 length = asn1.offset - start;
1205                 if (tree) {
1206                         proto_tree_add_text(tree, tvb, offset, length,
1207                             "Timestamp: %u", timestamp);
1208                 }               
1209                 offset += length;
1210                 break;
1211         }
1212
1213         /* variable bindings */
1214         /* get header for variable-bindings sequence */
1215         ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1216         if (ret != ASN1_ERR_NOERROR) {
1217                 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1218                         "variable bindings header", ret);
1219                 return;
1220         }
1221         offset += length;
1222
1223         /* loop on variable bindings */
1224         vb_index = 0;
1225         while (variable_bindings_length > 0) {
1226                 vb_index++;
1227                 sequence_length = 0;
1228
1229                 /* parse type */
1230                 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1231                 if (ret != ASN1_ERR_NOERROR) {
1232                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1233                                 "variable binding header", ret);
1234                         return;
1235                 }
1236                 sequence_length += length;
1237
1238                 /* parse object identifier */
1239                 ret = asn1_oid_decode (&asn1, &variable_oid,
1240                     &variable_oid_length, &length);
1241                 if (ret != ASN1_ERR_NOERROR) {
1242                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1243                             "variable binding OID", ret);
1244                         return;
1245                 }
1246                 sequence_length += length;
1247
1248                 unsafe = FALSE;
1249                 if (tree) {
1250                         oid_string = format_oid(variable_oid,
1251                             variable_oid_length);
1252                         
1253 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1254 # ifdef RED_HAT_MODIFIED_UCD_SNMP
1255                         sprint_objid(binit(NULL, vb_oid_string, sizeof(vb_oid_string)), 
1256                             variable_oid, variable_oid_length);
1257 # else
1258                         sprint_objid(vb_oid_string, variable_oid,
1259                             variable_oid_length);
1260 # endif
1261                         proto_tree_add_text(tree, tvb, offset, sequence_length,
1262                             "Object identifier %d: %s (%s)", vb_index,
1263                             oid_string, vb_oid_string);
1264 #ifdef HAVE_SNMP_SNMP_H
1265                         /*
1266                          * CMU SNMP has a bug wherein "sprint_value()"
1267                          * calls "get_symbol()", passing it the
1268                          * OID supplied, to get an information about the
1269                          * variable, and blithely assumes that it will
1270                          * never get a null pointer back and dereferences
1271                          * the resulting pointer.
1272                          *
1273                          * Not true.  If there's nothing in the MIB
1274                          * about *any* of the components of the OID,
1275                          * it'll return a null pointer.
1276                          *
1277                          * So we have to check for that, and pass
1278                          * down to "snmp_variable_decode" a flag
1279                          * saying "don't pass this to 'sprint_value()'.
1280                          *
1281                          * We check for that by looking for a decoded
1282                          * OID string beginning with "." followed by a
1283                          * digit, meaning it couldn't even find any
1284                          * symbolic representation for the very
1285                          * beginning of the OID string.
1286                          */
1287                         if (vb_oid_string[0] == '.' &&
1288                             isdigit((guchar)vb_oid_string[1]))
1289                                 unsafe = TRUE;
1290 #endif /* HAVE_SNMP_SNMP_H */
1291 #else /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1292                         proto_tree_add_text(tree, tvb, offset, sequence_length,
1293                             "Object identifier %d: %s", vb_index,
1294                             oid_string);
1295 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1296                         g_free(oid_string);
1297                 }
1298                 offset += sequence_length;
1299                 variable_bindings_length -= sequence_length;
1300                                 
1301                 /* Parse the variable's value */
1302                 ret = snmp_variable_decode(tree, variable_oid,
1303                     variable_oid_length, &asn1, offset, &length,
1304                     unsafe);
1305                 if (ret != ASN1_ERR_NOERROR) {
1306                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1307                             "variable", ret);
1308                         return;
1309                 }
1310                 offset += length;
1311                 variable_bindings_length -= length;
1312         }
1313 }
1314
1315 static const value_string qos_vals[] = {
1316         { 0x0,  "No authentication or privacy" },
1317         { 0x1,  "Authentication, no privacy" },
1318         { 0x2,  "Authentication and privacy" },
1319         { 0x3,  "Authentication and privacy" },
1320         { 0,    NULL },
1321 };
1322
1323 static void
1324 dissect_snmp2u_parameters(proto_tree *tree, tvbuff_t *tvb, int offset, int length,
1325     guchar *parameters, int parameters_length)
1326 {
1327         proto_item *item;
1328         proto_tree *parameters_tree;
1329         proto_tree *qos_tree;
1330         guint8 model;
1331         guint8 qos;
1332         guint8 len;
1333
1334         item = proto_tree_add_text(tree, tvb, offset, length,
1335             "Parameters");
1336         parameters_tree = proto_item_add_subtree(item, ett_parameters);
1337         offset += length - parameters_length;
1338
1339         if (parameters_length < 1)
1340                 return;
1341         model = *parameters;
1342         proto_tree_add_text(parameters_tree, tvb, offset, 1,
1343             "model: %u", model);
1344         offset += 1;
1345         parameters += 1;
1346         parameters_length -= 1;
1347         if (model != 1) {
1348                 /* Unknown model. */
1349                 proto_tree_add_text(parameters_tree, tvb, offset,
1350                     parameters_length, "parameters: %s",
1351                     bytes_to_str(parameters, parameters_length));
1352                 return;
1353         }
1354
1355         if (parameters_length < 1)
1356                 return;
1357         qos = *parameters;
1358         item = proto_tree_add_text(parameters_tree, tvb, offset, 1,
1359             "qoS: 0x%x", qos);
1360         qos_tree = proto_item_add_subtree(item, ett_parameters_qos);
1361         proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
1362             decode_boolean_bitfield(qos, 0x04,
1363                 8, "Generation of report PDU allowed",
1364                    "Generation of report PDU not allowed"));
1365         proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
1366             decode_enumerated_bitfield(qos, 0x03,
1367                 8, qos_vals, "%s"));
1368         offset += 1;
1369         parameters += 1;
1370         parameters_length -= 1;
1371
1372         if (parameters_length < 12)
1373                 return;
1374         proto_tree_add_text(parameters_tree, tvb, offset, 12,
1375             "agentID: %s", bytes_to_str(parameters, 12));
1376         offset += 12;
1377         parameters += 12;
1378         parameters_length -= 12;
1379
1380         if (parameters_length < 4)
1381                 return;
1382         proto_tree_add_text(parameters_tree, tvb, offset, 4,
1383             "agentBoots: %u", pntohl(parameters));
1384         offset += 4;
1385         parameters += 4;
1386         parameters_length -= 4;
1387
1388         if (parameters_length < 4)
1389                 return;
1390         proto_tree_add_text(parameters_tree, tvb, offset, 4,
1391             "agentTime: %u", pntohl(parameters));
1392         offset += 4;
1393         parameters += 4;
1394         parameters_length -= 4;
1395
1396         if (parameters_length < 2)
1397                 return;
1398         proto_tree_add_text(parameters_tree, tvb, offset, 2,
1399             "maxSize: %u", pntohs(parameters));
1400         offset += 2;
1401         parameters += 2;
1402         parameters_length -= 2;
1403
1404         if (parameters_length < 1)
1405                 return;
1406         len = *parameters;
1407         proto_tree_add_text(parameters_tree, tvb, offset, 1,
1408             "userLen: %u", len);
1409         offset += 1;
1410         parameters += 1;
1411         parameters_length -= 1;
1412
1413         if (parameters_length < len)
1414                 return;
1415         proto_tree_add_text(parameters_tree, tvb, offset, len,
1416             "userName: %.*s", len, parameters);
1417         offset += len;
1418         parameters += len;
1419         parameters_length -= len;
1420
1421         if (parameters_length < 1)
1422                 return;
1423         len = *parameters;
1424         proto_tree_add_text(parameters_tree, tvb, offset, 1,
1425             "authLen: %u", len);
1426         offset += 1;
1427         parameters += 1;
1428         parameters_length -= 1;
1429
1430         if (parameters_length < len)
1431                 return;
1432         proto_tree_add_text(parameters_tree, tvb, offset, len,
1433             "authDigest: %s", bytes_to_str(parameters, len));
1434         offset += len;
1435         parameters += len;
1436         parameters_length -= len;
1437
1438         if (parameters_length < 1)
1439                 return;
1440         proto_tree_add_text(parameters_tree, tvb, offset, parameters_length,
1441             "contextSelector: %s", bytes_to_str(parameters, parameters_length));
1442 }
1443
1444 void
1445 dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1446     proto_tree *tree, char *proto_name, int proto, gint ett)
1447 {
1448         ASN1_SCK asn1;
1449         int start;
1450         gboolean def;
1451         gboolean encrypted;
1452         guint length;
1453         guint message_length;
1454         guint global_length;
1455
1456         guint32 version;
1457         guint32 msgid;
1458         guint32 msgmax;
1459         guint32 msgsec;
1460         guint32 engineboots;
1461         guint32 enginetime;
1462
1463         guchar *msgflags;
1464         guchar *community;
1465         guchar *secparm;
1466         guchar *cengineid;
1467         guchar *cname;
1468         guchar *cryptpdu;
1469         guchar *aengineid;
1470         guchar *username;
1471         guchar *authpar;
1472         guchar *privpar;
1473         int msgflags_length;
1474         int community_length;
1475         int secparm_length;
1476         int cengineid_length;
1477         int cname_length;
1478         int cryptpdu_length;
1479         int aengineid_length;
1480         int username_length;
1481         int authpar_length;
1482         int privpar_length;
1483
1484         guint pdu_type;
1485         guint pdu_length;
1486
1487         proto_tree *snmp_tree = NULL;
1488         proto_tree *global_tree = NULL;
1489         proto_tree *flags_tree = NULL;
1490         proto_tree *secur_tree = NULL;
1491         proto_item *item = NULL;
1492         int ret;
1493         guint cls, con, tag;
1494
1495         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1496                 col_add_str(pinfo->cinfo, COL_PROTOCOL, proto_name);
1497
1498         if (tree) {
1499                 item = proto_tree_add_item(tree, proto, tvb, offset, -1, FALSE);
1500                 snmp_tree = proto_item_add_subtree(item, ett);
1501         }
1502
1503         /* NOTE: we have to parse the message piece by piece, since the
1504          * capture length may be less than the message length: a 'global'
1505          * parsing is likely to fail.
1506          */
1507         /* parse the SNMP header */
1508         asn1_open(&asn1, tvb, offset);
1509         ret = asn1_sequence_decode(&asn1, &message_length, &length);
1510         if (ret != ASN1_ERR_NOERROR) {
1511                 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1512                         "message header", ret);
1513                 return;
1514         }
1515         offset += length;
1516
1517         ret = asn1_uint32_decode (&asn1, &version, &length);
1518         if (ret != ASN1_ERR_NOERROR) {
1519                 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1520                     "version number", ret);
1521                 return;
1522         }
1523         if (snmp_tree) {
1524                 proto_tree_add_text(snmp_tree, tvb, offset, length,
1525                     "Version: %s",
1526                     val_to_str(version, versions, "Unknown version %#x"));
1527         }
1528         offset += length;
1529
1530
1531         switch (version) {
1532         case SNMP_VERSION_1:
1533         case SNMP_VERSION_2c:
1534                 ret = asn1_octet_string_decode (&asn1, &community, 
1535                     &community_length, &length);
1536                 if (ret != ASN1_ERR_NOERROR) {
1537                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1538                             "community", ret);
1539                         return;
1540                 }
1541                 if (tree) {
1542                         proto_tree_add_text(snmp_tree, tvb, offset, length,
1543                             "Community: %.*s", community_length,
1544                             SAFE_STRING(community));
1545                 }
1546                 g_free(community);
1547                 offset += length;
1548                 break;
1549         case SNMP_VERSION_2u:
1550                 ret = asn1_octet_string_decode (&asn1, &community, 
1551                     &community_length, &length);
1552                 if (tree) {
1553                         dissect_snmp2u_parameters(snmp_tree, tvb, offset, length,
1554                             community, community_length);
1555                 }
1556                 g_free(community);
1557                 offset += length;
1558                 break;
1559         case SNMP_VERSION_3:
1560                 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1561                 if (ret != ASN1_ERR_NOERROR) {
1562                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1563                                 "message global header", ret);
1564                         return;
1565                 }
1566                 if (snmp_tree) {
1567                         item = proto_tree_add_text(snmp_tree, tvb, offset,
1568                             global_length + length, "Message Global Header");
1569                         global_tree = proto_item_add_subtree(item, ett_global);
1570                         proto_tree_add_text(global_tree, tvb, offset,
1571                             length,
1572                             "Message Global Header Length: %d", global_length);
1573                 }
1574                 offset += length;
1575                 ret = asn1_uint32_decode (&asn1, &msgid, &length);
1576                 if (ret != ASN1_ERR_NOERROR) {
1577                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1578                             "message id", ret);
1579                         return;
1580                 }
1581                 if (global_tree) {
1582                         proto_tree_add_text(global_tree, tvb, offset,
1583                             length, "Message ID: %d", msgid);
1584                 }
1585                 offset += length;
1586                 ret = asn1_uint32_decode (&asn1, &msgmax, &length);
1587                 if (ret != ASN1_ERR_NOERROR) {
1588                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1589                             "message max size", ret);
1590                         return;
1591                 }
1592                 if (global_tree) {
1593                         proto_tree_add_text(global_tree, tvb, offset,
1594                             length, "Message Max Size: %d", msgmax);
1595                 }
1596                 offset += length;
1597                 ret = asn1_octet_string_decode (&asn1, &msgflags, 
1598                     &msgflags_length, &length);
1599                 if (ret != ASN1_ERR_NOERROR) {
1600                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1601                             "message flags", ret);
1602                         return;
1603                 }
1604                 if (msgflags_length != 1) {
1605                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1606                             "message flags wrong length", ret);
1607                         g_free(msgflags);
1608                         return;
1609                 }
1610                 if (global_tree) {
1611                         item = proto_tree_add_uint_format(global_tree,
1612                             hf_snmpv3_flags, tvb, offset, length,
1613                             msgflags[0], "Flags: 0x%02x", msgflags[0]);
1614                         flags_tree = proto_item_add_subtree(item, ett_flags);
1615                         proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_report,
1616                             tvb, offset, length, msgflags[0]);
1617                         proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
1618                             tvb, offset, length, msgflags[0]);
1619                         proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
1620                             tvb, offset, length, msgflags[0]);
1621                 }
1622                 encrypted = msgflags[0] & TH_CRYPT;
1623                 g_free(msgflags);
1624                 offset += length;
1625                 ret = asn1_uint32_decode (&asn1, &msgsec, &length);
1626                 if (ret != ASN1_ERR_NOERROR) {
1627                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1628                             "message security model", ret);
1629                         return;
1630                 }
1631                 if (global_tree) {
1632                         proto_tree_add_text(global_tree, tvb, offset,
1633                             length, "Message Security Model: %s",
1634                             val_to_str(msgsec, sec_models,
1635                             "Unknown model %#x"));
1636                 }
1637                 offset += length;
1638                 switch(msgsec) {
1639                 case SNMP_SEC_USM:
1640                         start = asn1.offset;
1641                         ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1642                             &def, &secparm_length);
1643                         length = asn1.offset - start;
1644                         if (cls != ASN1_UNI && con != ASN1_PRI && 
1645                             tag != ASN1_OTS) {
1646                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1647                                     snmp_tree, "Message Security Parameters",
1648                                     ASN1_ERR_WRONG_TYPE);
1649                                 return;
1650                         }
1651                         if (snmp_tree) {
1652                                 item = proto_tree_add_text(snmp_tree, tvb,
1653                                     offset, secparm_length + length,
1654                                     "Message Security Parameters");
1655                                 secur_tree = proto_item_add_subtree(item,
1656                                     ett_secur);
1657                                 proto_tree_add_text(secur_tree, tvb, offset,
1658                                     length, 
1659                                     "Message Security Parameters Length: %d",
1660                                     secparm_length);
1661                         }
1662                         offset += length;
1663                         ret = asn1_sequence_decode(&asn1, &secparm_length,
1664                             &length);
1665                         if (ret != ASN1_ERR_NOERROR) {
1666                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1667                                     snmp_tree, "USM sequence header", ret);
1668                                 return;
1669                         }
1670                         offset += length;
1671                         ret = asn1_octet_string_decode (&asn1, &aengineid, 
1672                             &aengineid_length, &length);
1673                         if (ret != ASN1_ERR_NOERROR) {
1674                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1675                                     snmp_tree, "authoritative engine id", ret);
1676                                 return;
1677                         }
1678                         if (secur_tree) {
1679                                 proto_tree_add_text(secur_tree, tvb, offset,
1680                                     length, "Authoritative Engine ID: %s",
1681                                     bytes_to_str(aengineid, aengineid_length));
1682                         }
1683                         g_free(aengineid);
1684                         offset += length;
1685                         ret = asn1_uint32_decode (&asn1, &engineboots, &length);
1686                         if (ret != ASN1_ERR_NOERROR) {
1687                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1688                                     snmp_tree, "engine boots", ret);
1689                                 return;
1690                         }
1691                         if (secur_tree) {
1692                                 proto_tree_add_text(secur_tree, tvb,
1693                                     offset, length, "Engine Boots: %d", 
1694                                     engineboots);
1695                         }
1696                         offset += length;
1697                         ret = asn1_uint32_decode (&asn1, &enginetime, &length);
1698                         if (ret != ASN1_ERR_NOERROR) {
1699                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1700                                     snmp_tree,  "engine time", ret);
1701                                 return;
1702                         }
1703                         if (secur_tree) {
1704                                 proto_tree_add_text(secur_tree, tvb,
1705                                     offset, length, "Engine Time: %d", 
1706                                     enginetime);
1707                         }
1708                         offset += length;
1709                         ret = asn1_octet_string_decode (&asn1, &username, 
1710                             &username_length, &length);
1711                         if (ret != ASN1_ERR_NOERROR) {
1712                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1713                                     snmp_tree, "user name", ret);
1714                                 return;
1715                         }
1716                         if (secur_tree) {
1717                                 proto_tree_add_text(secur_tree, tvb, offset,
1718                                     length, "User Name: %.*s", 
1719                                     username_length,
1720                                     SAFE_STRING(username));
1721                         }
1722                         g_free(username);
1723                         offset += length;
1724                         ret = asn1_octet_string_decode (&asn1, &authpar, 
1725                             &authpar_length, &length);
1726                         if (ret != ASN1_ERR_NOERROR) {
1727                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1728                                     snmp_tree, "authentication parameter", ret);
1729                                 return;
1730                         }
1731                         if (secur_tree) {
1732                                 proto_tree_add_text(secur_tree, tvb, offset,
1733                                     length, "Authentication Parameter: %s",
1734                                     bytes_to_str(authpar, authpar_length));
1735                         }
1736                         g_free(authpar);
1737                         offset += length;
1738                         ret = asn1_octet_string_decode (&asn1, &privpar, 
1739                             &privpar_length, &length);
1740                         if (ret != ASN1_ERR_NOERROR) {
1741                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1742                                     snmp_tree, "privacy parameter", ret);
1743                                 return;
1744                         }
1745                         if (secur_tree) {
1746                                 proto_tree_add_text(secur_tree, tvb, offset,
1747                                     length, "Privacy Parameter: %s",
1748                                     bytes_to_str(privpar, privpar_length));
1749                         }
1750                         g_free(privpar);
1751                         offset += length;
1752                         break;
1753                 default:
1754                         ret = asn1_octet_string_decode (&asn1, 
1755                             &secparm, &secparm_length, &length);
1756                         if (ret != ASN1_ERR_NOERROR) {
1757                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1758                                     snmp_tree, "Message Security Parameters",
1759                                     ret);
1760                                 return;
1761                         }
1762                         if (snmp_tree) {
1763                                 proto_tree_add_text(snmp_tree, tvb, offset,
1764                                     length,
1765                                     "Message Security Parameters Data"
1766                                     " (%d bytes)", secparm_length);
1767                         }
1768                         g_free(secparm);
1769                         offset += length;
1770                         break;
1771                 }
1772                 /* PDU starts here */
1773                 if (encrypted) {
1774                         ret = asn1_octet_string_decode (&asn1, &cryptpdu,
1775                             &cryptpdu_length, &length);
1776                         if (ret != ASN1_ERR_NOERROR) {
1777                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1778                                     snmp_tree, "encrypted PDU header", ret);
1779                                 return;
1780                         }
1781                         proto_tree_add_text(snmp_tree, tvb, offset, length,
1782                             "Encrypted PDU (%d bytes)", length);
1783                         g_free(cryptpdu);
1784                         if (check_col(pinfo->cinfo, COL_INFO))
1785                                 col_set_str(pinfo->cinfo, COL_INFO, "Encrypted PDU");
1786                         return;
1787                 }
1788                 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1789                 if (ret != ASN1_ERR_NOERROR) {
1790                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1791                                 "PDU header", ret);
1792                         return;
1793                 }
1794                 offset += length;
1795                 ret = asn1_octet_string_decode (&asn1, &cengineid, 
1796                     &cengineid_length, &length);
1797                 if (ret != ASN1_ERR_NOERROR) {
1798                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1799                             "context engine id", ret);
1800                         return;
1801                 }
1802                 if (snmp_tree) {
1803                         proto_tree_add_text(snmp_tree, tvb, offset, length,
1804                             "Context Engine ID: %s",
1805                             bytes_to_str(cengineid, cengineid_length));
1806                 }
1807                 g_free(cengineid);
1808                 offset += length;
1809                 ret = asn1_octet_string_decode (&asn1, &cname, 
1810                     &cname_length, &length);
1811                 if (ret != ASN1_ERR_NOERROR) {
1812                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1813                             "context name", ret);
1814                         return;
1815                 }
1816                 if (snmp_tree) {
1817                         proto_tree_add_text(snmp_tree, tvb, offset, length,
1818                             "Context Name: %.*s", cname_length,
1819                             SAFE_STRING(cname));
1820                 }
1821                 g_free(cname);
1822                 offset += length;
1823                 break;
1824         default:
1825                 dissect_snmp_error(tvb, offset, pinfo, snmp_tree,
1826                     "PDU for unknown version of SNMP");
1827                 return;
1828         }
1829
1830         start = asn1.offset;
1831         ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1832             &pdu_length);
1833         if (ret != ASN1_ERR_NOERROR) {
1834                 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1835                     "PDU type", ret);
1836                 return;
1837         }
1838         if (cls != ASN1_CTX || con != ASN1_CON) {
1839                 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1840                     "PDU type", ASN1_ERR_WRONG_TYPE);
1841                 return;
1842         }
1843         dissect_common_pdu(tvb, offset, pinfo, snmp_tree, asn1, pdu_type, start);
1844 }
1845
1846 static void
1847 dissect_smux_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1848     proto_tree *tree, int proto, gint ett)
1849 {
1850         ASN1_SCK asn1;
1851         int start;
1852         gboolean def;
1853         guint length;
1854
1855         guint pdu_type;
1856         char *pdu_type_string;
1857         guint pdu_length;
1858
1859         guint32 version;
1860         guint32 cause;
1861         guint32 priority;
1862         guint32 operation;
1863         guint32 commit;
1864
1865         guchar *password;
1866         int password_length;
1867
1868         guchar *application;
1869         int application_length;
1870
1871         subid_t *regid;
1872         guint regid_length;
1873
1874         gchar *oid_string;
1875
1876         proto_tree *smux_tree = NULL;
1877         proto_item *item = NULL;
1878         int ret;
1879         guint cls, con;
1880
1881         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1882                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMUX");
1883
1884         if (tree) {
1885                 item = proto_tree_add_item(tree, proto, tvb, offset, -1, FALSE);
1886                 smux_tree = proto_item_add_subtree(item, ett);
1887         }
1888
1889         /* NOTE: we have to parse the message piece by piece, since the
1890          * capture length may be less than the message length: a 'global'
1891          * parsing is likely to fail.
1892          */
1893         /* parse the SNMP header */
1894         asn1_open(&asn1, tvb, offset);
1895         start = asn1.offset;
1896         ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1897             &pdu_length);
1898         if (ret != ASN1_ERR_NOERROR) {
1899                 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1900                     "PDU type", ret);
1901                 return;
1902         }
1903
1904         /* Dissect SMUX here */
1905         if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) {
1906                 pdu_type_string = val_to_str(pdu_type, smux_types,
1907                     "Unknown PDU type %#x");
1908                 if (check_col(pinfo->cinfo, COL_INFO))
1909                         col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
1910                 length = asn1.offset - start;
1911                 if (tree) {
1912                         proto_tree_add_text(smux_tree, tvb, offset, length,
1913                             "PDU type: %s", pdu_type_string);
1914                 }
1915                 offset += length;
1916                 ret = asn1_uint32_decode (&asn1, &version, &length);
1917                 if (ret != ASN1_ERR_NOERROR) {
1918                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1919                             "version", ret);
1920                         return;
1921                 }
1922                 if (tree) {
1923                         proto_tree_add_text(smux_tree, tvb, offset, length,
1924                             "Version: %d", version);
1925                 }
1926                 offset += length;
1927
1928                 ret = asn1_oid_decode (&asn1, &regid, &regid_length, &length);
1929                 if (ret != ASN1_ERR_NOERROR) {
1930                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1931                             "registration OID", ret);
1932                         return;
1933                 }
1934                 if (tree) {
1935                         oid_string = format_oid(regid, regid_length);
1936                         proto_tree_add_text(smux_tree, tvb, offset, length,
1937                             "Registration: %s", oid_string);
1938                         g_free(oid_string);
1939                 }
1940                 g_free(regid);
1941                 offset += length;
1942
1943                 ret = asn1_octet_string_decode (&asn1, &application, 
1944                     &application_length, &length);
1945                 if (ret != ASN1_ERR_NOERROR) {
1946                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree, 
1947                             "application", ret);
1948                         return;
1949                 }
1950                 if (tree) {
1951                         proto_tree_add_text(smux_tree, tvb, offset, length,
1952                             "Application: %.*s", application_length,
1953                              SAFE_STRING(application));
1954                 }
1955                 g_free(application);
1956                 offset += length;
1957
1958                 ret = asn1_octet_string_decode (&asn1, &password, 
1959                     &password_length, &length);
1960                 if (ret != ASN1_ERR_NOERROR) {
1961                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree, 
1962                             "password", ret);
1963                         return;
1964                 }
1965                 if (tree) {
1966                         proto_tree_add_text(smux_tree, tvb, offset, length,
1967                             "Password: %.*s", password_length,
1968                             SAFE_STRING(password));
1969                 }
1970                 g_free(password);
1971                 offset += length;
1972                 return;
1973         }
1974         if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) {
1975                 pdu_type_string = val_to_str(pdu_type, smux_types,
1976                     "Unknown PDU type %#x");
1977                 if (check_col(pinfo->cinfo, COL_INFO))
1978                         col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
1979                 length = asn1.offset - start;
1980                 if (tree) {
1981                         proto_tree_add_text(smux_tree, tvb, offset, length,
1982                             "PDU type: %s", pdu_type_string);
1983                 }
1984                 offset += length;
1985                 ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
1986                 if (ret != ASN1_ERR_NOERROR) {
1987                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1988                             "cause", ret);
1989                         return;
1990                 }
1991                 if (tree) {
1992                         proto_tree_add_text(smux_tree, tvb, offset,
1993                             pdu_length, "Cause: %s",
1994                             val_to_str(cause, smux_close, 
1995                                 "Unknown cause %#x"));
1996                 }
1997                 offset += pdu_length;
1998                 return;
1999         }
2000         if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) {
2001                 pdu_type_string = val_to_str(pdu_type, smux_types,
2002                     "Unknown PDU type %#x");
2003                 if (check_col(pinfo->cinfo, COL_INFO))
2004                         col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2005                 length = asn1.offset - start;
2006                 if (tree) {
2007                         proto_tree_add_text(smux_tree, tvb, offset, length,
2008                             "PDU type: %s", pdu_type_string);
2009                 }
2010                 offset += length;
2011                 ret = asn1_oid_decode (&asn1, &regid, &regid_length, &length);
2012                 if (ret != ASN1_ERR_NOERROR) {
2013                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2014                             "registration subtree", ret);
2015                         return;
2016                 }
2017                 if (tree) {
2018                         oid_string = format_oid(regid, regid_length);
2019                         proto_tree_add_text(smux_tree, tvb, offset, length,
2020                             "Registration: %s", oid_string);
2021                         g_free(oid_string);
2022                 }
2023                 g_free(regid);
2024                 offset += length;
2025
2026                 ret = asn1_uint32_decode (&asn1, &priority, &length);
2027                 if (ret != ASN1_ERR_NOERROR) {
2028                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2029                             "priority", ret);
2030                         return;
2031                 }
2032                 if (tree) {
2033                         proto_tree_add_text(smux_tree, tvb, offset, length,
2034                             "Priority: %d", priority);
2035                 }
2036                 offset += length;
2037
2038                 ret = asn1_uint32_decode (&asn1, &operation, &length);
2039                 if (ret != ASN1_ERR_NOERROR) {
2040                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2041                             "operation", ret);
2042                         return;
2043                 }
2044                 if (tree) {
2045                         proto_tree_add_text(smux_tree, tvb, offset, length,
2046                             "Operation: %s", 
2047                             val_to_str(operation, smux_rreq, 
2048                                 "Unknown operation %#x"));
2049                 }
2050                 offset += length;
2051                 return;
2052         }
2053         if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) {
2054                 pdu_type_string = val_to_str(pdu_type, smux_types,
2055                     "Unknown PDU type %#x");
2056                 if (check_col(pinfo->cinfo, COL_INFO))
2057                         col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2058                 length = asn1.offset - start;
2059                 if (tree) {
2060                         proto_tree_add_text(smux_tree, tvb, offset, length,
2061                             "PDU type: %s", pdu_type_string);
2062                 }
2063                 offset += length;
2064                 ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
2065                 if (ret != ASN1_ERR_NOERROR) {
2066                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2067                             "priority", ret);
2068                         return;
2069                 }
2070                 if (tree) {
2071                         proto_tree_add_text(smux_tree, tvb, offset,
2072                             pdu_length, "%s",
2073                             val_to_str(priority, smux_prio, 
2074                                 "Priority: %#x"));
2075                 }
2076                 offset += pdu_length;
2077                 return;
2078         }
2079         if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) {
2080                 pdu_type_string = val_to_str(pdu_type, smux_types,
2081                     "Unknown PDU type %#x");
2082                 if (check_col(pinfo->cinfo, COL_INFO))
2083                         col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2084                 length = asn1.offset - start;
2085                 if (tree) {
2086                         proto_tree_add_text(smux_tree, tvb, offset, length,
2087                             "PDU type: %s", pdu_type_string);
2088                 }
2089                 offset += length;
2090                 ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
2091                 if (ret != ASN1_ERR_NOERROR) {
2092                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2093                             "commit", ret);
2094                         return;
2095                 }
2096                 if (tree) {
2097                         proto_tree_add_text(smux_tree, tvb, offset,
2098                             pdu_length, "%s",
2099                             val_to_str(commit, smux_sout, 
2100                                 "Unknown SOUT Value: %#x"));
2101                 }
2102                 offset += pdu_length;
2103                 return;
2104         }
2105         if (cls != ASN1_CTX || con != ASN1_CON) {
2106                 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2107                     "PDU type", ASN1_ERR_WRONG_TYPE);
2108                 return;
2109         }
2110         dissect_common_pdu(tvb, offset, pinfo, smux_tree, asn1, pdu_type, start);
2111 }
2112
2113 static void
2114 dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 
2115 {
2116         conversation_t  *conversation;
2117
2118         /*
2119          * The first SNMP packet goes to the SNMP port; the second one
2120          * may come from some *other* port, but goes back to the same
2121          * IP address and port as the ones from which the first packet
2122          * came; all subsequent packets presumably go between those two
2123          * IP addresses and ports.
2124          *
2125          * If this packet went to the SNMP port, we check to see if
2126          * there's already a conversation with one address/port pair
2127          * matching the source IP address and port of this packet,
2128          * the other address matching the destination IP address of this
2129          * packet, and any destination port.
2130          *
2131          * If not, we create one, with its address 1/port 1 pair being
2132          * the source address/port of this packet, its address 2 being
2133          * the destination address of this packet, and its port 2 being
2134          * wildcarded, and give it the SNMP dissector as a dissector.
2135          */
2136         if (pinfo->destport == UDP_PORT_SNMP) {
2137           conversation = find_conversation(&pinfo->src, &pinfo->dst, PT_UDP,
2138                                            pinfo->srcport, 0, NO_PORT_B);
2139           if (conversation == NULL) {
2140             conversation = conversation_new(&pinfo->src, &pinfo->dst, PT_UDP,
2141                                             pinfo->srcport, 0, NO_PORT2);
2142             conversation_set_dissector(conversation, snmp_handle);
2143           }
2144         }
2145
2146         dissect_snmp_pdu(tvb, 0, pinfo, tree, "SNMP", proto_snmp, ett_snmp);
2147 }
2148
2149 static void
2150 dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 
2151 {
2152         dissect_smux_pdu(tvb, 0, pinfo, tree, proto_smux, ett_smux);
2153 }
2154
2155 void
2156 proto_register_snmp(void)
2157 {
2158 #if defined(HAVE_UCD_SNMP_SNMP_H) && defined(linux)
2159         void *libsnmp_handle;
2160         int (*snmp_set_suffix_only_p)(int);
2161         int (*ds_set_int_p)(int, int, int);
2162 #endif
2163
2164         static hf_register_info hf[] = {
2165                 { &hf_snmpv3_flags,
2166                 { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
2167                     0x0, "", HFILL }},
2168                 { &hf_snmpv3_flags_auth,
2169                 { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8,
2170                     TFS(&flags_set_truth), TH_AUTH, "", HFILL }},
2171                 { &hf_snmpv3_flags_crypt,
2172                 { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8,
2173                     TFS(&flags_set_truth), TH_CRYPT, "", HFILL }},
2174                 { &hf_snmpv3_flags_report,
2175                 { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
2176                     TFS(&flags_set_truth), TH_REPORT, "", HFILL }},
2177         };
2178         static gint *ett[] = {
2179                 &ett_snmp,
2180                 &ett_smux,
2181                 &ett_parameters,
2182                 &ett_parameters_qos,
2183                 &ett_global,
2184                 &ett_flags,
2185                 &ett_secur,
2186         };
2187
2188 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
2189         /* UCD or CMU SNMP */
2190         init_mib();
2191 #ifdef HAVE_UCD_SNMP_SNMP_H
2192 #ifdef linux
2193         /* As per the comment near the beginning of the file, UCD SNMP 4.1.1
2194            changed "snmp_set_suffix_only()" from a function to a macro,
2195            removing "snmp_set_suffix_only()" from the library; this means
2196            that binaries that call "snmp_set_suffix_only()" and
2197            that are linked against shared libraries from earlier versions
2198            of the UCD SNMP library won't run with shared libraries from
2199            4.1.1.
2200
2201            This is a problem on Red Hat Linux, as pre-6.2 releases
2202            came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
2203            Versions of Ethereal built on pre-6.2 releases don't run
2204            on 6.2, and the current Ethereal RPMs are built on pre-6.2
2205            releases, causing problems when users running 6.2 download
2206            them and try to use them.
2207
2208            Building the releases on 6.2 isn't necessarily the answer,
2209            as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
2210            with a second argument not supported by at least some pre-4.1.1
2211            versions of the library - it appears that the 4.0.1 library,
2212            at least, checks for invalid arguments and returns an error
2213            rather than stomping random memory, but that means that you
2214            won't get get OIDs displayed as module-name::sub-OID.
2215
2216            So we use a trick similar to one I've seen mentioned as
2217            used in Windows applications to let you build binaries
2218            that run on many different versions of Windows 9x and
2219            Windows NT, that use features present on later versions
2220            if run on those later versions, but that avoid calling,
2221            when run on older versions, routines not present on those
2222            older versions.
2223
2224            I.e., we load "libsnmp.so.0" with "dlopen()", and call
2225            "dlsym()" to try to find "snmp_set_suffix_only()"; if we
2226            don't find it, we make the appropriate call to
2227            "ds_set_int()" instead.  (We load "libsnmp.so.0" rather
2228            than "libsnmp.so" because, at least on RH 6.2, "libsnmp.so"
2229            exists only if you've loaded the libsnmp development package,
2230            which makes "libsnmp.so" a symlink to "libsnmp.so.0"; we
2231            don't want to force users to install it or to make said
2232            symlink by hand.)
2233
2234            We do this only on Linux, for now, as we've only seen the
2235            problem on Red Hat; it may show up on other OSes that bundle
2236            UCD SNMP, or on OSes where it's not bundled but for which
2237            binary packages are built that link against a shared version
2238            of the UCD SNMP library.  If we run into one of those, we
2239            can do this under those OSes as well, *if* "dlopen()" makes
2240            the run-time linker use the same search rules as it uses when
2241            loading libraries with which the application is linked.
2242
2243            (Perhaps we could use the GLib wrappers for run-time linking,
2244            *if* they're thin enough; however, as this code is currently
2245            used only on Linux, we don't worry about that for now.) */
2246
2247         libsnmp_handle = dlopen("libsnmp.so.0", RTLD_LAZY|RTLD_GLOBAL);
2248         if (libsnmp_handle == NULL) {
2249                 /* We didn't find "libsnmp.so.0".
2250
2251                    This could mean that there is no SNMP shared library
2252                    on this system, in which case we were linked statically,
2253                    in which case whatever call the following line of code
2254                    makes will presumably work, as we have the routine it
2255                    calls wired into our binary.  (If we were linked
2256                    dynamically with "-lsnmp", we would have failed to
2257                    start.)
2258
2259                    It could also mean that there is an SNMP shared library
2260                    on this system, but it's called something other than
2261                    "libsnmp.so.0"; so far, we've seen the problem we're
2262                    working around only on systems where the SNMP shared
2263                    library is called "libsnmp.so.0", so we assume for now
2264                    that systems with shared SNMP libraries named something
2265                    other than "libsnmp.so.0" have an SNMP library that's
2266                    not 4.1.1. */
2267                 snmp_set_suffix_only(2);
2268         } else {
2269                 /* OK, we have it loaded.  Do we have
2270                    "snmp_set_suffix_only()"? */
2271                 snmp_set_suffix_only_p = dlsym(libsnmp_handle,
2272                     "snmp_set_suffix_only");
2273                 if (snmp_set_suffix_only_p != NULL) {
2274                         /* Yes - call it. */
2275                         (*snmp_set_suffix_only_p)(2);
2276                 } else {
2277                         /* No; do we have "ds_set_int()"? */
2278                         ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
2279                         if (ds_set_int_p != NULL) {
2280                                 /* Yes - cal it with DS_LIBRARY_ID,
2281                                    DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
2282                                    arguments.
2283
2284                                    We do *not* use DS_LIBRARY_ID or
2285                                    DS_LIB_PRINT_SUFFIX_ONLY by name, so that
2286                                    we don't require that Ethereal be built
2287                                    with versions of UCD SNMP that include
2288                                    that value; instead, we use their values
2289                                    in UCD SNMP 4.1.1, which are 0 and 4,
2290                                    respectively. */
2291                                 (*ds_set_int_p)(0, 4, 2);
2292                         }
2293                 }
2294                 dlclose(libsnmp_handle);
2295         }
2296 #else /* linux */
2297         snmp_set_suffix_only(2);
2298 #endif /* linux */
2299 #endif /* HAVE_UCD_SNMP_SNMP_H */
2300 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
2301         proto_snmp = proto_register_protocol("Simple Network Management Protocol",
2302             "SNMP", "snmp");
2303         proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2304             "SMUX", "smux");
2305         proto_register_field_array(proto_snmp, hf, array_length(hf));
2306         proto_register_subtree_array(ett, array_length(ett));
2307         snmp_handle = create_dissector_handle(dissect_snmp, proto_snmp);
2308 }
2309
2310 void
2311 proto_reg_handoff_snmp(void)
2312 {
2313         dissector_handle_t smux_handle;
2314
2315         dissector_add("udp.port", UDP_PORT_SNMP, snmp_handle);
2316         dissector_add("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
2317         smux_handle = create_dissector_handle(dissect_smux, proto_smux);
2318         dissector_add("tcp.port", TCP_PORT_SMUX, smux_handle);
2319         dissector_add("ethertype", ETHERTYPE_SNMP, snmp_handle);
2320         dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
2321         dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
2322         data_handle = find_dissector("data");
2323 }