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