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