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