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