2 * Routines for SNMP (simple network management protocol)
5 * $Id: packet-snmp.c,v 1.23 2000/01/07 22:05:39 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 * XXX - for now, we assume all versions of UCD SNMP have it.
70 # define HAVE_SPRINT_VALUE
73 * Define values "sprint_value()" expects.
75 # define VALTYPE_INTEGER ASN_INTEGER
76 # define VALTYPE_COUNTER ASN_COUNTER
77 # define VALTYPE_GAUGE ASN_GAUGE
78 # define VALTYPE_TIMETICKS ASN_TIMETICKS
79 # define VALTYPE_STRING ASN_OCTET_STR
80 # define VALTYPE_IPADDR ASN_IPADDRESS
81 # define VALTYPE_OPAQUE ASN_OPAQUE
82 # define VALTYPE_NSAP ASN_NSAP
83 # define VALTYPE_OBJECTID ASN_OBJECT_ID
84 # define VALTYPE_BITSTR ASN_BIT_STR
85 # define VALTYPE_COUNTER64 ASN_COUNTER64
86 # elif defined(HAVE_SNMP_SNMP_H)
90 # include <snmp/snmp.h>
93 * Some older versions of CMU SNMP may lack these values (e.g., the
94 * "libsnmp3.6" package for Debian, which is based on some old
95 * CMU SNMP, perhaps 1.0); for now, we assume they also lack
99 # define HAVE_SPRINT_VALUE
101 * Define values "sprint_value()" expects.
103 # define VALTYPE_INTEGER SMI_INTEGER
104 # define VALTYPE_COUNTER SMI_COUNTER32
105 # define VALTYPE_GAUGE SMI_GAUGE32
106 # define VALTYPE_TIMETICKS SMI_TIMETICKS
107 # define VALTYPE_STRING SMI_STRING
108 # define VALTYPE_IPADDR SMI_IPADDRESS
109 # define VALTYPE_OPAQUE SMI_OPAQUE
110 # define VALTYPE_NSAP SMI_STRING
111 # define VALTYPE_OBJECTID SMI_OBJID
112 # define VALTYPE_BITSTR ASN_BIT_STR
113 # define VALTYPE_COUNTER64 SMI_COUNTER64
116 * Now undo all the definitions they "helpfully" gave us, so we don't get
117 * complaints about redefining them.
119 * Why, oh why, is there no library that provides code to
123 * 2) translate object IDs into names;
125 * 3) let you find out, for a given object ID, what the type, enum
126 * values, display hint, etc. are;
128 * in a *simple* fashion, without assuming that your code is part of an
129 * SNMP agent or client that wants a pile of definitions of PDU types,
130 * etc.? Is it just that 99 44/100% of the code that uses an SNMP library
131 * *is* part of an agent or client, and really *does* need that stuff,
132 * and *doesn't* need the interfaces we want?
134 # undef SNMP_ERR_NOERROR
135 # undef SNMP_ERR_TOOBIG
136 # undef SNMP_ERR_NOSUCHNAME
137 # undef SNMP_ERR_BADVALUE
138 # undef SNMP_ERR_READONLY
139 # undef SNMP_ERR_NOACCESS
140 # undef SNMP_ERR_WRONGTYPE
141 # undef SNMP_ERR_WRONGLENGTH
142 # undef SNMP_ERR_WRONGENCODING
143 # undef SNMP_ERR_WRONGVALUE
144 # undef SNMP_ERR_NOCREATION
145 # undef SNMP_ERR_INCONSISTENTVALUE
146 # undef SNMP_ERR_RESOURCEUNAVAILABLE
147 # undef SNMP_ERR_COMMITFAILED
148 # undef SNMP_ERR_UNDOFAILED
149 # undef SNMP_ERR_AUTHORIZATIONERROR
150 # undef SNMP_ERR_NOTWRITABLE
151 # undef SNMP_ERR_INCONSISTENTNAME
152 # undef SNMP_TRAP_COLDSTART
153 # undef SNMP_TRAP_WARMSTART
154 # undef SNMP_TRAP_LINKDOWN
155 # undef SNMP_TRAP_LINKUP
156 # undef SNMP_TRAP_EGPNEIGHBORLOSS
157 # undef SNMP_TRAP_ENTERPRISESPECIFIC
163 #include "packet-snmp.h"
165 static int proto_snmp = -1;
167 static gint ett_snmp = -1;
169 /* Protocol version numbers */
170 #define SNMP_VERSION_1 0
171 #define SNMP_VERSION_2c 1
172 #define SNMP_VERSION_2u 2
173 #define SNMP_VERSION_3 3
175 static const value_string versions[] = {
176 { SNMP_VERSION_1, "1" },
177 { SNMP_VERSION_2c, "2C" },
178 { SNMP_VERSION_2u, "2U" },
179 { SNMP_VERSION_3, "3" },
184 #define SNMP_MSG_GET 0
185 #define SNMP_MSG_GETNEXT 1
186 #define SNMP_MSG_RESPONSE 2
187 #define SNMP_MSG_SET 3
188 #define SNMP_MSG_TRAP 4
190 #define SNMP_MSG_GETBULK 5
191 #define SNMP_MSG_INFORM 6
192 #define SNMP_MSG_TRAP2 7
193 #define SNMP_MSG_REPORT 8
195 static const value_string pdu_types[] = {
196 { SNMP_MSG_GET, "GET" },
197 { SNMP_MSG_GETNEXT, "GET-NEXT" },
198 { SNMP_MSG_SET, "SET" },
199 { SNMP_MSG_RESPONSE, "RESPONSE" },
200 { SNMP_MSG_TRAP, "TRAP-V1" },
201 { SNMP_MSG_GETBULK, "GETBULK" },
202 { SNMP_MSG_INFORM, "INFORM" },
203 { SNMP_MSG_TRAP2, "TRAP-V2" },
204 { SNMP_MSG_REPORT, "REPORT" },
208 /* Error status values */
209 #define SNMP_ERR_NOERROR 0
210 #define SNMP_ERR_TOOBIG 1
211 #define SNMP_ERR_NOSUCHNAME 2
212 #define SNMP_ERR_BADVALUE 3
213 #define SNMP_ERR_READONLY 4
214 #define SNMP_ERR_GENERROR 5
216 #define SNMP_ERR_NOACCESS 6
217 #define SNMP_ERR_WRONGTYPE 7
218 #define SNMP_ERR_WRONGLENGTH 8
219 #define SNMP_ERR_WRONGENCODING 9
220 #define SNMP_ERR_WRONGVALUE 10
221 #define SNMP_ERR_NOCREATION 11
222 #define SNMP_ERR_INCONSISTENTVALUE 12
223 #define SNMP_ERR_RESOURCEUNAVAILABLE 13
224 #define SNMP_ERR_COMMITFAILED 14
225 #define SNMP_ERR_UNDOFAILED 15
226 #define SNMP_ERR_AUTHORIZATIONERROR 16
227 #define SNMP_ERR_NOTWRITABLE 17
228 #define SNMP_ERR_INCONSISTENTNAME 18
230 static const value_string error_statuses[] = {
231 { SNMP_ERR_NOERROR, "NO ERROR" },
232 { SNMP_ERR_TOOBIG, "TOOBIG" },
233 { SNMP_ERR_NOSUCHNAME, "NO SUCH NAME" },
234 { SNMP_ERR_BADVALUE, "BAD VALUE" },
235 { SNMP_ERR_READONLY, "READ ONLY" },
236 { SNMP_ERR_GENERROR, "GENERIC ERROR" },
237 { SNMP_ERR_NOACCESS, "NO ACCESS" },
238 { SNMP_ERR_WRONGTYPE, "WRONG TYPE" },
239 { SNMP_ERR_WRONGLENGTH, "WRONG LENGTH" },
240 { SNMP_ERR_WRONGENCODING, "WRONG ENCODING" },
241 { SNMP_ERR_WRONGVALUE, "WRONG VALUE" },
242 { SNMP_ERR_NOCREATION, "NO CREATION" },
243 { SNMP_ERR_INCONSISTENTVALUE, "INCONSISTENT VALUE" },
244 { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
245 { SNMP_ERR_COMMITFAILED, "COMMIT FAILED" },
246 { SNMP_ERR_UNDOFAILED, "UNDO FAILED" },
247 { SNMP_ERR_AUTHORIZATIONERROR, "AUTHORIZATION ERROR" },
248 { SNMP_ERR_NOTWRITABLE, "NOT WRITABLE" },
249 { SNMP_ERR_INCONSISTENTNAME, "INCONSISTENT NAME" },
253 /* General SNMP V1 Traps */
255 #define SNMP_TRAP_COLDSTART 0
256 #define SNMP_TRAP_WARMSTART 1
257 #define SNMP_TRAP_LINKDOWN 2
258 #define SNMP_TRAP_LINKUP 3
259 #define SNMP_TRAP_AUTHFAIL 4
260 #define SNMP_TRAP_EGPNEIGHBORLOSS 5
261 #define SNMP_TRAP_ENTERPRISESPECIFIC 6
263 static const value_string trap_types[] = {
264 { SNMP_TRAP_COLDSTART, "COLD START" },
265 { SNMP_TRAP_WARMSTART, "WARM START" },
266 { SNMP_TRAP_LINKDOWN, "LINK DOWN" },
267 { SNMP_TRAP_LINKUP, "LINK UP" },
268 { SNMP_TRAP_AUTHFAIL, "AUTHENTICATION FAILED" },
269 { SNMP_TRAP_EGPNEIGHBORLOSS, "EGP NEIGHBORLOSS" },
270 { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
276 #define SNMP_IPA 0 /* IP Address */
277 #define SNMP_CNT 1 /* Counter (Counter32) */
278 #define SNMP_GGE 2 /* Gauge (Gauge32) */
279 #define SNMP_TIT 3 /* TimeTicks */
280 #define SNMP_OPQ 4 /* Opaque */
281 #define SNMP_NSP 5 /* NsapAddress */
282 #define SNMP_C64 6 /* Counter64 */
283 #define SNMP_U32 7 /* Uinteger32 */
292 #define SNMP_INTEGER 1 /* l */
293 #define SNMP_OCTETSTR 2 /* c */
294 #define SNMP_DISPLAYSTR 2 /* c */
295 #define SNMP_OBJECTID 3 /* ul */
296 #define SNMP_IPADDR 4 /* uc */
297 #define SNMP_COUNTER 5 /* ul */
298 #define SNMP_GAUGE 6 /* ul */
299 #define SNMP_TIMETICKS 7 /* ul */
300 #define SNMP_OPAQUE 8 /* c */
302 /* additional SNMPv2 Types */
304 #define SNMP_UINTEGER 5 /* ul */
305 #define SNMP_BITSTR 9 /* uc */
306 #define SNMP_NSAP 10 /* uc */
307 #define SNMP_COUNTER64 11 /* ul */
308 #define SNMP_NOSUCHOBJECT 12
309 #define SNMP_NOSUCHINSTANCE 13
310 #define SNMP_ENDOFMIBVIEW 14
312 typedef struct _SNMP_CNV SNMP_CNV;
322 static SNMP_CNV SnmpCnv [] =
324 {ASN1_UNI, ASN1_NUL, SNMP_NULL, "NULL"},
325 {ASN1_UNI, ASN1_INT, SNMP_INTEGER, "INTEGER"},
326 {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR, "OCTET STRING"},
327 {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID, "OBJECTID"},
328 {ASN1_APL, SNMP_IPA, SNMP_IPADDR, "IPADDR"},
329 {ASN1_APL, SNMP_CNT, SNMP_COUNTER, "COUNTER"}, /* Counter32 */
330 {ASN1_APL, SNMP_GGE, SNMP_GAUGE, "GAUGE"}, /* Gauge32 == Unsigned32 */
331 {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
332 {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE, "OPAQUE"},
334 /* SNMPv2 data types and errors */
336 {ASN1_UNI, ASN1_BTS, SNMP_BITSTR, "BITSTR"},
337 {ASN1_APL, SNMP_C64, SNMP_COUNTER64, "COUNTER64"},
338 {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT, "NOSUCHOBJECT"},
339 {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
340 {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW, "ENDOFMIBVIEW"},
345 * NAME: g_snmp_tag_cls2syntax
346 * SYNOPSIS: gboolean g_snmp_tag_cls2syntax
352 * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
353 * See SnmpCnv for conversion.
354 * RETURNS: name on success, NULL on failure
358 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
363 while (cnv->syntax != -1)
365 if (cnv->tag == tag && cnv->class == cls)
367 *syntax = cnv->syntax;
376 dissect_snmp_parse_error(const u_char *pd, int offset, frame_data *fd,
377 proto_tree *tree, const char *field_name, int ret)
381 if (check_col(fd, COL_INFO)) {
385 errstr = "Ran out of data";
388 case ASN1_ERR_EOC_MISMATCH:
389 errstr = "EOC mismatch";
392 case ASN1_ERR_WRONG_TYPE:
393 errstr = "Wrong type for that item";
396 case ASN1_ERR_LENGTH_NOT_DEFINITE:
397 errstr = "Length was indefinite";
400 case ASN1_ERR_LENGTH_MISMATCH:
401 errstr = "Length mismatch";
404 case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
405 errstr = "Wrong length for that item's type";
409 errstr = "Unknown error";
412 col_add_fstr(fd, COL_INFO,
413 "ERROR: Couldn't parse %s: %s", field_name, errstr);
416 dissect_data(pd, offset, fd, tree);
420 dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
421 proto_tree *tree, const char *message)
423 if (check_col(fd, COL_INFO))
424 col_add_str(fd, COL_INFO, message);
426 dissect_data(pd, offset, fd, tree);
430 format_oid(gchar *buf, subid_t *oid, guint oid_length)
435 len = sprintf(buf, "%lu", (unsigned long)oid[0]);
437 for (i = 1; i < oid_length;i++) {
438 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
443 #ifdef HAVE_SPRINT_VALUE
445 format_value(gchar *buf, struct variable_list *variable, subid_t *variable_oid,
446 guint variable_oid_length, gushort vb_type, guint vb_length)
448 variable->next_variable = NULL;
449 variable->name = variable_oid;
450 variable->name_length = variable_oid_length;
454 variable->type = VALTYPE_INTEGER;
458 variable->type = VALTYPE_COUNTER;
462 variable->type = VALTYPE_GAUGE;
466 variable->type = VALTYPE_TIMETICKS;
470 variable->type = VALTYPE_STRING;
474 variable->type = VALTYPE_IPADDR;
478 variable->type = VALTYPE_OPAQUE;
482 variable->type = VALTYPE_NSAP;
486 variable->type = VALTYPE_OBJECTID;
490 variable->type = VALTYPE_BITSTR;
494 variable->type = VALTYPE_COUNTER64;
497 variable->val_len = vb_length;
498 sprint_value(buf, variable_oid, variable_oid_length, variable);
503 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
504 guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp)
515 gint32 vb_integer_value;
516 guint32 vb_uinteger_value;
518 guint8 *vb_octet_string;
523 gchar vb_display_string[MAX_STRING_LEN]; /* TBC */
525 #ifdef HAVE_SPRINT_VALUE
526 struct variable_list variable;
527 #if defined(HAVE_UCD_SNMP_SNMP_H)
530 #else /* HAVE_SPRINT_VALUE */
534 #endif /* HAVE_SPRINT_VALUE */
536 /* parse the type of the object */
537 start = asn1->pointer;
538 ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
539 if (ret != ASN1_ERR_NOERROR)
542 return ASN1_ERR_LENGTH_NOT_DEFINITE;
544 /* Convert the class, constructed flag, and tag to a type. */
545 vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
546 if (vb_type_name == NULL) {
549 * Dissect the value as an opaque string of octets.
551 vb_type_name = "unsupported type";
552 vb_type = SNMP_OPAQUE;
555 /* parse the value */
559 ret = asn1_int32_value_decode(asn1, vb_length,
561 if (ret != ASN1_ERR_NOERROR)
563 length = asn1->pointer - start;
565 #ifdef HAVE_SPRINT_VALUE
566 #if defined(HAVE_UCD_SNMP_SNMP_H)
567 value = vb_integer_value;
568 variable.val.integer = &value;
569 #elif defined(HAVE_SNMP_SNMP_H)
570 variable.val.integer = &vb_integer_value;
572 format_value(vb_display_string, &variable,
573 variable_oid, variable_oid_length, vb_type,
575 proto_tree_add_text(snmp_tree, offset, length,
576 "Value: %s", vb_display_string);
578 proto_tree_add_text(snmp_tree, offset, length,
579 "Value: %s: %d (%#x)", vb_type_name,
580 vb_integer_value, vb_integer_value);
588 ret = asn1_uint32_value_decode(asn1, vb_length,
590 if (ret != ASN1_ERR_NOERROR)
592 length = asn1->pointer - start;
594 #ifdef HAVE_SPRINT_VALUE
595 #if defined(HAVE_UCD_SNMP_SNMP_H)
596 value = vb_uinteger_value;
597 variable.val.integer = &value;
598 #elif defined(HAVE_SNMP_SNMP_H)
599 variable.val.integer = &vb_uinteger_value;
601 format_value(vb_display_string, &variable,
602 variable_oid, variable_oid_length, vb_type,
604 proto_tree_add_text(snmp_tree, offset, length,
605 "Value: %s", vb_display_string);
607 proto_tree_add_text(snmp_tree, offset, length,
608 "Value: %s: %u (%#x)", vb_type_name,
609 vb_uinteger_value, vb_uinteger_value);
620 ret = asn1_octet_string_value_decode (asn1, vb_length,
622 if (ret != ASN1_ERR_NOERROR)
624 length = asn1->pointer - start;
626 #ifdef HAVE_SPRINT_VALUE
627 variable.val.string = vb_octet_string;
628 format_value(vb_display_string, &variable,
629 variable_oid, variable_oid_length, vb_type,
631 proto_tree_add_text(snmp_tree, offset, length,
632 "Value: %s", vb_display_string);
635 * If some characters are not printable, display
636 * the string as bytes.
638 for (i = 0; i < vb_length; i++) {
639 if (!(isprint(vb_octet_string[i])
640 || isspace(vb_octet_string[i])))
645 * We stopped, due to a non-printable
646 * character, before we got to the end
649 buf = &vb_display_string[0];
650 len = sprintf(buf, "%03u", vb_octet_string[0]);
652 for (i = 1; i < vb_length; i++) {
653 len = sprintf(buf, ".%03u",
657 proto_tree_add_text(snmp_tree, offset, length,
658 "Value: %s: %s", vb_type_name,
661 proto_tree_add_text(snmp_tree, offset, length,
662 "Value: %s: %.*s", vb_type_name, vb_length,
667 g_free(vb_octet_string);
671 ret = asn1_null_decode (asn1, vb_length);
672 if (ret != ASN1_ERR_NOERROR)
674 length = asn1->pointer - start;
676 proto_tree_add_text(snmp_tree, offset, length,
677 "Value: %s", vb_type_name);
682 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
684 if (ret != ASN1_ERR_NOERROR)
686 length = asn1->pointer - start;
688 #ifdef HAVE_SPRINT_VALUE
689 variable.val.objid = vb_oid;
690 format_value(vb_display_string, &variable,
691 variable_oid, variable_oid_length, vb_type,
692 vb_length*sizeof (subid_t));
693 proto_tree_add_text(snmp_tree, offset, length,
694 "Value: %s", vb_display_string);
696 format_oid(vb_display_string, vb_oid, vb_oid_length);
697 proto_tree_add_text(snmp_tree, offset, length,
698 "Value: %s: %s", vb_type_name, vb_display_string);
704 case SNMP_NOSUCHOBJECT:
705 length = asn1->pointer - start;
707 proto_tree_add_text(snmp_tree, offset, length,
708 "Value: %s: no such object", vb_type_name);
712 case SNMP_NOSUCHINSTANCE:
713 length = asn1->pointer - start;
715 proto_tree_add_text(snmp_tree, offset, length,
716 "Value: %s: no such instance", vb_type_name);
720 case SNMP_ENDOFMIBVIEW:
721 length = asn1->pointer - start;
723 proto_tree_add_text(snmp_tree, offset, length,
724 "Value: %s: end of mib view", vb_type_name);
729 g_assert_not_reached();
730 return ASN1_ERR_WRONG_TYPE;
733 return ASN1_ERR_NOERROR;
737 dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
738 proto_tree *tree, char *proto_name, int proto, gint ett)
744 guint sequence_length;
746 guint message_length;
751 int community_length;
754 char *pdu_type_string;
759 guint32 error_status;
764 guint enterprise_length;
766 guint8 *agent_address;
767 guint agent_address_length;
771 guint32 specific_type;
774 guint timestamp_length;
776 gchar oid_string[MAX_STRING_LEN]; /* TBC */
778 guint variable_bindings_length;
781 guint variable_length;
782 subid_t *variable_oid;
783 guint variable_oid_length;
784 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
785 gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
788 proto_tree *snmp_tree = NULL;
789 proto_item *item = NULL;
793 if (check_col(fd, COL_PROTOCOL))
794 col_add_str(fd, COL_PROTOCOL, proto_name);
797 item = proto_tree_add_item(tree, proto, offset, END_OF_FRAME, NULL);
798 snmp_tree = proto_item_add_subtree(item, ett);
801 /* NOTE: we have to parse the message piece by piece, since the
802 * capture length may be less than the message length: a 'global'
803 * parsing is likely to fail.
805 /* parse the SNMP header */
806 asn1_open(&asn1, &pd[offset], END_OF_FRAME);
807 ret = asn1_sequence_decode(&asn1, &message_length, &length);
808 if (ret != ASN1_ERR_NOERROR) {
809 dissect_snmp_parse_error(pd, offset, fd, tree,
810 "message header", ret);
815 ret = asn1_uint32_decode (&asn1, &version, &length);
816 if (ret != ASN1_ERR_NOERROR) {
817 dissect_snmp_parse_error(pd, offset, fd, tree, "version number",
822 proto_tree_add_text(snmp_tree, offset, length,
824 val_to_str(version, versions, "Unknown version %#x"));
828 ret = asn1_octet_string_decode (&asn1, &community, &community_length,
830 if (ret != ASN1_ERR_NOERROR) {
831 dissect_snmp_parse_error(pd, offset, fd, tree, "community",
836 proto_tree_add_text(snmp_tree, offset, length,
837 "Community: %.*s", community_length, community);
845 case SNMP_VERSION_2c:
846 case SNMP_VERSION_2u:
851 dissect_snmp_error(pd, offset, fd, tree,
852 "PDU for unknown version of SNMP");
856 start = asn1.pointer;
857 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
859 if (ret != ASN1_ERR_NOERROR) {
860 dissect_snmp_parse_error(pd, offset, fd, tree,
864 if (cls != ASN1_CTX || con != ASN1_CON) {
865 dissect_snmp_parse_error(pd, offset, fd, tree,
866 "PDU type", ASN1_ERR_WRONG_TYPE);
869 pdu_type_string = val_to_str(pdu_type, pdu_types,
870 "Unknown PDU type %#x");
871 if (check_col(fd, COL_INFO))
872 col_add_str(fd, COL_INFO, pdu_type_string);
873 length = asn1.pointer - start;
875 proto_tree_add_text(snmp_tree, offset, length,
876 "PDU type: %s", pdu_type_string);
880 /* get the fields in the PDU preceeding the variable-bindings sequence */
884 case SNMP_MSG_GETNEXT:
885 case SNMP_MSG_RESPONSE:
887 /* XXX - are they like V1 non-trap PDUs? */
888 case SNMP_MSG_GETBULK:
889 case SNMP_MSG_INFORM:
891 ret = asn1_uint32_decode (&asn1, &request_id, &length);
892 if (ret != ASN1_ERR_NOERROR) {
893 dissect_snmp_parse_error(pd, offset, fd, tree,
898 proto_tree_add_text(snmp_tree, offset, length,
899 "Request Id: %#x", request_id);
903 /* error status (getbulk non-repeaters) */
904 ret = asn1_uint32_decode (&asn1, &error_status, &length);
905 if (ret != ASN1_ERR_NOERROR) {
906 dissect_snmp_parse_error(pd, offset, fd, tree,
907 "error status", ret);
911 proto_tree_add_text(snmp_tree, offset, length,
913 val_to_str(error_status, error_statuses,
918 /* error index (getbulk max-repetitions) */
919 ret = asn1_uint32_decode (&asn1, &error_index, &length);
920 if (ret != ASN1_ERR_NOERROR) {
921 dissect_snmp_parse_error(pd, offset, fd, tree,
926 proto_tree_add_text(snmp_tree, offset, length,
927 "Error Index: %u", error_index);
934 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
936 if (ret != ASN1_ERR_NOERROR) {
937 dissect_snmp_parse_error(pd, offset, fd, tree,
938 "enterprise OID", ret);
942 format_oid(oid_string, enterprise, enterprise_length);
943 proto_tree_add_text(snmp_tree, offset, length,
944 "Enterprise: %s", oid_string);
950 start = asn1.pointer;
951 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
952 &def, &agent_address_length);
953 if (ret != ASN1_ERR_NOERROR) {
954 dissect_snmp_parse_error(pd, offset, fd, tree,
955 "agent address", ret);
958 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
959 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
960 /* GXSNMP 0.0.15 says the latter is "needed for
962 dissect_snmp_parse_error(pd, offset, fd, tree,
963 "agent_address", ASN1_ERR_WRONG_TYPE);
966 if (agent_address_length != 4) {
967 dissect_snmp_parse_error(pd, offset, fd, tree,
968 "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
971 ret = asn1_octet_string_value_decode (&asn1,
972 agent_address_length, &agent_address);
973 if (ret != ASN1_ERR_NOERROR) {
974 dissect_snmp_parse_error(pd, offset, fd, tree,
975 "agent address", ret);
978 length = asn1.pointer - start;
980 proto_tree_add_text(snmp_tree, offset, agent_address_length,
981 "Agent address: %s", ip_to_str(agent_address));
983 g_free(agent_address);
986 /* generic trap type */
987 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
988 if (ret != ASN1_ERR_NOERROR) {
989 dissect_snmp_parse_error(pd, offset, fd, tree,
990 "generic trap type", ret);
994 proto_tree_add_text(snmp_tree, offset, length,
996 val_to_str(trap_type, trap_types, "Unknown (%u)"));
1000 /* specific trap type */
1001 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1002 if (ret != ASN1_ERR_NOERROR) {
1003 dissect_snmp_parse_error(pd, offset, fd, tree,
1004 "specific trap type", ret);
1008 proto_tree_add_text(snmp_tree, offset, length,
1009 "Specific trap type: %u (%#x)",
1010 specific_type, specific_type);
1015 start = asn1.pointer;
1016 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1017 &def, ×tamp_length);
1018 if (ret != ASN1_ERR_NOERROR) {
1019 dissect_snmp_parse_error(pd, offset, fd, tree,
1023 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1024 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1025 dissect_snmp_parse_error(pd, offset, fd, tree,
1026 "timestamp", ASN1_ERR_WRONG_TYPE);
1029 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1031 if (ret != ASN1_ERR_NOERROR) {
1032 dissect_snmp_parse_error(pd, offset, fd, tree,
1036 length = asn1.pointer - start;
1038 proto_tree_add_text(snmp_tree, offset, length,
1039 "Timestamp: %u", timestamp);
1045 /* variable bindings */
1046 /* get header for variable-bindings sequence */
1047 ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1048 if (ret != ASN1_ERR_NOERROR) {
1049 dissect_snmp_parse_error(pd, offset, fd, tree,
1050 "variable bindings header", ret);
1055 /* loop on variable bindings */
1057 while (variable_bindings_length > 0) {
1059 sequence_length = 0;
1062 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1063 if (ret != ASN1_ERR_NOERROR) {
1064 dissect_snmp_parse_error(pd, offset, fd, tree,
1065 "variable binding header", ret);
1068 sequence_length += length;
1070 /* parse object identifier */
1071 ret = asn1_oid_decode (&asn1, &variable_oid,
1072 &variable_oid_length, &length);
1073 if (ret != ASN1_ERR_NOERROR) {
1074 dissect_snmp_parse_error(pd, offset, fd, tree,
1075 "variable binding OID", ret);
1078 sequence_length += length;
1081 format_oid(oid_string, variable_oid,
1082 variable_oid_length);
1084 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1085 sprint_objid(vb_oid_string, variable_oid,
1086 variable_oid_length);
1087 proto_tree_add_text(snmp_tree, offset, sequence_length,
1088 "Object identifier %d: %s (%s)", vb_index,
1089 oid_string, vb_oid_string);
1092 proto_tree_add_text(snmp_tree, offset, sequence_length,
1093 "Object identifier %d: %s", vb_index,
1097 offset += sequence_length;
1098 variable_bindings_length -= sequence_length;
1100 /* Parse the variable's value */
1101 ret = snmp_variable_decode(snmp_tree, variable_oid,
1102 variable_oid_length, &asn1, offset, &length);
1103 if (ret != ASN1_ERR_NOERROR) {
1104 dissect_snmp_parse_error(pd, offset, fd, tree,
1109 variable_bindings_length -= length;
1114 dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1116 dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp);
1120 proto_register_snmp(void)
1122 /* static hf_register_info hf[] = {
1124 { "Name", "snmp.abbreviation", TYPE, VALS_POINTER }},
1126 static gint *ett[] = {
1130 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1131 /* UCD or CMU SNMP */
1133 #ifdef HAVE_UCD_SNMP_SNMP_H
1134 snmp_set_full_objid(TRUE);
1137 proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp");
1138 /* proto_register_field_array(proto_snmp, hf, array_length(hf));*/
1139 proto_register_subtree_array(ett, array_length(ett));