2 * Routines for SNMP (simple network management protocol)
3 * Copyright (C) 1998 Didier Jorand
5 * See RFC 1157 for SNMPv1.
7 * See RFCs 1901, 1905, and 1906 for SNMPv2c.
9 * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u.
11 * $Id: packet-snmp.c,v 1.82 2002/03/06 03:52:13 guy Exp $
13 * Ethereal - Network traffic analyzer
14 * By Gerald Combs <gerald@ethereal.com>
15 * Copyright 1998 Gerald Combs
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
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.
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.
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.
46 #ifdef HAVE_SYS_TYPES_H
47 # include <sys/types.h>
50 #ifdef HAVE_NETINET_IN_H
51 # include <netinet/in.h>
54 #define MAX_STRING_LEN 2048 /* TBC */
62 #include <epan/packet.h>
63 #include <epan/strutil.h>
64 #include <epan/conversation.h>
66 #include "packet-ipx.h"
68 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
72 # if defined(HAVE_UCD_SNMP_SNMP_H)
76 # include <ucd-snmp/asn1.h>
77 # include <ucd-snmp/snmp_api.h>
78 # include <ucd-snmp/snmp_impl.h>
79 # include <ucd-snmp/mib.h>
82 * Sigh. UCD SNMP 4.1.1 makes "snmp_set_suffix_only()" a macro
83 * that calls "ds_set_int()" with the first two arguments
84 * being DS_LIBRARY_ID and DS_LIB_PRINT_SUFFIX_ONLY; this means that,
85 * when building with 4.1.1, we need to arrange that
86 * <ucd-snmp/default_store.h> is included, to define those two values
87 * and to declare "ds_int()".
91 * 1) we can't include it on earlier versions (at least not 3.6.2),
92 * as it doesn't exist in those versions;
94 * 2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
95 * as that includes <ucd-snmp/snmp.h>, and that defines a whole
96 * bunch of values that we also define ourselves.
98 * So we only include it if "snmp_set_suffix_only" is defined as
101 # ifdef snmp_set_suffix_only
102 # include <ucd-snmp/default_store.h>
106 * XXX - for now, we assume all versions of UCD SNMP have it.
108 # define HAVE_SPRINT_VALUE
111 * Define values "sprint_value()" expects.
113 # define VALTYPE_INTEGER ASN_INTEGER
114 # define VALTYPE_COUNTER ASN_COUNTER
115 # define VALTYPE_GAUGE ASN_GAUGE
116 # define VALTYPE_TIMETICKS ASN_TIMETICKS
117 # define VALTYPE_STRING ASN_OCTET_STR
118 # define VALTYPE_IPADDR ASN_IPADDRESS
119 # define VALTYPE_OPAQUE ASN_OPAQUE
120 # define VALTYPE_NSAP ASN_NSAP
121 # define VALTYPE_OBJECTID ASN_OBJECT_ID
122 # define VALTYPE_BITSTR ASN_BIT_STR
123 # define VALTYPE_COUNTER64 ASN_COUNTER64
125 # ifdef RED_HAT_MODIFIED_UCD_SNMP
126 # include <ucd-snmp/parse.h>
130 # elif defined(HAVE_SNMP_SNMP_H)
134 # include <snmp/snmp.h>
137 * Some older versions of CMU SNMP may lack these values (e.g., the
138 * "libsnmp3.6" package for Debian, which is based on some old
139 * CMU SNMP, perhaps 1.0); for now, we assume they also lack
143 # define HAVE_SPRINT_VALUE
145 * Define values "sprint_value()" expects.
147 # define VALTYPE_INTEGER SMI_INTEGER
148 # define VALTYPE_COUNTER SMI_COUNTER32
149 # define VALTYPE_GAUGE SMI_GAUGE32
150 # define VALTYPE_TIMETICKS SMI_TIMETICKS
151 # define VALTYPE_STRING SMI_STRING
152 # define VALTYPE_IPADDR SMI_IPADDRESS
153 # define VALTYPE_OPAQUE SMI_OPAQUE
154 # define VALTYPE_NSAP SMI_STRING
155 # define VALTYPE_OBJECTID SMI_OBJID
156 # define VALTYPE_BITSTR ASN_BIT_STR
157 # define VALTYPE_COUNTER64 SMI_COUNTER64
160 * Now undo all the definitions they "helpfully" gave us, so we don't get
161 * complaints about redefining them.
163 * Why, oh why, is there no library that provides code to
167 * 2) translate object IDs into names;
169 * 3) let you find out, for a given object ID, what the type, enum
170 * values, display hint, etc. are;
172 * in a *simple* fashion, without assuming that your code is part of an
173 * SNMP agent or client that wants a pile of definitions of PDU types,
174 * etc.? Is it just that 99 44/100% of the code that uses an SNMP library
175 * *is* part of an agent or client, and really *does* need that stuff,
176 * and *doesn't* need the interfaces we want?
178 # undef SNMP_ERR_NOERROR
179 # undef SNMP_ERR_TOOBIG
180 # undef SNMP_ERR_NOSUCHNAME
181 # undef SNMP_ERR_BADVALUE
182 # undef SNMP_ERR_READONLY
183 # undef SNMP_ERR_NOACCESS
184 # undef SNMP_ERR_WRONGTYPE
185 # undef SNMP_ERR_WRONGLENGTH
186 # undef SNMP_ERR_WRONGENCODING
187 # undef SNMP_ERR_WRONGVALUE
188 # undef SNMP_ERR_NOCREATION
189 # undef SNMP_ERR_INCONSISTENTVALUE
190 # undef SNMP_ERR_RESOURCEUNAVAILABLE
191 # undef SNMP_ERR_COMMITFAILED
192 # undef SNMP_ERR_UNDOFAILED
193 # undef SNMP_ERR_AUTHORIZATIONERROR
194 # undef SNMP_ERR_NOTWRITABLE
195 # undef SNMP_ERR_INCONSISTENTNAME
196 # undef SNMP_TRAP_COLDSTART
197 # undef SNMP_TRAP_WARMSTART
198 # undef SNMP_TRAP_LINKDOWN
199 # undef SNMP_TRAP_LINKUP
200 # undef SNMP_TRAP_EGPNEIGHBORLOSS
201 # undef SNMP_TRAP_ENTERPRISESPECIFIC
207 #include "packet-snmp.h"
209 /* Null string of type "guchar[]". */
210 static const guchar nullstring[] = "";
212 /* Take a pointer that may be null and return a pointer that's not null
213 by turning null pointers into pointers to the above null string. */
214 #define SAFE_STRING(s) (((s) != NULL) ? (s) : nullstring)
216 static int proto_snmp = -1;
217 static int proto_smux = -1;
219 static gint ett_snmp = -1;
220 static gint ett_smux = -1;
221 static gint ett_parameters = -1;
222 static gint ett_parameters_qos = -1;
223 static gint ett_global = -1;
224 static gint ett_flags = -1;
225 static gint ett_secur = -1;
227 static int hf_snmpv3_flags = -1;
228 static int hf_snmpv3_flags_auth = -1;
229 static int hf_snmpv3_flags_crypt = -1;
230 static int hf_snmpv3_flags_report = -1;
232 static dissector_handle_t snmp_handle;
233 static dissector_handle_t data_handle;
236 #define TH_CRYPT 0x02
237 #define TH_REPORT 0x04
239 static const true_false_string flags_set_truth = {
244 #define UDP_PORT_SNMP 161
245 #define UDP_PORT_SNMP_TRAP 162
246 #define TCP_PORT_SMUX 199
248 /* Protocol version numbers */
249 #define SNMP_VERSION_1 0
250 #define SNMP_VERSION_2c 1
251 #define SNMP_VERSION_2u 2
252 #define SNMP_VERSION_3 3
254 static const value_string versions[] = {
255 { SNMP_VERSION_1, "1" },
256 { SNMP_VERSION_2c, "2C" },
257 { SNMP_VERSION_2u, "2U" },
258 { SNMP_VERSION_3, "3" },
263 #define SNMP_MSG_GET 0
264 #define SNMP_MSG_GETNEXT 1
265 #define SNMP_MSG_RESPONSE 2
266 #define SNMP_MSG_SET 3
267 #define SNMP_MSG_TRAP 4
269 #define SNMP_MSG_GETBULK 5
270 #define SNMP_MSG_INFORM 6
271 #define SNMP_MSG_TRAP2 7
272 #define SNMP_MSG_REPORT 8
274 static const value_string pdu_types[] = {
275 { SNMP_MSG_GET, "GET" },
276 { SNMP_MSG_GETNEXT, "GET-NEXT" },
277 { SNMP_MSG_SET, "SET" },
278 { SNMP_MSG_RESPONSE, "RESPONSE" },
279 { SNMP_MSG_TRAP, "TRAP-V1" },
280 { SNMP_MSG_GETBULK, "GETBULK" },
281 { SNMP_MSG_INFORM, "INFORM" },
282 { SNMP_MSG_TRAP2, "TRAP-V2" },
283 { SNMP_MSG_REPORT, "REPORT" },
288 #define SMUX_MSG_OPEN 0
289 #define SMUX_MSG_CLOSE 1
290 #define SMUX_MSG_RREQ 2
291 #define SMUX_MSG_RRSP 3
292 #define SMUX_MSG_SOUT 4
294 static const value_string smux_types[] = {
295 { SMUX_MSG_OPEN, "Open" },
296 { SMUX_MSG_CLOSE, "Close" },
297 { SMUX_MSG_RREQ, "Registration Request" },
298 { SMUX_MSG_RRSP, "Registration Response" },
299 { SMUX_MSG_SOUT, "Commit Or Rollback" },
303 /* SMUX Closing causes */
304 #define SMUX_CLOSE_DOWN 0
305 #define SMUX_CLOSE_VERSION 1
306 #define SMUX_CLOSE_PACKET 2
307 #define SMUX_CLOSE_PROTOCOL 3
308 #define SMUX_CLOSE_INTERNAL 4
309 #define SMUX_CLOSE_NOAUTH 5
311 static const value_string smux_close[] = {
312 { SMUX_CLOSE_DOWN, "Going down" },
313 { SMUX_CLOSE_VERSION, "Unsupported Version" },
314 { SMUX_CLOSE_PACKET, "Packet Format Error" },
315 { SMUX_CLOSE_PROTOCOL, "Protocol Error" },
316 { SMUX_CLOSE_INTERNAL, "Internal Error" },
317 { SMUX_CLOSE_NOAUTH, "Unauthorized" },
321 /* SMUX Request codes */
322 #define SMUX_RREQ_DELETE 0
323 #define SMUX_RREQ_READONLY 1
324 #define SMUX_RREQ_READWRITE 2
326 static const value_string smux_rreq[] = {
327 { SMUX_RREQ_DELETE, "Delete" },
328 { SMUX_RREQ_READONLY, "Read Only" },
329 { SMUX_RREQ_READWRITE, "Read Write" },
333 static const value_string smux_prio[] = {
338 /* SMUX SOut codes */
339 #define SMUX_SOUT_COMMIT 0
340 #define SMUX_SOUT_ROLLBACK 1
342 static const value_string smux_sout[] = {
343 { SMUX_SOUT_COMMIT, "Commit" },
344 { SMUX_SOUT_ROLLBACK, "Rollback" },
348 /* Error status values */
349 #define SNMP_ERR_NOERROR 0
350 #define SNMP_ERR_TOOBIG 1
351 #define SNMP_ERR_NOSUCHNAME 2
352 #define SNMP_ERR_BADVALUE 3
353 #define SNMP_ERR_READONLY 4
354 #define SNMP_ERR_GENERROR 5
356 #define SNMP_ERR_NOACCESS 6
357 #define SNMP_ERR_WRONGTYPE 7
358 #define SNMP_ERR_WRONGLENGTH 8
359 #define SNMP_ERR_WRONGENCODING 9
360 #define SNMP_ERR_WRONGVALUE 10
361 #define SNMP_ERR_NOCREATION 11
362 #define SNMP_ERR_INCONSISTENTVALUE 12
363 #define SNMP_ERR_RESOURCEUNAVAILABLE 13
364 #define SNMP_ERR_COMMITFAILED 14
365 #define SNMP_ERR_UNDOFAILED 15
366 #define SNMP_ERR_AUTHORIZATIONERROR 16
367 #define SNMP_ERR_NOTWRITABLE 17
368 #define SNMP_ERR_INCONSISTENTNAME 18
370 static const value_string error_statuses[] = {
371 { SNMP_ERR_NOERROR, "NO ERROR" },
372 { SNMP_ERR_TOOBIG, "TOOBIG" },
373 { SNMP_ERR_NOSUCHNAME, "NO SUCH NAME" },
374 { SNMP_ERR_BADVALUE, "BAD VALUE" },
375 { SNMP_ERR_READONLY, "READ ONLY" },
376 { SNMP_ERR_GENERROR, "GENERIC ERROR" },
377 { SNMP_ERR_NOACCESS, "NO ACCESS" },
378 { SNMP_ERR_WRONGTYPE, "WRONG TYPE" },
379 { SNMP_ERR_WRONGLENGTH, "WRONG LENGTH" },
380 { SNMP_ERR_WRONGENCODING, "WRONG ENCODING" },
381 { SNMP_ERR_WRONGVALUE, "WRONG VALUE" },
382 { SNMP_ERR_NOCREATION, "NO CREATION" },
383 { SNMP_ERR_INCONSISTENTVALUE, "INCONSISTENT VALUE" },
384 { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
385 { SNMP_ERR_COMMITFAILED, "COMMIT FAILED" },
386 { SNMP_ERR_UNDOFAILED, "UNDO FAILED" },
387 { SNMP_ERR_AUTHORIZATIONERROR, "AUTHORIZATION ERROR" },
388 { SNMP_ERR_NOTWRITABLE, "NOT WRITABLE" },
389 { SNMP_ERR_INCONSISTENTNAME, "INCONSISTENT NAME" },
393 /* General SNMP V1 Traps */
395 #define SNMP_TRAP_COLDSTART 0
396 #define SNMP_TRAP_WARMSTART 1
397 #define SNMP_TRAP_LINKDOWN 2
398 #define SNMP_TRAP_LINKUP 3
399 #define SNMP_TRAP_AUTHFAIL 4
400 #define SNMP_TRAP_EGPNEIGHBORLOSS 5
401 #define SNMP_TRAP_ENTERPRISESPECIFIC 6
403 static const value_string trap_types[] = {
404 { SNMP_TRAP_COLDSTART, "COLD START" },
405 { SNMP_TRAP_WARMSTART, "WARM START" },
406 { SNMP_TRAP_LINKDOWN, "LINK DOWN" },
407 { SNMP_TRAP_LINKUP, "LINK UP" },
408 { SNMP_TRAP_AUTHFAIL, "AUTHENTICATION FAILED" },
409 { SNMP_TRAP_EGPNEIGHBORLOSS, "EGP NEIGHBORLOSS" },
410 { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
414 /* Security Models */
416 #define SNMP_SEC_ANY 0
417 #define SNMP_SEC_V1 1
418 #define SNMP_SEC_V2C 2
419 #define SNMP_SEC_USM 3
421 static const value_string sec_models[] = {
422 { SNMP_SEC_ANY, "Any" },
423 { SNMP_SEC_V1, "V1" },
424 { SNMP_SEC_V2C, "V2C" },
425 { SNMP_SEC_USM, "USM" },
431 #define SNMP_IPA 0 /* IP Address */
432 #define SNMP_CNT 1 /* Counter (Counter32) */
433 #define SNMP_GGE 2 /* Gauge (Gauge32) */
434 #define SNMP_TIT 3 /* TimeTicks */
435 #define SNMP_OPQ 4 /* Opaque */
436 #define SNMP_NSP 5 /* NsapAddress */
437 #define SNMP_C64 6 /* Counter64 */
438 #define SNMP_U32 7 /* Uinteger32 */
447 #define SNMP_INTEGER 1 /* l */
448 #define SNMP_OCTETSTR 2 /* c */
449 #define SNMP_DISPLAYSTR 2 /* c */
450 #define SNMP_OBJECTID 3 /* ul */
451 #define SNMP_IPADDR 4 /* uc */
452 #define SNMP_COUNTER 5 /* ul */
453 #define SNMP_GAUGE 6 /* ul */
454 #define SNMP_TIMETICKS 7 /* ul */
455 #define SNMP_OPAQUE 8 /* c */
457 /* additional SNMPv2 Types */
459 #define SNMP_UINTEGER 5 /* ul */
460 #define SNMP_BITSTR 9 /* uc */
461 #define SNMP_NSAP 10 /* uc */
462 #define SNMP_COUNTER64 11 /* ul */
463 #define SNMP_NOSUCHOBJECT 12
464 #define SNMP_NOSUCHINSTANCE 13
465 #define SNMP_ENDOFMIBVIEW 14
467 typedef struct _SNMP_CNV SNMP_CNV;
477 static SNMP_CNV SnmpCnv [] =
479 {ASN1_UNI, ASN1_NUL, SNMP_NULL, "NULL"},
480 {ASN1_UNI, ASN1_INT, SNMP_INTEGER, "INTEGER"},
481 {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR, "OCTET STRING"},
482 {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID, "OBJECTID"},
483 {ASN1_APL, SNMP_IPA, SNMP_IPADDR, "IPADDR"},
484 {ASN1_APL, SNMP_CNT, SNMP_COUNTER, "COUNTER"}, /* Counter32 */
485 {ASN1_APL, SNMP_GGE, SNMP_GAUGE, "GAUGE"}, /* Gauge32 == Unsigned32 */
486 {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
487 {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE, "OPAQUE"},
489 /* SNMPv2 data types and errors */
491 {ASN1_UNI, ASN1_BTS, SNMP_BITSTR, "BITSTR"},
492 {ASN1_APL, SNMP_C64, SNMP_COUNTER64, "COUNTER64"},
493 {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT, "NOSUCHOBJECT"},
494 {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
495 {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW, "ENDOFMIBVIEW"},
500 * NAME: g_snmp_tag_cls2syntax
501 * SYNOPSIS: gboolean g_snmp_tag_cls2syntax
507 * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
508 * See SnmpCnv for conversion.
509 * RETURNS: name on success, NULL on failure
513 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
518 while (cnv->syntax != -1)
520 if (cnv->tag == tag && cnv->class == cls)
522 *syntax = cnv->syntax;
531 dissect_snmp_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
532 proto_tree *tree, const char *field_name, int ret)
536 errstr = asn1_err_to_str(ret);
538 if (check_col(pinfo->cinfo, COL_INFO)) {
539 col_add_fstr(pinfo->cinfo, COL_INFO,
540 "ERROR: Couldn't parse %s: %s", field_name, errstr);
543 proto_tree_add_text(tree, tvb, offset, 0,
544 "ERROR: Couldn't parse %s: %s", field_name, errstr);
545 call_dissector(data_handle,
546 tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
551 dissect_snmp_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
552 proto_tree *tree, const char *message)
554 if (check_col(pinfo->cinfo, COL_INFO))
555 col_add_str(pinfo->cinfo, COL_INFO, message);
558 proto_tree_add_text(tree, tvb, offset, 0, "%s", message);
559 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
564 format_oid(subid_t *oid, guint oid_length)
572 result_len = oid_length * 22;
573 result = g_malloc(result_len + 1);
575 len = sprintf(buf, "%lu", (unsigned long)oid[0]);
577 for (i = 1; i < oid_length;i++) {
578 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
584 #ifdef HAVE_SPRINT_VALUE
586 check_var_length(guint vb_length, guint required_length)
589 static const char badlen_fmt[] = "Length is %u, should be %u";
591 if (vb_length != required_length) {
592 /* Enough room for the largest "Length is XXX,
593 should be XXX" message - 10 digits for each
595 buf = g_malloc(sizeof badlen_fmt + 10 + 10);
596 sprintf(buf, badlen_fmt, vb_length, required_length);
599 return NULL; /* length is OK */
603 format_var(struct variable_list *variable, subid_t *variable_oid,
604 guint variable_oid_length, gushort vb_type, guint vb_length)
614 /* We don't know how long this will be, but let's guess it
615 fits within 128 characters; that should be enough for an
616 integral value plus some sort of type indication. */
621 /* Length has to be 4 bytes. */
622 buf = check_var_length(vb_length, 4);
624 return buf; /* it's not 4 bytes */
625 /* We don't know how long this will be, but let's guess it
626 fits within 128 characters plus 4 characters per octet. */
627 buf = g_malloc(128 + 4*vb_length);
631 /* Length has to be 8 bytes. */
632 buf = check_var_length(vb_length, 8);
634 return buf; /* it's not 8 bytes */
635 /* We don't know how long this will be, but let's guess it
636 fits within 128 characters plus 4 characters per octet. */
637 buf = g_malloc(128 + 4*vb_length);
644 /* We don't know how long this will be, but let's guess it
645 fits within 128 characters plus 4 characters per octet. */
646 buf = g_malloc(128 + 4*vb_length);
650 /* We don't know how long this will be, but let's guess it
651 fits within 128 characters plus 32 characters per subid
652 (10 digits plus period, or a subid name). */
653 buf = g_malloc(1024 + 32*vb_length);
657 /* Should not happen. */
658 g_assert_not_reached();
663 variable->next_variable = NULL;
664 variable->name = variable_oid;
665 variable->name_length = variable_oid_length;
669 variable->type = VALTYPE_INTEGER;
673 variable->type = VALTYPE_COUNTER;
677 variable->type = VALTYPE_GAUGE;
681 variable->type = VALTYPE_TIMETICKS;
685 variable->type = VALTYPE_STRING;
689 variable->type = VALTYPE_IPADDR;
693 variable->type = VALTYPE_OPAQUE;
697 variable->type = VALTYPE_NSAP;
701 variable->type = VALTYPE_OBJECTID;
702 vb_length *= sizeof (subid_t); /* XXX - necessary? */
706 variable->type = VALTYPE_BITSTR;
710 variable->type = VALTYPE_COUNTER64;
713 variable->val_len = vb_length;
715 # ifdef RED_HAT_MODIFIED_UCD_SNMP
716 sprint_value(binit(NULL, buf, sizeof(buf)), variable_oid,
717 variable_oid_length, variable);
719 sprint_value(buf, variable_oid, variable_oid_length, variable);
726 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
727 guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp,
739 gint32 vb_integer_value;
740 guint32 vb_uinteger_value;
742 guint8 *vb_octet_string;
747 gchar *vb_display_string;
749 #ifdef HAVE_SPRINT_VALUE
750 struct variable_list variable;
751 #if defined(HAVE_UCD_SNMP_SNMP_H)
754 #endif /* HAVE_SPRINT_VALUE */
759 /* parse the type of the object */
760 start = asn1->offset;
761 ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
762 if (ret != ASN1_ERR_NOERROR)
765 return ASN1_ERR_LENGTH_NOT_DEFINITE;
767 /* Convert the class, constructed flag, and tag to a type. */
768 vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
769 if (vb_type_name == NULL) {
772 * Dissect the value as an opaque string of octets.
774 vb_type_name = "unsupported type";
775 vb_type = SNMP_OPAQUE;
778 /* parse the value */
782 ret = asn1_int32_value_decode(asn1, vb_length,
784 if (ret != ASN1_ERR_NOERROR)
786 length = asn1->offset - start;
788 #ifdef HAVE_SPRINT_VALUE
790 #if defined(HAVE_UCD_SNMP_SNMP_H)
791 value = vb_integer_value;
792 variable.val.integer = &value;
793 #elif defined(HAVE_SNMP_SNMP_H)
794 variable.val.integer = &vb_integer_value;
796 vb_display_string = format_var(&variable,
797 variable_oid, variable_oid_length, vb_type,
799 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
801 "Value: %s", vb_display_string);
802 g_free(vb_display_string);
803 break; /* we added formatted version to the tree */
805 #endif /* HAVE_SPRINT_VALUE */
806 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
807 "Value: %s: %d (%#x)", vb_type_name,
808 vb_integer_value, vb_integer_value);
815 ret = asn1_uint32_value_decode(asn1, vb_length,
817 if (ret != ASN1_ERR_NOERROR)
819 length = asn1->offset - start;
821 #ifdef HAVE_SPRINT_VALUE
823 #if defined(HAVE_UCD_SNMP_SNMP_H)
824 value = vb_uinteger_value;
825 variable.val.integer = &value;
826 #elif defined(HAVE_SNMP_SNMP_H)
827 variable.val.integer = &vb_uinteger_value;
829 vb_display_string = format_var(&variable,
830 variable_oid, variable_oid_length, vb_type,
832 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
834 "Value: %s", vb_display_string);
835 g_free(vb_display_string);
836 break; /* we added formatted version to the tree */
838 #endif /* HAVE_SPRINT_VALUE */
839 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
840 "Value: %s: %u (%#x)", vb_type_name,
841 vb_uinteger_value, vb_uinteger_value);
851 ret = asn1_string_value_decode (asn1, vb_length,
853 if (ret != ASN1_ERR_NOERROR)
855 length = asn1->offset - start;
857 #ifdef HAVE_SPRINT_VALUE
859 variable.val.string = vb_octet_string;
860 vb_display_string = format_var(&variable,
861 variable_oid, variable_oid_length, vb_type,
863 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
865 "Value: %s", vb_display_string);
866 g_free(vb_display_string);
867 break; /* we added formatted version to the tree */
869 #endif /* HAVE_SPRINT_VALUE */
871 * If some characters are not printable, display
872 * the string as bytes.
874 for (i = 0; i < vb_length; i++) {
875 if (!(isprint(vb_octet_string[i])
876 || isspace(vb_octet_string[i])))
881 * We stopped, due to a non-printable
882 * character, before we got to the end
885 vb_display_string = g_malloc(4*vb_length);
886 buf = &vb_display_string[0];
887 len = sprintf(buf, "%03u", vb_octet_string[0]);
889 for (i = 1; i < vb_length; i++) {
890 len = sprintf(buf, ".%03u",
894 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
895 "Value: %s: %s", vb_type_name,
897 g_free(vb_display_string);
899 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
900 "Value: %s: %.*s", vb_type_name,
902 SAFE_STRING(vb_octet_string));
905 g_free(vb_octet_string);
909 ret = asn1_null_decode (asn1, vb_length);
910 if (ret != ASN1_ERR_NOERROR)
912 length = asn1->offset - start;
914 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
915 "Value: %s", vb_type_name);
920 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
922 if (ret != ASN1_ERR_NOERROR)
924 length = asn1->offset - start;
926 #ifdef HAVE_SPRINT_VALUE
928 variable.val.objid = vb_oid;
929 vb_display_string = format_var(&variable,
930 variable_oid, variable_oid_length, vb_type,
932 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
934 "Value: %s", vb_display_string);
935 break; /* we added formatted version to the tree */
937 #endif /* HAVE_SPRINT_VALUE */
938 vb_display_string = format_oid(vb_oid, vb_oid_length);
939 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
940 "Value: %s: %s", vb_type_name, vb_display_string);
941 g_free(vb_display_string);
946 case SNMP_NOSUCHOBJECT:
947 length = asn1->offset - start;
949 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
950 "Value: %s: no such object", vb_type_name);
954 case SNMP_NOSUCHINSTANCE:
955 length = asn1->offset - start;
957 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
958 "Value: %s: no such instance", vb_type_name);
962 case SNMP_ENDOFMIBVIEW:
963 length = asn1->offset - start;
965 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
966 "Value: %s: end of mib view", vb_type_name);
971 g_assert_not_reached();
972 return ASN1_ERR_WRONG_TYPE;
975 return ASN1_ERR_NOERROR;
979 dissect_common_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
980 proto_tree *tree, ASN1_SCK asn1, guint pdu_type, int start)
984 guint sequence_length;
988 guint32 error_status;
992 char *pdu_type_string;
995 guint enterprise_length;
997 guint8 *agent_address;
998 guint agent_address_length;
1002 guint32 specific_type;
1005 guint timestamp_length;
1009 guint variable_bindings_length;
1012 guint variable_length;
1013 subid_t *variable_oid;
1014 guint variable_oid_length;
1015 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1016 gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
1021 guint cls, con, tag;
1023 pdu_type_string = val_to_str(pdu_type, pdu_types,
1024 "Unknown PDU type %#x");
1025 if (check_col(pinfo->cinfo, COL_INFO))
1026 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
1027 length = asn1.offset - start;
1029 proto_tree_add_text(tree, tvb, offset, length,
1030 "PDU type: %s", pdu_type_string);
1034 /* get the fields in the PDU preceeding the variable-bindings sequence */
1038 case SNMP_MSG_GETNEXT:
1039 case SNMP_MSG_RESPONSE:
1041 case SNMP_MSG_GETBULK:
1042 case SNMP_MSG_INFORM:
1043 case SNMP_MSG_TRAP2:
1044 case SNMP_MSG_REPORT:
1046 ret = asn1_uint32_decode (&asn1, &request_id, &length);
1047 if (ret != ASN1_ERR_NOERROR) {
1048 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1053 proto_tree_add_text(tree, tvb, offset, length,
1054 "Request Id: %#x", request_id);
1058 /* error status, or getbulk non-repeaters */
1059 ret = asn1_uint32_decode (&asn1, &error_status, &length);
1060 if (ret != ASN1_ERR_NOERROR) {
1061 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1062 (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
1068 if (pdu_type == SNMP_MSG_GETBULK) {
1069 proto_tree_add_text(tree, tvb, offset,
1070 length, "Non-repeaters: %u", error_status);
1072 proto_tree_add_text(tree, tvb, offset,
1073 length, "Error Status: %s",
1074 val_to_str(error_status, error_statuses,
1080 /* error index, or getbulk max-repetitions */
1081 ret = asn1_uint32_decode (&asn1, &error_index, &length);
1082 if (ret != ASN1_ERR_NOERROR) {
1083 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1084 (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
1090 if (pdu_type == SNMP_MSG_GETBULK) {
1091 proto_tree_add_text(tree, tvb, offset,
1092 length, "Max repetitions: %u", error_index);
1094 proto_tree_add_text(tree, tvb, offset,
1095 length, "Error Index: %u", error_index);
1103 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
1105 if (ret != ASN1_ERR_NOERROR) {
1106 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1107 "enterprise OID", ret);
1111 oid_string = format_oid(enterprise, enterprise_length);
1112 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1113 # ifdef RED_HAT_MODIFIED_UCD_SNMP
1114 sprint_objid(binit(NULL, vb_oid_string, sizeof(vb_oid_string)),
1115 enterprise, enterprise_length);
1117 sprint_objid(vb_oid_string, enterprise,
1120 proto_tree_add_text(tree, tvb, offset, length,
1121 "Enterprise: %s (%s)", oid_string, vb_oid_string);
1122 #else /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1123 proto_tree_add_text(tree, tvb, offset, length,
1124 "Enterprise: %s", oid_string);
1125 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1132 start = asn1.offset;
1133 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1134 &def, &agent_address_length);
1135 if (ret != ASN1_ERR_NOERROR) {
1136 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1137 "agent address", ret);
1140 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
1141 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
1142 /* GXSNMP 0.0.15 says the latter is "needed for
1144 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1145 "agent_address", ASN1_ERR_WRONG_TYPE);
1148 if (agent_address_length != 4) {
1149 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1150 "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
1153 ret = asn1_string_value_decode (&asn1,
1154 agent_address_length, &agent_address);
1155 if (ret != ASN1_ERR_NOERROR) {
1156 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1157 "agent address", ret);
1160 length = asn1.offset - start;
1162 if (agent_address_length != 4) {
1163 proto_tree_add_text(tree, tvb, offset,
1165 "Agent address: <length is %u, not 4>",
1166 agent_address_length);
1168 proto_tree_add_text(tree, tvb, offset,
1170 "Agent address: %s",
1171 ip_to_str(agent_address));
1174 g_free(agent_address);
1177 /* generic trap type */
1178 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1179 if (ret != ASN1_ERR_NOERROR) {
1180 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1181 "generic trap type", ret);
1185 proto_tree_add_text(tree, tvb, offset, length,
1187 val_to_str(trap_type, trap_types, "Unknown (%u)"));
1191 /* specific trap type */
1192 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1193 if (ret != ASN1_ERR_NOERROR) {
1194 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1195 "specific trap type", ret);
1199 proto_tree_add_text(tree, tvb, offset, length,
1200 "Specific trap type: %u (%#x)",
1201 specific_type, specific_type);
1206 start = asn1.offset;
1207 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1208 &def, ×tamp_length);
1209 if (ret != ASN1_ERR_NOERROR) {
1210 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1214 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1215 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1216 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1217 "timestamp", ASN1_ERR_WRONG_TYPE);
1220 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1222 if (ret != ASN1_ERR_NOERROR) {
1223 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1227 length = asn1.offset - start;
1229 proto_tree_add_text(tree, tvb, offset, length,
1230 "Timestamp: %u", timestamp);
1236 /* variable bindings */
1237 /* get header for variable-bindings sequence */
1238 ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1239 if (ret != ASN1_ERR_NOERROR) {
1240 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1241 "variable bindings header", ret);
1246 /* loop on variable bindings */
1248 while (variable_bindings_length > 0) {
1250 sequence_length = 0;
1253 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1254 if (ret != ASN1_ERR_NOERROR) {
1255 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1256 "variable binding header", ret);
1259 sequence_length += length;
1261 /* parse object identifier */
1262 ret = asn1_oid_decode (&asn1, &variable_oid,
1263 &variable_oid_length, &length);
1264 if (ret != ASN1_ERR_NOERROR) {
1265 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1266 "variable binding OID", ret);
1269 sequence_length += length;
1273 oid_string = format_oid(variable_oid,
1274 variable_oid_length);
1276 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1277 # ifdef RED_HAT_MODIFIED_UCD_SNMP
1278 sprint_objid(binit(NULL, vb_oid_string, sizeof(vb_oid_string)),
1279 variable_oid, variable_oid_length);
1281 sprint_objid(vb_oid_string, variable_oid,
1282 variable_oid_length);
1284 proto_tree_add_text(tree, tvb, offset, sequence_length,
1285 "Object identifier %d: %s (%s)", vb_index,
1286 oid_string, vb_oid_string);
1287 #ifdef HAVE_SNMP_SNMP_H
1289 * CMU SNMP has a bug wherein "sprint_value()"
1290 * calls "get_symbol()", passing it the
1291 * OID supplied, to get an information about the
1292 * variable, and blithely assumes that it will
1293 * never get a null pointer back and dereferences
1294 * the resulting pointer.
1296 * Not true. If there's nothing in the MIB
1297 * about *any* of the components of the OID,
1298 * it'll return a null pointer.
1300 * So we have to check for that, and pass
1301 * down to "snmp_variable_decode" a flag
1302 * saying "don't pass this to 'sprint_value()'.
1304 * We check for that by looking for a decoded
1305 * OID string beginning with "." followed by a
1306 * digit, meaning it couldn't even find any
1307 * symbolic representation for the very
1308 * beginning of the OID string.
1310 if (vb_oid_string[0] == '.' &&
1311 isdigit((guchar)vb_oid_string[1]))
1313 #endif /* HAVE_SNMP_SNMP_H */
1314 #else /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1315 proto_tree_add_text(tree, tvb, offset, sequence_length,
1316 "Object identifier %d: %s", vb_index,
1318 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1321 offset += sequence_length;
1322 variable_bindings_length -= sequence_length;
1324 /* Parse the variable's value */
1325 ret = snmp_variable_decode(tree, variable_oid,
1326 variable_oid_length, &asn1, offset, &length,
1328 if (ret != ASN1_ERR_NOERROR) {
1329 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1334 variable_bindings_length -= length;
1338 static const value_string qos_vals[] = {
1339 { 0x0, "No authentication or privacy" },
1340 { 0x1, "Authentication, no privacy" },
1341 { 0x2, "Authentication and privacy" },
1342 { 0x3, "Authentication and privacy" },
1347 dissect_snmp2u_parameters(proto_tree *tree, tvbuff_t *tvb, int offset, int length,
1348 guchar *parameters, int parameters_length)
1351 proto_tree *parameters_tree;
1352 proto_tree *qos_tree;
1357 item = proto_tree_add_text(tree, tvb, offset, length,
1359 parameters_tree = proto_item_add_subtree(item, ett_parameters);
1360 offset += length - parameters_length;
1362 if (parameters_length < 1)
1364 model = *parameters;
1365 proto_tree_add_text(parameters_tree, tvb, offset, 1,
1366 "model: %u", model);
1369 parameters_length -= 1;
1371 /* Unknown model. */
1372 proto_tree_add_text(parameters_tree, tvb, offset,
1373 parameters_length, "parameters: %s",
1374 bytes_to_str(parameters, parameters_length));
1378 if (parameters_length < 1)
1381 item = proto_tree_add_text(parameters_tree, tvb, offset, 1,
1383 qos_tree = proto_item_add_subtree(item, ett_parameters_qos);
1384 proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
1385 decode_boolean_bitfield(qos, 0x04,
1386 8, "Generation of report PDU allowed",
1387 "Generation of report PDU not allowed"));
1388 proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
1389 decode_enumerated_bitfield(qos, 0x03,
1390 8, qos_vals, "%s"));
1393 parameters_length -= 1;
1395 if (parameters_length < 12)
1397 proto_tree_add_text(parameters_tree, tvb, offset, 12,
1398 "agentID: %s", bytes_to_str(parameters, 12));
1401 parameters_length -= 12;
1403 if (parameters_length < 4)
1405 proto_tree_add_text(parameters_tree, tvb, offset, 4,
1406 "agentBoots: %u", pntohl(parameters));
1409 parameters_length -= 4;
1411 if (parameters_length < 4)
1413 proto_tree_add_text(parameters_tree, tvb, offset, 4,
1414 "agentTime: %u", pntohl(parameters));
1417 parameters_length -= 4;
1419 if (parameters_length < 2)
1421 proto_tree_add_text(parameters_tree, tvb, offset, 2,
1422 "maxSize: %u", pntohs(parameters));
1425 parameters_length -= 2;
1427 if (parameters_length < 1)
1430 proto_tree_add_text(parameters_tree, tvb, offset, 1,
1431 "userLen: %u", len);
1434 parameters_length -= 1;
1436 if (parameters_length < len)
1438 proto_tree_add_text(parameters_tree, tvb, offset, len,
1439 "userName: %.*s", len, parameters);
1442 parameters_length -= len;
1444 if (parameters_length < 1)
1447 proto_tree_add_text(parameters_tree, tvb, offset, 1,
1448 "authLen: %u", len);
1451 parameters_length -= 1;
1453 if (parameters_length < len)
1455 proto_tree_add_text(parameters_tree, tvb, offset, len,
1456 "authDigest: %s", bytes_to_str(parameters, len));
1459 parameters_length -= len;
1461 if (parameters_length < 1)
1463 proto_tree_add_text(parameters_tree, tvb, offset, parameters_length,
1464 "contextSelector: %s", bytes_to_str(parameters, parameters_length));
1468 dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1469 proto_tree *tree, char *proto_name, int proto, gint ett)
1476 guint message_length;
1477 guint global_length;
1483 guint32 engineboots;
1496 int msgflags_length;
1497 int community_length;
1499 int cengineid_length;
1501 int cryptpdu_length;
1502 int aengineid_length;
1503 int username_length;
1510 proto_tree *snmp_tree = NULL;
1511 proto_tree *global_tree = NULL;
1512 proto_tree *flags_tree = NULL;
1513 proto_tree *secur_tree = NULL;
1514 proto_item *item = NULL;
1516 guint cls, con, tag;
1518 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1519 col_add_str(pinfo->cinfo, COL_PROTOCOL, proto_name);
1522 item = proto_tree_add_item(tree, proto, tvb, offset, -1, FALSE);
1523 snmp_tree = proto_item_add_subtree(item, ett);
1526 /* NOTE: we have to parse the message piece by piece, since the
1527 * capture length may be less than the message length: a 'global'
1528 * parsing is likely to fail.
1530 /* parse the SNMP header */
1531 asn1_open(&asn1, tvb, offset);
1532 ret = asn1_sequence_decode(&asn1, &message_length, &length);
1533 if (ret != ASN1_ERR_NOERROR) {
1534 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1535 "message header", ret);
1540 ret = asn1_uint32_decode (&asn1, &version, &length);
1541 if (ret != ASN1_ERR_NOERROR) {
1542 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1543 "version number", ret);
1547 proto_tree_add_text(snmp_tree, tvb, offset, length,
1549 val_to_str(version, versions, "Unknown version %#x"));
1555 case SNMP_VERSION_1:
1556 case SNMP_VERSION_2c:
1557 ret = asn1_octet_string_decode (&asn1, &community,
1558 &community_length, &length);
1559 if (ret != ASN1_ERR_NOERROR) {
1560 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1565 proto_tree_add_text(snmp_tree, tvb, offset, length,
1566 "Community: %.*s", community_length,
1567 SAFE_STRING(community));
1572 case SNMP_VERSION_2u:
1573 ret = asn1_octet_string_decode (&asn1, &community,
1574 &community_length, &length);
1576 dissect_snmp2u_parameters(snmp_tree, tvb, offset, length,
1577 community, community_length);
1582 case SNMP_VERSION_3:
1583 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1584 if (ret != ASN1_ERR_NOERROR) {
1585 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1586 "message global header", ret);
1590 item = proto_tree_add_text(snmp_tree, tvb, offset,
1591 global_length + length, "Message Global Header");
1592 global_tree = proto_item_add_subtree(item, ett_global);
1593 proto_tree_add_text(global_tree, tvb, offset,
1595 "Message Global Header Length: %d", global_length);
1598 ret = asn1_uint32_decode (&asn1, &msgid, &length);
1599 if (ret != ASN1_ERR_NOERROR) {
1600 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1605 proto_tree_add_text(global_tree, tvb, offset,
1606 length, "Message ID: %d", msgid);
1609 ret = asn1_uint32_decode (&asn1, &msgmax, &length);
1610 if (ret != ASN1_ERR_NOERROR) {
1611 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1612 "message max size", ret);
1616 proto_tree_add_text(global_tree, tvb, offset,
1617 length, "Message Max Size: %d", msgmax);
1620 ret = asn1_octet_string_decode (&asn1, &msgflags,
1621 &msgflags_length, &length);
1622 if (ret != ASN1_ERR_NOERROR) {
1623 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1624 "message flags", ret);
1627 if (msgflags_length != 1) {
1628 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1629 "message flags wrong length", ret);
1634 item = proto_tree_add_uint_format(global_tree,
1635 hf_snmpv3_flags, tvb, offset, length,
1636 msgflags[0], "Flags: 0x%02x", msgflags[0]);
1637 flags_tree = proto_item_add_subtree(item, ett_flags);
1638 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_report,
1639 tvb, offset, length, msgflags[0]);
1640 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
1641 tvb, offset, length, msgflags[0]);
1642 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
1643 tvb, offset, length, msgflags[0]);
1645 encrypted = msgflags[0] & TH_CRYPT;
1648 ret = asn1_uint32_decode (&asn1, &msgsec, &length);
1649 if (ret != ASN1_ERR_NOERROR) {
1650 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1651 "message security model", ret);
1655 proto_tree_add_text(global_tree, tvb, offset,
1656 length, "Message Security Model: %s",
1657 val_to_str(msgsec, sec_models,
1658 "Unknown model %#x"));
1663 start = asn1.offset;
1664 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1665 &def, &secparm_length);
1666 length = asn1.offset - start;
1667 if (cls != ASN1_UNI && con != ASN1_PRI &&
1669 dissect_snmp_parse_error(tvb, offset, pinfo,
1670 snmp_tree, "Message Security Parameters",
1671 ASN1_ERR_WRONG_TYPE);
1675 item = proto_tree_add_text(snmp_tree, tvb,
1676 offset, secparm_length + length,
1677 "Message Security Parameters");
1678 secur_tree = proto_item_add_subtree(item,
1680 proto_tree_add_text(secur_tree, tvb, offset,
1682 "Message Security Parameters Length: %d",
1686 ret = asn1_sequence_decode(&asn1, &secparm_length,
1688 if (ret != ASN1_ERR_NOERROR) {
1689 dissect_snmp_parse_error(tvb, offset, pinfo,
1690 snmp_tree, "USM sequence header", ret);
1694 ret = asn1_octet_string_decode (&asn1, &aengineid,
1695 &aengineid_length, &length);
1696 if (ret != ASN1_ERR_NOERROR) {
1697 dissect_snmp_parse_error(tvb, offset, pinfo,
1698 snmp_tree, "authoritative engine id", ret);
1702 proto_tree_add_text(secur_tree, tvb, offset,
1703 length, "Authoritative Engine ID: %s",
1704 bytes_to_str(aengineid, aengineid_length));
1708 ret = asn1_uint32_decode (&asn1, &engineboots, &length);
1709 if (ret != ASN1_ERR_NOERROR) {
1710 dissect_snmp_parse_error(tvb, offset, pinfo,
1711 snmp_tree, "engine boots", ret);
1715 proto_tree_add_text(secur_tree, tvb,
1716 offset, length, "Engine Boots: %d",
1720 ret = asn1_uint32_decode (&asn1, &enginetime, &length);
1721 if (ret != ASN1_ERR_NOERROR) {
1722 dissect_snmp_parse_error(tvb, offset, pinfo,
1723 snmp_tree, "engine time", ret);
1727 proto_tree_add_text(secur_tree, tvb,
1728 offset, length, "Engine Time: %d",
1732 ret = asn1_octet_string_decode (&asn1, &username,
1733 &username_length, &length);
1734 if (ret != ASN1_ERR_NOERROR) {
1735 dissect_snmp_parse_error(tvb, offset, pinfo,
1736 snmp_tree, "user name", ret);
1740 proto_tree_add_text(secur_tree, tvb, offset,
1741 length, "User Name: %.*s",
1743 SAFE_STRING(username));
1747 ret = asn1_octet_string_decode (&asn1, &authpar,
1748 &authpar_length, &length);
1749 if (ret != ASN1_ERR_NOERROR) {
1750 dissect_snmp_parse_error(tvb, offset, pinfo,
1751 snmp_tree, "authentication parameter", ret);
1755 proto_tree_add_text(secur_tree, tvb, offset,
1756 length, "Authentication Parameter: %s",
1757 bytes_to_str(authpar, authpar_length));
1761 ret = asn1_octet_string_decode (&asn1, &privpar,
1762 &privpar_length, &length);
1763 if (ret != ASN1_ERR_NOERROR) {
1764 dissect_snmp_parse_error(tvb, offset, pinfo,
1765 snmp_tree, "privacy parameter", ret);
1769 proto_tree_add_text(secur_tree, tvb, offset,
1770 length, "Privacy Parameter: %s",
1771 bytes_to_str(privpar, privpar_length));
1777 ret = asn1_octet_string_decode (&asn1,
1778 &secparm, &secparm_length, &length);
1779 if (ret != ASN1_ERR_NOERROR) {
1780 dissect_snmp_parse_error(tvb, offset, pinfo,
1781 snmp_tree, "Message Security Parameters",
1786 proto_tree_add_text(snmp_tree, tvb, offset,
1788 "Message Security Parameters Data"
1789 " (%d bytes)", secparm_length);
1795 /* PDU starts here */
1797 ret = asn1_octet_string_decode (&asn1, &cryptpdu,
1798 &cryptpdu_length, &length);
1799 if (ret != ASN1_ERR_NOERROR) {
1800 dissect_snmp_parse_error(tvb, offset, pinfo,
1801 snmp_tree, "encrypted PDU header", ret);
1804 proto_tree_add_text(snmp_tree, tvb, offset, length,
1805 "Encrypted PDU (%d bytes)", length);
1807 if (check_col(pinfo->cinfo, COL_INFO))
1808 col_set_str(pinfo->cinfo, COL_INFO, "Encrypted PDU");
1811 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1812 if (ret != ASN1_ERR_NOERROR) {
1813 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1818 ret = asn1_octet_string_decode (&asn1, &cengineid,
1819 &cengineid_length, &length);
1820 if (ret != ASN1_ERR_NOERROR) {
1821 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1822 "context engine id", ret);
1826 proto_tree_add_text(snmp_tree, tvb, offset, length,
1827 "Context Engine ID: %s",
1828 bytes_to_str(cengineid, cengineid_length));
1832 ret = asn1_octet_string_decode (&asn1, &cname,
1833 &cname_length, &length);
1834 if (ret != ASN1_ERR_NOERROR) {
1835 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1836 "context name", ret);
1840 proto_tree_add_text(snmp_tree, tvb, offset, length,
1841 "Context Name: %.*s", cname_length,
1842 SAFE_STRING(cname));
1848 dissect_snmp_error(tvb, offset, pinfo, snmp_tree,
1849 "PDU for unknown version of SNMP");
1853 start = asn1.offset;
1854 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1856 if (ret != ASN1_ERR_NOERROR) {
1857 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1861 if (cls != ASN1_CTX || con != ASN1_CON) {
1862 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1863 "PDU type", ASN1_ERR_WRONG_TYPE);
1866 dissect_common_pdu(tvb, offset, pinfo, snmp_tree, asn1, pdu_type, start);
1870 dissect_smux_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1871 proto_tree *tree, int proto, gint ett)
1879 char *pdu_type_string;
1889 int password_length;
1891 guchar *application;
1892 int application_length;
1899 proto_tree *smux_tree = NULL;
1900 proto_item *item = NULL;
1904 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1905 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMUX");
1908 item = proto_tree_add_item(tree, proto, tvb, offset, -1, FALSE);
1909 smux_tree = proto_item_add_subtree(item, ett);
1912 /* NOTE: we have to parse the message piece by piece, since the
1913 * capture length may be less than the message length: a 'global'
1914 * parsing is likely to fail.
1916 /* parse the SNMP header */
1917 asn1_open(&asn1, tvb, offset);
1918 start = asn1.offset;
1919 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1921 if (ret != ASN1_ERR_NOERROR) {
1922 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1927 /* Dissect SMUX here */
1928 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) {
1929 pdu_type_string = val_to_str(pdu_type, smux_types,
1930 "Unknown PDU type %#x");
1931 if (check_col(pinfo->cinfo, COL_INFO))
1932 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
1933 length = asn1.offset - start;
1935 proto_tree_add_text(smux_tree, tvb, offset, length,
1936 "PDU type: %s", pdu_type_string);
1939 ret = asn1_uint32_decode (&asn1, &version, &length);
1940 if (ret != ASN1_ERR_NOERROR) {
1941 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1946 proto_tree_add_text(smux_tree, tvb, offset, length,
1947 "Version: %d", version);
1951 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
1952 if (ret != ASN1_ERR_NOERROR) {
1953 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1954 "registration OID", ret);
1958 oid_string = format_oid(regid, regid_length);
1959 proto_tree_add_text(smux_tree, tvb, offset, length,
1960 "Registration: %s", oid_string);
1966 ret = asn1_octet_string_decode (&asn1, &application,
1967 &application_length, &length);
1968 if (ret != ASN1_ERR_NOERROR) {
1969 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1970 "application", ret);
1974 proto_tree_add_text(smux_tree, tvb, offset, length,
1975 "Application: %.*s", application_length,
1976 SAFE_STRING(application));
1978 g_free(application);
1981 ret = asn1_octet_string_decode (&asn1, &password,
1982 &password_length, &length);
1983 if (ret != ASN1_ERR_NOERROR) {
1984 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1989 proto_tree_add_text(smux_tree, tvb, offset, length,
1990 "Password: %.*s", password_length,
1991 SAFE_STRING(password));
1997 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) {
1998 pdu_type_string = val_to_str(pdu_type, smux_types,
1999 "Unknown PDU type %#x");
2000 if (check_col(pinfo->cinfo, COL_INFO))
2001 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2002 length = asn1.offset - start;
2004 proto_tree_add_text(smux_tree, tvb, offset, length,
2005 "PDU type: %s", pdu_type_string);
2008 ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
2009 if (ret != ASN1_ERR_NOERROR) {
2010 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2015 proto_tree_add_text(smux_tree, tvb, offset,
2016 pdu_length, "Cause: %s",
2017 val_to_str(cause, smux_close,
2018 "Unknown cause %#x"));
2020 offset += pdu_length;
2023 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) {
2024 pdu_type_string = val_to_str(pdu_type, smux_types,
2025 "Unknown PDU type %#x");
2026 if (check_col(pinfo->cinfo, COL_INFO))
2027 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2028 length = asn1.offset - start;
2030 proto_tree_add_text(smux_tree, tvb, offset, length,
2031 "PDU type: %s", pdu_type_string);
2034 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
2035 if (ret != ASN1_ERR_NOERROR) {
2036 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2037 "registration subtree", ret);
2041 oid_string = format_oid(regid, regid_length);
2042 proto_tree_add_text(smux_tree, tvb, offset, length,
2043 "Registration: %s", oid_string);
2049 ret = asn1_uint32_decode (&asn1, &priority, &length);
2050 if (ret != ASN1_ERR_NOERROR) {
2051 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2056 proto_tree_add_text(smux_tree, tvb, offset, length,
2057 "Priority: %d", priority);
2061 ret = asn1_uint32_decode (&asn1, &operation, &length);
2062 if (ret != ASN1_ERR_NOERROR) {
2063 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2068 proto_tree_add_text(smux_tree, tvb, offset, length,
2070 val_to_str(operation, smux_rreq,
2071 "Unknown operation %#x"));
2076 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) {
2077 pdu_type_string = val_to_str(pdu_type, smux_types,
2078 "Unknown PDU type %#x");
2079 if (check_col(pinfo->cinfo, COL_INFO))
2080 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2081 length = asn1.offset - start;
2083 proto_tree_add_text(smux_tree, tvb, offset, length,
2084 "PDU type: %s", pdu_type_string);
2087 ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
2088 if (ret != ASN1_ERR_NOERROR) {
2089 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2094 proto_tree_add_text(smux_tree, tvb, offset,
2096 val_to_str(priority, smux_prio,
2099 offset += pdu_length;
2102 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) {
2103 pdu_type_string = val_to_str(pdu_type, smux_types,
2104 "Unknown PDU type %#x");
2105 if (check_col(pinfo->cinfo, COL_INFO))
2106 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2107 length = asn1.offset - start;
2109 proto_tree_add_text(smux_tree, tvb, offset, length,
2110 "PDU type: %s", pdu_type_string);
2113 ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
2114 if (ret != ASN1_ERR_NOERROR) {
2115 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2120 proto_tree_add_text(smux_tree, tvb, offset,
2122 val_to_str(commit, smux_sout,
2123 "Unknown SOUT Value: %#x"));
2125 offset += pdu_length;
2128 if (cls != ASN1_CTX || con != ASN1_CON) {
2129 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2130 "PDU type", ASN1_ERR_WRONG_TYPE);
2133 dissect_common_pdu(tvb, offset, pinfo, smux_tree, asn1, pdu_type, start);
2137 dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2139 conversation_t *conversation;
2142 * The first SNMP packet goes to the SNMP port; the second one
2143 * may come from some *other* port, but goes back to the same
2144 * IP address and port as the ones from which the first packet
2145 * came; all subsequent packets presumably go between those two
2146 * IP addresses and ports.
2148 * If this packet went to the SNMP port, we check to see if
2149 * there's already a conversation with one address/port pair
2150 * matching the source IP address and port of this packet,
2151 * the other address matching the destination IP address of this
2152 * packet, and any destination port.
2154 * If not, we create one, with its address 1/port 1 pair being
2155 * the source address/port of this packet, its address 2 being
2156 * the destination address of this packet, and its port 2 being
2157 * wildcarded, and give it the SNMP dissector as a dissector.
2159 if (pinfo->destport == UDP_PORT_SNMP) {
2160 conversation = find_conversation(&pinfo->src, &pinfo->dst, PT_UDP,
2161 pinfo->srcport, 0, NO_PORT_B);
2162 if (conversation == NULL) {
2163 conversation = conversation_new(&pinfo->src, &pinfo->dst, PT_UDP,
2164 pinfo->srcport, 0, NO_PORT2);
2165 conversation_set_dissector(conversation, snmp_handle);
2169 dissect_snmp_pdu(tvb, 0, pinfo, tree, "SNMP", proto_snmp, ett_snmp);
2173 dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2175 dissect_smux_pdu(tvb, 0, pinfo, tree, proto_smux, ett_smux);
2179 proto_register_snmp(void)
2181 #if defined(HAVE_UCD_SNMP_SNMP_H) && defined(linux)
2182 void *libsnmp_handle;
2183 int (*snmp_set_suffix_only_p)(int);
2184 int (*ds_set_int_p)(int, int, int);
2187 static hf_register_info hf[] = {
2189 { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
2191 { &hf_snmpv3_flags_auth,
2192 { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8,
2193 TFS(&flags_set_truth), TH_AUTH, "", HFILL }},
2194 { &hf_snmpv3_flags_crypt,
2195 { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8,
2196 TFS(&flags_set_truth), TH_CRYPT, "", HFILL }},
2197 { &hf_snmpv3_flags_report,
2198 { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
2199 TFS(&flags_set_truth), TH_REPORT, "", HFILL }},
2201 static gint *ett[] = {
2205 &ett_parameters_qos,
2211 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
2212 /* UCD or CMU SNMP */
2214 #ifdef HAVE_UCD_SNMP_SNMP_H
2216 /* As per the comment near the beginning of the file, UCD SNMP 4.1.1
2217 changed "snmp_set_suffix_only()" from a function to a macro,
2218 removing "snmp_set_suffix_only()" from the library; this means
2219 that binaries that call "snmp_set_suffix_only()" and
2220 that are linked against shared libraries from earlier versions
2221 of the UCD SNMP library won't run with shared libraries from
2224 This is a problem on Red Hat Linux, as pre-6.2 releases
2225 came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
2226 Versions of Ethereal built on pre-6.2 releases don't run
2227 on 6.2, and the current Ethereal RPMs are built on pre-6.2
2228 releases, causing problems when users running 6.2 download
2229 them and try to use them.
2231 Building the releases on 6.2 isn't necessarily the answer,
2232 as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
2233 with a second argument not supported by at least some pre-4.1.1
2234 versions of the library - it appears that the 4.0.1 library,
2235 at least, checks for invalid arguments and returns an error
2236 rather than stomping random memory, but that means that you
2237 won't get get OIDs displayed as module-name::sub-OID.
2239 So we use a trick similar to one I've seen mentioned as
2240 used in Windows applications to let you build binaries
2241 that run on many different versions of Windows 9x and
2242 Windows NT, that use features present on later versions
2243 if run on those later versions, but that avoid calling,
2244 when run on older versions, routines not present on those
2247 I.e., we load "libsnmp.so.0" with "dlopen()", and call
2248 "dlsym()" to try to find "snmp_set_suffix_only()"; if we
2249 don't find it, we make the appropriate call to
2250 "ds_set_int()" instead. (We load "libsnmp.so.0" rather
2251 than "libsnmp.so" because, at least on RH 6.2, "libsnmp.so"
2252 exists only if you've loaded the libsnmp development package,
2253 which makes "libsnmp.so" a symlink to "libsnmp.so.0"; we
2254 don't want to force users to install it or to make said
2257 We do this only on Linux, for now, as we've only seen the
2258 problem on Red Hat; it may show up on other OSes that bundle
2259 UCD SNMP, or on OSes where it's not bundled but for which
2260 binary packages are built that link against a shared version
2261 of the UCD SNMP library. If we run into one of those, we
2262 can do this under those OSes as well, *if* "dlopen()" makes
2263 the run-time linker use the same search rules as it uses when
2264 loading libraries with which the application is linked.
2266 (Perhaps we could use the GLib wrappers for run-time linking,
2267 *if* they're thin enough; however, as this code is currently
2268 used only on Linux, we don't worry about that for now.) */
2270 libsnmp_handle = dlopen("libsnmp.so.0", RTLD_LAZY|RTLD_GLOBAL);
2271 if (libsnmp_handle == NULL) {
2272 /* We didn't find "libsnmp.so.0".
2274 This could mean that there is no SNMP shared library
2275 on this system, in which case we were linked statically,
2276 in which case whatever call the following line of code
2277 makes will presumably work, as we have the routine it
2278 calls wired into our binary. (If we were linked
2279 dynamically with "-lsnmp", we would have failed to
2282 It could also mean that there is an SNMP shared library
2283 on this system, but it's called something other than
2284 "libsnmp.so.0"; so far, we've seen the problem we're
2285 working around only on systems where the SNMP shared
2286 library is called "libsnmp.so.0", so we assume for now
2287 that systems with shared SNMP libraries named something
2288 other than "libsnmp.so.0" have an SNMP library that's
2290 snmp_set_suffix_only(2);
2292 /* OK, we have it loaded. Do we have
2293 "snmp_set_suffix_only()"? */
2294 snmp_set_suffix_only_p = dlsym(libsnmp_handle,
2295 "snmp_set_suffix_only");
2296 if (snmp_set_suffix_only_p != NULL) {
2297 /* Yes - call it. */
2298 (*snmp_set_suffix_only_p)(2);
2300 /* No; do we have "ds_set_int()"? */
2301 ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
2302 if (ds_set_int_p != NULL) {
2303 /* Yes - cal it with DS_LIBRARY_ID,
2304 DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
2307 We do *not* use DS_LIBRARY_ID or
2308 DS_LIB_PRINT_SUFFIX_ONLY by name, so that
2309 we don't require that Ethereal be built
2310 with versions of UCD SNMP that include
2311 that value; instead, we use their values
2312 in UCD SNMP 4.1.1, which are 0 and 4,
2314 (*ds_set_int_p)(0, 4, 2);
2317 dlclose(libsnmp_handle);
2320 snmp_set_suffix_only(2);
2322 #endif /* HAVE_UCD_SNMP_SNMP_H */
2323 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
2324 proto_snmp = proto_register_protocol("Simple Network Management Protocol",
2326 proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2328 proto_register_field_array(proto_snmp, hf, array_length(hf));
2329 proto_register_subtree_array(ett, array_length(ett));
2330 snmp_handle = create_dissector_handle(dissect_snmp, proto_snmp);
2334 proto_reg_handoff_snmp(void)
2336 dissector_handle_t smux_handle;
2338 dissector_add("udp.port", UDP_PORT_SNMP, snmp_handle);
2339 dissector_add("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
2340 smux_handle = create_dissector_handle(dissect_smux, proto_smux);
2341 dissector_add("tcp.port", TCP_PORT_SMUX, smux_handle);
2342 dissector_add("ethertype", ETHERTYPE_SNMP, snmp_handle);
2343 dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
2344 dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
2345 data_handle = find_dissector("data");