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