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