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