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