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