2 * Routines for SNMP (simple network management protocol)
5 * $Id: packet-snmp.c,v 1.24 2000/02/20 03:32:29 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@zing.org>
9 * Copyright 1998 Didier Jorand
13 * GXSNMP -- An snmp mangament application
14 * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
15 * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
44 #ifdef HAVE_NETINET_IN_H
45 # include <netinet/in.h>
48 #define MAX_STRING_LEN 1024 /* TBC */
54 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
58 # if defined(HAVE_UCD_SNMP_SNMP_H)
62 # include <ucd-snmp/asn1.h>
63 # include <ucd-snmp/snmp_api.h>
64 # include <ucd-snmp/snmp_impl.h>
65 # include <ucd-snmp/mib.h>
68 * Sigh. UCD SNMP 4.1[.x] makes "snmp_set_full_objid()" a macro
69 * that calls "ds_set_boolean()" with the first two arguments
70 * being DS_LIBRARY_ID and DS_LIB_PRINT_FULL_OID; this means that,
71 * when building with 4.1[.x], we need to arrange that
72 * <ucd-snmp/default_store.h> is included, to define those two values
73 * and to declare "ds_set_boolean()".
77 * 1) we can't include it on earlier versions (at least not 3.6.2),
78 * as it doesn't exist in those versions;
80 * 2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
81 * as that includes <ucd-snmp/snmp.h>, and that defines a whole
82 * bunch of values that we also define ourselves.
84 * So we only include it if "snmp_set_full_objid" is defined as
87 # ifdef snmp_set_full_objid
88 # include <ucd-snmp/default_store.h>
92 * XXX - for now, we assume all versions of UCD SNMP have it.
94 # define HAVE_SPRINT_VALUE
97 * Define values "sprint_value()" expects.
99 # define VALTYPE_INTEGER ASN_INTEGER
100 # define VALTYPE_COUNTER ASN_COUNTER
101 # define VALTYPE_GAUGE ASN_GAUGE
102 # define VALTYPE_TIMETICKS ASN_TIMETICKS
103 # define VALTYPE_STRING ASN_OCTET_STR
104 # define VALTYPE_IPADDR ASN_IPADDRESS
105 # define VALTYPE_OPAQUE ASN_OPAQUE
106 # define VALTYPE_NSAP ASN_NSAP
107 # define VALTYPE_OBJECTID ASN_OBJECT_ID
108 # define VALTYPE_BITSTR ASN_BIT_STR
109 # define VALTYPE_COUNTER64 ASN_COUNTER64
110 # elif defined(HAVE_SNMP_SNMP_H)
114 # include <snmp/snmp.h>
117 * Some older versions of CMU SNMP may lack these values (e.g., the
118 * "libsnmp3.6" package for Debian, which is based on some old
119 * CMU SNMP, perhaps 1.0); for now, we assume they also lack
123 # define HAVE_SPRINT_VALUE
125 * Define values "sprint_value()" expects.
127 # define VALTYPE_INTEGER SMI_INTEGER
128 # define VALTYPE_COUNTER SMI_COUNTER32
129 # define VALTYPE_GAUGE SMI_GAUGE32
130 # define VALTYPE_TIMETICKS SMI_TIMETICKS
131 # define VALTYPE_STRING SMI_STRING
132 # define VALTYPE_IPADDR SMI_IPADDRESS
133 # define VALTYPE_OPAQUE SMI_OPAQUE
134 # define VALTYPE_NSAP SMI_STRING
135 # define VALTYPE_OBJECTID SMI_OBJID
136 # define VALTYPE_BITSTR ASN_BIT_STR
137 # define VALTYPE_COUNTER64 SMI_COUNTER64
140 * Now undo all the definitions they "helpfully" gave us, so we don't get
141 * complaints about redefining them.
143 * Why, oh why, is there no library that provides code to
147 * 2) translate object IDs into names;
149 * 3) let you find out, for a given object ID, what the type, enum
150 * values, display hint, etc. are;
152 * in a *simple* fashion, without assuming that your code is part of an
153 * SNMP agent or client that wants a pile of definitions of PDU types,
154 * etc.? Is it just that 99 44/100% of the code that uses an SNMP library
155 * *is* part of an agent or client, and really *does* need that stuff,
156 * and *doesn't* need the interfaces we want?
158 # undef SNMP_ERR_NOERROR
159 # undef SNMP_ERR_TOOBIG
160 # undef SNMP_ERR_NOSUCHNAME
161 # undef SNMP_ERR_BADVALUE
162 # undef SNMP_ERR_READONLY
163 # undef SNMP_ERR_NOACCESS
164 # undef SNMP_ERR_WRONGTYPE
165 # undef SNMP_ERR_WRONGLENGTH
166 # undef SNMP_ERR_WRONGENCODING
167 # undef SNMP_ERR_WRONGVALUE
168 # undef SNMP_ERR_NOCREATION
169 # undef SNMP_ERR_INCONSISTENTVALUE
170 # undef SNMP_ERR_RESOURCEUNAVAILABLE
171 # undef SNMP_ERR_COMMITFAILED
172 # undef SNMP_ERR_UNDOFAILED
173 # undef SNMP_ERR_AUTHORIZATIONERROR
174 # undef SNMP_ERR_NOTWRITABLE
175 # undef SNMP_ERR_INCONSISTENTNAME
176 # undef SNMP_TRAP_COLDSTART
177 # undef SNMP_TRAP_WARMSTART
178 # undef SNMP_TRAP_LINKDOWN
179 # undef SNMP_TRAP_LINKUP
180 # undef SNMP_TRAP_EGPNEIGHBORLOSS
181 # undef SNMP_TRAP_ENTERPRISESPECIFIC
187 #include "packet-snmp.h"
189 static int proto_snmp = -1;
191 static gint ett_snmp = -1;
193 /* Protocol version numbers */
194 #define SNMP_VERSION_1 0
195 #define SNMP_VERSION_2c 1
196 #define SNMP_VERSION_2u 2
197 #define SNMP_VERSION_3 3
199 static const value_string versions[] = {
200 { SNMP_VERSION_1, "1" },
201 { SNMP_VERSION_2c, "2C" },
202 { SNMP_VERSION_2u, "2U" },
203 { SNMP_VERSION_3, "3" },
208 #define SNMP_MSG_GET 0
209 #define SNMP_MSG_GETNEXT 1
210 #define SNMP_MSG_RESPONSE 2
211 #define SNMP_MSG_SET 3
212 #define SNMP_MSG_TRAP 4
214 #define SNMP_MSG_GETBULK 5
215 #define SNMP_MSG_INFORM 6
216 #define SNMP_MSG_TRAP2 7
217 #define SNMP_MSG_REPORT 8
219 static const value_string pdu_types[] = {
220 { SNMP_MSG_GET, "GET" },
221 { SNMP_MSG_GETNEXT, "GET-NEXT" },
222 { SNMP_MSG_SET, "SET" },
223 { SNMP_MSG_RESPONSE, "RESPONSE" },
224 { SNMP_MSG_TRAP, "TRAP-V1" },
225 { SNMP_MSG_GETBULK, "GETBULK" },
226 { SNMP_MSG_INFORM, "INFORM" },
227 { SNMP_MSG_TRAP2, "TRAP-V2" },
228 { SNMP_MSG_REPORT, "REPORT" },
232 /* Error status values */
233 #define SNMP_ERR_NOERROR 0
234 #define SNMP_ERR_TOOBIG 1
235 #define SNMP_ERR_NOSUCHNAME 2
236 #define SNMP_ERR_BADVALUE 3
237 #define SNMP_ERR_READONLY 4
238 #define SNMP_ERR_GENERROR 5
240 #define SNMP_ERR_NOACCESS 6
241 #define SNMP_ERR_WRONGTYPE 7
242 #define SNMP_ERR_WRONGLENGTH 8
243 #define SNMP_ERR_WRONGENCODING 9
244 #define SNMP_ERR_WRONGVALUE 10
245 #define SNMP_ERR_NOCREATION 11
246 #define SNMP_ERR_INCONSISTENTVALUE 12
247 #define SNMP_ERR_RESOURCEUNAVAILABLE 13
248 #define SNMP_ERR_COMMITFAILED 14
249 #define SNMP_ERR_UNDOFAILED 15
250 #define SNMP_ERR_AUTHORIZATIONERROR 16
251 #define SNMP_ERR_NOTWRITABLE 17
252 #define SNMP_ERR_INCONSISTENTNAME 18
254 static const value_string error_statuses[] = {
255 { SNMP_ERR_NOERROR, "NO ERROR" },
256 { SNMP_ERR_TOOBIG, "TOOBIG" },
257 { SNMP_ERR_NOSUCHNAME, "NO SUCH NAME" },
258 { SNMP_ERR_BADVALUE, "BAD VALUE" },
259 { SNMP_ERR_READONLY, "READ ONLY" },
260 { SNMP_ERR_GENERROR, "GENERIC ERROR" },
261 { SNMP_ERR_NOACCESS, "NO ACCESS" },
262 { SNMP_ERR_WRONGTYPE, "WRONG TYPE" },
263 { SNMP_ERR_WRONGLENGTH, "WRONG LENGTH" },
264 { SNMP_ERR_WRONGENCODING, "WRONG ENCODING" },
265 { SNMP_ERR_WRONGVALUE, "WRONG VALUE" },
266 { SNMP_ERR_NOCREATION, "NO CREATION" },
267 { SNMP_ERR_INCONSISTENTVALUE, "INCONSISTENT VALUE" },
268 { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
269 { SNMP_ERR_COMMITFAILED, "COMMIT FAILED" },
270 { SNMP_ERR_UNDOFAILED, "UNDO FAILED" },
271 { SNMP_ERR_AUTHORIZATIONERROR, "AUTHORIZATION ERROR" },
272 { SNMP_ERR_NOTWRITABLE, "NOT WRITABLE" },
273 { SNMP_ERR_INCONSISTENTNAME, "INCONSISTENT NAME" },
277 /* General SNMP V1 Traps */
279 #define SNMP_TRAP_COLDSTART 0
280 #define SNMP_TRAP_WARMSTART 1
281 #define SNMP_TRAP_LINKDOWN 2
282 #define SNMP_TRAP_LINKUP 3
283 #define SNMP_TRAP_AUTHFAIL 4
284 #define SNMP_TRAP_EGPNEIGHBORLOSS 5
285 #define SNMP_TRAP_ENTERPRISESPECIFIC 6
287 static const value_string trap_types[] = {
288 { SNMP_TRAP_COLDSTART, "COLD START" },
289 { SNMP_TRAP_WARMSTART, "WARM START" },
290 { SNMP_TRAP_LINKDOWN, "LINK DOWN" },
291 { SNMP_TRAP_LINKUP, "LINK UP" },
292 { SNMP_TRAP_AUTHFAIL, "AUTHENTICATION FAILED" },
293 { SNMP_TRAP_EGPNEIGHBORLOSS, "EGP NEIGHBORLOSS" },
294 { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
300 #define SNMP_IPA 0 /* IP Address */
301 #define SNMP_CNT 1 /* Counter (Counter32) */
302 #define SNMP_GGE 2 /* Gauge (Gauge32) */
303 #define SNMP_TIT 3 /* TimeTicks */
304 #define SNMP_OPQ 4 /* Opaque */
305 #define SNMP_NSP 5 /* NsapAddress */
306 #define SNMP_C64 6 /* Counter64 */
307 #define SNMP_U32 7 /* Uinteger32 */
316 #define SNMP_INTEGER 1 /* l */
317 #define SNMP_OCTETSTR 2 /* c */
318 #define SNMP_DISPLAYSTR 2 /* c */
319 #define SNMP_OBJECTID 3 /* ul */
320 #define SNMP_IPADDR 4 /* uc */
321 #define SNMP_COUNTER 5 /* ul */
322 #define SNMP_GAUGE 6 /* ul */
323 #define SNMP_TIMETICKS 7 /* ul */
324 #define SNMP_OPAQUE 8 /* c */
326 /* additional SNMPv2 Types */
328 #define SNMP_UINTEGER 5 /* ul */
329 #define SNMP_BITSTR 9 /* uc */
330 #define SNMP_NSAP 10 /* uc */
331 #define SNMP_COUNTER64 11 /* ul */
332 #define SNMP_NOSUCHOBJECT 12
333 #define SNMP_NOSUCHINSTANCE 13
334 #define SNMP_ENDOFMIBVIEW 14
336 typedef struct _SNMP_CNV SNMP_CNV;
346 static SNMP_CNV SnmpCnv [] =
348 {ASN1_UNI, ASN1_NUL, SNMP_NULL, "NULL"},
349 {ASN1_UNI, ASN1_INT, SNMP_INTEGER, "INTEGER"},
350 {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR, "OCTET STRING"},
351 {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID, "OBJECTID"},
352 {ASN1_APL, SNMP_IPA, SNMP_IPADDR, "IPADDR"},
353 {ASN1_APL, SNMP_CNT, SNMP_COUNTER, "COUNTER"}, /* Counter32 */
354 {ASN1_APL, SNMP_GGE, SNMP_GAUGE, "GAUGE"}, /* Gauge32 == Unsigned32 */
355 {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
356 {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE, "OPAQUE"},
358 /* SNMPv2 data types and errors */
360 {ASN1_UNI, ASN1_BTS, SNMP_BITSTR, "BITSTR"},
361 {ASN1_APL, SNMP_C64, SNMP_COUNTER64, "COUNTER64"},
362 {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT, "NOSUCHOBJECT"},
363 {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
364 {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW, "ENDOFMIBVIEW"},
369 * NAME: g_snmp_tag_cls2syntax
370 * SYNOPSIS: gboolean g_snmp_tag_cls2syntax
376 * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
377 * See SnmpCnv for conversion.
378 * RETURNS: name on success, NULL on failure
382 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
387 while (cnv->syntax != -1)
389 if (cnv->tag == tag && cnv->class == cls)
391 *syntax = cnv->syntax;
400 dissect_snmp_parse_error(const u_char *pd, int offset, frame_data *fd,
401 proto_tree *tree, const char *field_name, int ret)
405 if (check_col(fd, COL_INFO)) {
409 errstr = "Ran out of data";
412 case ASN1_ERR_EOC_MISMATCH:
413 errstr = "EOC mismatch";
416 case ASN1_ERR_WRONG_TYPE:
417 errstr = "Wrong type for that item";
420 case ASN1_ERR_LENGTH_NOT_DEFINITE:
421 errstr = "Length was indefinite";
424 case ASN1_ERR_LENGTH_MISMATCH:
425 errstr = "Length mismatch";
428 case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
429 errstr = "Wrong length for that item's type";
433 errstr = "Unknown error";
436 col_add_fstr(fd, COL_INFO,
437 "ERROR: Couldn't parse %s: %s", field_name, errstr);
440 dissect_data(pd, offset, fd, tree);
444 dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
445 proto_tree *tree, const char *message)
447 if (check_col(fd, COL_INFO))
448 col_add_str(fd, COL_INFO, message);
450 dissect_data(pd, offset, fd, tree);
454 format_oid(gchar *buf, subid_t *oid, guint oid_length)
459 len = sprintf(buf, "%lu", (unsigned long)oid[0]);
461 for (i = 1; i < oid_length;i++) {
462 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
467 #ifdef HAVE_SPRINT_VALUE
469 format_value(gchar *buf, struct variable_list *variable, subid_t *variable_oid,
470 guint variable_oid_length, gushort vb_type, guint vb_length)
472 variable->next_variable = NULL;
473 variable->name = variable_oid;
474 variable->name_length = variable_oid_length;
478 variable->type = VALTYPE_INTEGER;
482 variable->type = VALTYPE_COUNTER;
486 variable->type = VALTYPE_GAUGE;
490 variable->type = VALTYPE_TIMETICKS;
494 variable->type = VALTYPE_STRING;
498 variable->type = VALTYPE_IPADDR;
502 variable->type = VALTYPE_OPAQUE;
506 variable->type = VALTYPE_NSAP;
510 variable->type = VALTYPE_OBJECTID;
514 variable->type = VALTYPE_BITSTR;
518 variable->type = VALTYPE_COUNTER64;
521 variable->val_len = vb_length;
522 sprint_value(buf, variable_oid, variable_oid_length, variable);
527 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
528 guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp)
539 gint32 vb_integer_value;
540 guint32 vb_uinteger_value;
542 guint8 *vb_octet_string;
547 gchar vb_display_string[MAX_STRING_LEN]; /* TBC */
549 #ifdef HAVE_SPRINT_VALUE
550 struct variable_list variable;
551 #if defined(HAVE_UCD_SNMP_SNMP_H)
554 #else /* HAVE_SPRINT_VALUE */
558 #endif /* HAVE_SPRINT_VALUE */
560 /* parse the type of the object */
561 start = asn1->pointer;
562 ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
563 if (ret != ASN1_ERR_NOERROR)
566 return ASN1_ERR_LENGTH_NOT_DEFINITE;
568 /* Convert the class, constructed flag, and tag to a type. */
569 vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
570 if (vb_type_name == NULL) {
573 * Dissect the value as an opaque string of octets.
575 vb_type_name = "unsupported type";
576 vb_type = SNMP_OPAQUE;
579 /* parse the value */
583 ret = asn1_int32_value_decode(asn1, vb_length,
585 if (ret != ASN1_ERR_NOERROR)
587 length = asn1->pointer - start;
589 #ifdef HAVE_SPRINT_VALUE
590 #if defined(HAVE_UCD_SNMP_SNMP_H)
591 value = vb_integer_value;
592 variable.val.integer = &value;
593 #elif defined(HAVE_SNMP_SNMP_H)
594 variable.val.integer = &vb_integer_value;
596 format_value(vb_display_string, &variable,
597 variable_oid, variable_oid_length, vb_type,
599 proto_tree_add_text(snmp_tree, offset, length,
600 "Value: %s", vb_display_string);
602 proto_tree_add_text(snmp_tree, offset, length,
603 "Value: %s: %d (%#x)", vb_type_name,
604 vb_integer_value, vb_integer_value);
612 ret = asn1_uint32_value_decode(asn1, vb_length,
614 if (ret != ASN1_ERR_NOERROR)
616 length = asn1->pointer - start;
618 #ifdef HAVE_SPRINT_VALUE
619 #if defined(HAVE_UCD_SNMP_SNMP_H)
620 value = vb_uinteger_value;
621 variable.val.integer = &value;
622 #elif defined(HAVE_SNMP_SNMP_H)
623 variable.val.integer = &vb_uinteger_value;
625 format_value(vb_display_string, &variable,
626 variable_oid, variable_oid_length, vb_type,
628 proto_tree_add_text(snmp_tree, offset, length,
629 "Value: %s", vb_display_string);
631 proto_tree_add_text(snmp_tree, offset, length,
632 "Value: %s: %u (%#x)", vb_type_name,
633 vb_uinteger_value, vb_uinteger_value);
644 ret = asn1_octet_string_value_decode (asn1, vb_length,
646 if (ret != ASN1_ERR_NOERROR)
648 length = asn1->pointer - start;
650 #ifdef HAVE_SPRINT_VALUE
651 variable.val.string = vb_octet_string;
652 format_value(vb_display_string, &variable,
653 variable_oid, variable_oid_length, vb_type,
655 proto_tree_add_text(snmp_tree, offset, length,
656 "Value: %s", vb_display_string);
659 * If some characters are not printable, display
660 * the string as bytes.
662 for (i = 0; i < vb_length; i++) {
663 if (!(isprint(vb_octet_string[i])
664 || isspace(vb_octet_string[i])))
669 * We stopped, due to a non-printable
670 * character, before we got to the end
673 buf = &vb_display_string[0];
674 len = sprintf(buf, "%03u", vb_octet_string[0]);
676 for (i = 1; i < vb_length; i++) {
677 len = sprintf(buf, ".%03u",
681 proto_tree_add_text(snmp_tree, offset, length,
682 "Value: %s: %s", vb_type_name,
685 proto_tree_add_text(snmp_tree, offset, length,
686 "Value: %s: %.*s", vb_type_name, vb_length,
691 g_free(vb_octet_string);
695 ret = asn1_null_decode (asn1, vb_length);
696 if (ret != ASN1_ERR_NOERROR)
698 length = asn1->pointer - start;
700 proto_tree_add_text(snmp_tree, offset, length,
701 "Value: %s", vb_type_name);
706 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
708 if (ret != ASN1_ERR_NOERROR)
710 length = asn1->pointer - start;
712 #ifdef HAVE_SPRINT_VALUE
713 variable.val.objid = vb_oid;
714 format_value(vb_display_string, &variable,
715 variable_oid, variable_oid_length, vb_type,
716 vb_length*sizeof (subid_t));
717 proto_tree_add_text(snmp_tree, offset, length,
718 "Value: %s", vb_display_string);
720 format_oid(vb_display_string, vb_oid, vb_oid_length);
721 proto_tree_add_text(snmp_tree, offset, length,
722 "Value: %s: %s", vb_type_name, vb_display_string);
728 case SNMP_NOSUCHOBJECT:
729 length = asn1->pointer - start;
731 proto_tree_add_text(snmp_tree, offset, length,
732 "Value: %s: no such object", vb_type_name);
736 case SNMP_NOSUCHINSTANCE:
737 length = asn1->pointer - start;
739 proto_tree_add_text(snmp_tree, offset, length,
740 "Value: %s: no such instance", vb_type_name);
744 case SNMP_ENDOFMIBVIEW:
745 length = asn1->pointer - start;
747 proto_tree_add_text(snmp_tree, offset, length,
748 "Value: %s: end of mib view", vb_type_name);
753 g_assert_not_reached();
754 return ASN1_ERR_WRONG_TYPE;
757 return ASN1_ERR_NOERROR;
761 dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
762 proto_tree *tree, char *proto_name, int proto, gint ett)
768 guint sequence_length;
770 guint message_length;
775 int community_length;
778 char *pdu_type_string;
783 guint32 error_status;
788 guint enterprise_length;
790 guint8 *agent_address;
791 guint agent_address_length;
795 guint32 specific_type;
798 guint timestamp_length;
800 gchar oid_string[MAX_STRING_LEN]; /* TBC */
802 guint variable_bindings_length;
805 guint variable_length;
806 subid_t *variable_oid;
807 guint variable_oid_length;
808 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
809 gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
812 proto_tree *snmp_tree = NULL;
813 proto_item *item = NULL;
817 if (check_col(fd, COL_PROTOCOL))
818 col_add_str(fd, COL_PROTOCOL, proto_name);
821 item = proto_tree_add_item(tree, proto, offset, END_OF_FRAME, NULL);
822 snmp_tree = proto_item_add_subtree(item, ett);
825 /* NOTE: we have to parse the message piece by piece, since the
826 * capture length may be less than the message length: a 'global'
827 * parsing is likely to fail.
829 /* parse the SNMP header */
830 asn1_open(&asn1, &pd[offset], END_OF_FRAME);
831 ret = asn1_sequence_decode(&asn1, &message_length, &length);
832 if (ret != ASN1_ERR_NOERROR) {
833 dissect_snmp_parse_error(pd, offset, fd, tree,
834 "message header", ret);
839 ret = asn1_uint32_decode (&asn1, &version, &length);
840 if (ret != ASN1_ERR_NOERROR) {
841 dissect_snmp_parse_error(pd, offset, fd, tree, "version number",
846 proto_tree_add_text(snmp_tree, offset, length,
848 val_to_str(version, versions, "Unknown version %#x"));
852 ret = asn1_octet_string_decode (&asn1, &community, &community_length,
854 if (ret != ASN1_ERR_NOERROR) {
855 dissect_snmp_parse_error(pd, offset, fd, tree, "community",
860 proto_tree_add_text(snmp_tree, offset, length,
861 "Community: %.*s", community_length, community);
869 case SNMP_VERSION_2c:
870 case SNMP_VERSION_2u:
875 dissect_snmp_error(pd, offset, fd, tree,
876 "PDU for unknown version of SNMP");
880 start = asn1.pointer;
881 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
883 if (ret != ASN1_ERR_NOERROR) {
884 dissect_snmp_parse_error(pd, offset, fd, tree,
888 if (cls != ASN1_CTX || con != ASN1_CON) {
889 dissect_snmp_parse_error(pd, offset, fd, tree,
890 "PDU type", ASN1_ERR_WRONG_TYPE);
893 pdu_type_string = val_to_str(pdu_type, pdu_types,
894 "Unknown PDU type %#x");
895 if (check_col(fd, COL_INFO))
896 col_add_str(fd, COL_INFO, pdu_type_string);
897 length = asn1.pointer - start;
899 proto_tree_add_text(snmp_tree, offset, length,
900 "PDU type: %s", pdu_type_string);
904 /* get the fields in the PDU preceeding the variable-bindings sequence */
908 case SNMP_MSG_GETNEXT:
909 case SNMP_MSG_RESPONSE:
911 /* XXX - are they like V1 non-trap PDUs? */
912 case SNMP_MSG_GETBULK:
913 case SNMP_MSG_INFORM:
915 ret = asn1_uint32_decode (&asn1, &request_id, &length);
916 if (ret != ASN1_ERR_NOERROR) {
917 dissect_snmp_parse_error(pd, offset, fd, tree,
922 proto_tree_add_text(snmp_tree, offset, length,
923 "Request Id: %#x", request_id);
927 /* error status (getbulk non-repeaters) */
928 ret = asn1_uint32_decode (&asn1, &error_status, &length);
929 if (ret != ASN1_ERR_NOERROR) {
930 dissect_snmp_parse_error(pd, offset, fd, tree,
931 "error status", ret);
935 proto_tree_add_text(snmp_tree, offset, length,
937 val_to_str(error_status, error_statuses,
942 /* error index (getbulk max-repetitions) */
943 ret = asn1_uint32_decode (&asn1, &error_index, &length);
944 if (ret != ASN1_ERR_NOERROR) {
945 dissect_snmp_parse_error(pd, offset, fd, tree,
950 proto_tree_add_text(snmp_tree, offset, length,
951 "Error Index: %u", error_index);
958 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
960 if (ret != ASN1_ERR_NOERROR) {
961 dissect_snmp_parse_error(pd, offset, fd, tree,
962 "enterprise OID", ret);
966 format_oid(oid_string, enterprise, enterprise_length);
967 proto_tree_add_text(snmp_tree, offset, length,
968 "Enterprise: %s", oid_string);
974 start = asn1.pointer;
975 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
976 &def, &agent_address_length);
977 if (ret != ASN1_ERR_NOERROR) {
978 dissect_snmp_parse_error(pd, offset, fd, tree,
979 "agent address", ret);
982 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
983 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
984 /* GXSNMP 0.0.15 says the latter is "needed for
986 dissect_snmp_parse_error(pd, offset, fd, tree,
987 "agent_address", ASN1_ERR_WRONG_TYPE);
990 if (agent_address_length != 4) {
991 dissect_snmp_parse_error(pd, offset, fd, tree,
992 "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
995 ret = asn1_octet_string_value_decode (&asn1,
996 agent_address_length, &agent_address);
997 if (ret != ASN1_ERR_NOERROR) {
998 dissect_snmp_parse_error(pd, offset, fd, tree,
999 "agent address", ret);
1002 length = asn1.pointer - start;
1004 proto_tree_add_text(snmp_tree, offset, agent_address_length,
1005 "Agent address: %s", ip_to_str(agent_address));
1007 g_free(agent_address);
1010 /* generic trap type */
1011 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1012 if (ret != ASN1_ERR_NOERROR) {
1013 dissect_snmp_parse_error(pd, offset, fd, tree,
1014 "generic trap type", ret);
1018 proto_tree_add_text(snmp_tree, offset, length,
1020 val_to_str(trap_type, trap_types, "Unknown (%u)"));
1024 /* specific trap type */
1025 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1026 if (ret != ASN1_ERR_NOERROR) {
1027 dissect_snmp_parse_error(pd, offset, fd, tree,
1028 "specific trap type", ret);
1032 proto_tree_add_text(snmp_tree, offset, length,
1033 "Specific trap type: %u (%#x)",
1034 specific_type, specific_type);
1039 start = asn1.pointer;
1040 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1041 &def, ×tamp_length);
1042 if (ret != ASN1_ERR_NOERROR) {
1043 dissect_snmp_parse_error(pd, offset, fd, tree,
1047 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1048 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1049 dissect_snmp_parse_error(pd, offset, fd, tree,
1050 "timestamp", ASN1_ERR_WRONG_TYPE);
1053 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1055 if (ret != ASN1_ERR_NOERROR) {
1056 dissect_snmp_parse_error(pd, offset, fd, tree,
1060 length = asn1.pointer - start;
1062 proto_tree_add_text(snmp_tree, offset, length,
1063 "Timestamp: %u", timestamp);
1069 /* variable bindings */
1070 /* get header for variable-bindings sequence */
1071 ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1072 if (ret != ASN1_ERR_NOERROR) {
1073 dissect_snmp_parse_error(pd, offset, fd, tree,
1074 "variable bindings header", ret);
1079 /* loop on variable bindings */
1081 while (variable_bindings_length > 0) {
1083 sequence_length = 0;
1086 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1087 if (ret != ASN1_ERR_NOERROR) {
1088 dissect_snmp_parse_error(pd, offset, fd, tree,
1089 "variable binding header", ret);
1092 sequence_length += length;
1094 /* parse object identifier */
1095 ret = asn1_oid_decode (&asn1, &variable_oid,
1096 &variable_oid_length, &length);
1097 if (ret != ASN1_ERR_NOERROR) {
1098 dissect_snmp_parse_error(pd, offset, fd, tree,
1099 "variable binding OID", ret);
1102 sequence_length += length;
1105 format_oid(oid_string, variable_oid,
1106 variable_oid_length);
1108 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1109 sprint_objid(vb_oid_string, variable_oid,
1110 variable_oid_length);
1111 proto_tree_add_text(snmp_tree, offset, sequence_length,
1112 "Object identifier %d: %s (%s)", vb_index,
1113 oid_string, vb_oid_string);
1116 proto_tree_add_text(snmp_tree, offset, sequence_length,
1117 "Object identifier %d: %s", vb_index,
1121 offset += sequence_length;
1122 variable_bindings_length -= sequence_length;
1124 /* Parse the variable's value */
1125 ret = snmp_variable_decode(snmp_tree, variable_oid,
1126 variable_oid_length, &asn1, offset, &length);
1127 if (ret != ASN1_ERR_NOERROR) {
1128 dissect_snmp_parse_error(pd, offset, fd, tree,
1133 variable_bindings_length -= length;
1138 dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1140 dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp);
1144 proto_register_snmp(void)
1146 /* static hf_register_info hf[] = {
1148 { "Name", "snmp.abbreviation", TYPE, VALS_POINTER }},
1150 static gint *ett[] = {
1154 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1155 /* UCD or CMU SNMP */
1157 #ifdef HAVE_UCD_SNMP_SNMP_H
1158 snmp_set_full_objid(TRUE);
1161 proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp");
1162 /* proto_register_field_array(proto_snmp, hf, array_length(hf));*/
1163 proto_register_subtree_array(ett, array_length(ett));