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