Note that non-GNU "make"s appear not to be able to build Ethereal, and
[metze/wireshark/wip.git] / packet-snmp.c
1 /* packet-snmp.c
2  * Routines for SNMP (simple network management protocol)
3  * D.Jorand (c) 1998
4  *
5  * $Id: packet-snmp.c,v 1.3 1999/06/12 04:17:19 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@unicom.net>
9  * Copyright 1998 Didier Jorand
10  *
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31
32 #if defined(HAVE_UCD_SNMP_SNMP_H)
33   #define WITH_SNMP_UCD 1
34 #elif defined(HAVE_SNMP_SNMP_H)
35   #define WITH_SNMP_CMU 1
36 #endif
37
38 #if defined(WITH_SNMP_CMU) || defined(WITH_SNMP_UCD)
39
40 #include <stdio.h>
41 #include <string.h>
42 #include <ctype.h>
43
44 #ifdef HAVE_SYS_TYPES_H
45 # include <sys/types.h>
46 #endif
47
48 #ifdef HAVE_NETINET_IN_H
49 # include <netinet/in.h>
50 #endif
51
52 #include <glib.h>
53 #include "packet.h"
54
55 #define in_addr_t u_int
56
57 #ifdef WITH_SNMP_UCD
58 /* should be defined only if supported in ucd-snmp */
59 #define OPAQUE_SPECIAL_TYPES 1
60 #include <ucd-snmp/asn1.h>
61 #include <ucd-snmp/snmp.h>
62 #include <ucd-snmp/snmp_api.h>
63 #include <ucd-snmp/snmp_impl.h>
64 #include <ucd-snmp/mib.h>
65
66 typedef long SNMP_INT;
67 typedef unsigned  long SNMP_UINT;
68 #define OID_FORMAT_STRING "%ld"
69 #define OID_FORMAT_STRING1 ".%ld"
70
71 #endif
72 #ifdef WITH_SNMP_CMU
73 #include <snmp/snmp.h>
74 #include <snmp/snmp_impl.h>
75
76
77 #ifndef MAX_NAME_LEN
78 #define MAX_NAME_LEN SNMP_MAX_LEN
79 #endif
80
81 #define SNMP_MSG_GET GET_REQ_MSG
82 #define SNMP_MSG_GETNEXT GETNEXT_REQ_MSG
83 #define SNMP_MSG_RESPONSE GET_RSP_MSG
84 #define SNMP_MSG_SET SET_REQ_MSG   
85 #define SNMP_MSG_TRAP TRP_REQ_MSG
86
87 #ifdef GETBULK_REQ_MSG
88 #define SNMP_MSG_GETBULK GETBULK_REQ_MSG
89 #else
90 #define SNMP_MSG_GETBULK SNMP_PDU_GETBULK
91 #endif
92
93 #ifdef INFORM_REQ_MSG
94 #define SNMP_MSG_INFORM INFORM_REQ_MSG
95 #else
96 #define SNMP_MSG_INFORM SNMP_PDU_INFORM
97 #endif
98
99 #ifdef TRP2_REQ_MSG
100 #define SNMP_MSG_TRAP2 TRP2_REQ_MSG
101 #else
102 #define SNMP_MSG_TRAP2 SNMP_PDU_V2TRAP
103 #endif
104
105 #ifdef REPORT_MSG
106 #define SNMP_MSG_REPORT REPORT_MSG
107 #else
108 #define SNMP_MSG_REPORT SNMP_PDU_REPORT
109 #endif
110
111
112 #ifndef SNMP_VERSION_2c
113 #define SNMP_VERSION_2c 1
114 #endif
115 #ifndef SNMP_VERSION_2u
116 #define SNMP_VERSION_2u 2
117 #endif
118 #ifndef SNMP_VERSION_3
119 #define SNMP_VERSION_3 3
120 #endif
121
122 #ifdef SNMP_TRAP_AUTHENTICATIONFAILURE
123 #define SNMP_TRAP_AUTHFAIL SNMP_TRAP_AUTHENTICATIONFAILURE
124 #endif
125
126 #ifndef COMMUNITY_MAX_LEN
127 #define COMMUNITY_MAX_LEN 256
128 #endif
129
130 #ifndef ASN_INTEGER
131 #define ASN_INTEGER SMI_INTEGER
132 #endif
133 #ifndef ASN_OCTET_STR
134 #define ASN_OCTET_STR SMI_STRING
135 #endif
136 #ifndef ASN_OBJECT_ID
137 #define ASN_OBJECT_ID SMI_OBJID
138 #endif
139 #ifndef ASN_NULL
140 #define ASN_NULL SMI_NULLOBJ
141 #endif
142
143 #ifndef ASN_IPADDRESS
144         #ifdef IPADDRESS
145         #define ASN_IPADDRESS IPADDRESS
146         #else
147         #define ASN_IPADDRESS SMI_IPADDRESS
148         #endif
149 #endif
150
151 #ifndef ASN_COUNTER
152         #ifdef COUNTER
153         #define ASN_COUNTER COUNTER
154         #else
155         #define ASN_COUNTER SMI_COUNTER32
156         #endif
157 #endif
158
159 #ifndef ASN_GAUGE
160         #ifdef GAUGE
161         #define ASN_GAUGE GAUGE
162         #else
163         #define ASN_GAUGE SMI_GAUGE32
164         #endif
165 #endif
166
167 #ifndef ASN_TIMETICKS
168         #ifdef TIMETICKS
169         #define ASN_TIMETICKS TIMETICKS
170         #else
171         #define ASN_TIMETICKS SMI_TIMETICKS
172         #endif
173 #endif
174
175 #ifndef ASN_OPAQUE
176         #ifdef OPAQUE
177         #define ASN_OPAQUE OPAQUE
178         #else
179         #define ASN_OPAQUE SMI_OPAQUE
180         #endif
181 #endif
182
183 #ifndef ASN_COUNTER64
184         #ifdef COUNTER64
185         #define ASN_COUNTER64 COUNTER64
186         #else
187         #define ASN_COUNTER64 SMI_COUNTER64
188         #endif
189 #endif
190
191 #ifndef ASN_UINTEGER
192 /* historic: should not be used! */
193 #define ASN_UINTEGER (ASN_APPLICATION | 7)
194 #endif
195 #ifndef ASN_NSAP
196 /* historic: should not be used! */
197 #define ASN_NSAP (ASN_APPLICATION | 5)
198 #endif
199 #ifndef SNMP_NOSUCHOBJECT
200 #define SNMP_NOSUCHOBJECT SMI_NOSUCHOBJECT
201 #endif
202 #ifndef SNMP_NOSUCHINSTANCE
203 #define SNMP_NOSUCHINSTANCE SMI_NOSUCHINSTANCE
204 #endif
205 #ifndef SNMP_ENDOFMIBVIEW
206 #define SNMP_ENDOFMIBVIEW SMI_ENDOFMIBVIEW
207 #endif
208
209
210 typedef int SNMP_INT;
211 typedef unsigned int SNMP_UINT;
212 #define OID_FORMAT_STRING "%d"
213 #define OID_FORMAT_STRING1 ".%d"
214
215 #endif
216
217 static const value_string versions[] = {
218         { SNMP_VERSION_1,       "VERSION 1" },
219         { SNMP_VERSION_2c,      "VERSION 2C" },
220         { SNMP_VERSION_2u,      "VERSION 2U" },
221         { SNMP_VERSION_3,       "VERSION 3" },
222         { 0,                    NULL },
223 };
224
225 static const value_string pdu_types[] = {
226         { SNMP_MSG_GET,         "GET" },
227         { SNMP_MSG_GETNEXT,     "GET-NEXT" },
228         { SNMP_MSG_SET,         "SET" },
229         { SNMP_MSG_RESPONSE,    "RESPONSE" },
230         { SNMP_MSG_TRAP,        "TRAP-V1" },
231         { SNMP_MSG_GETBULK,     "GETBULK" },
232         { SNMP_MSG_INFORM,      "INFORM" },
233         { SNMP_MSG_TRAP2,       "TRAP-V2" },
234         { SNMP_MSG_REPORT,      "REPORT" },
235         { 0,                    NULL }
236 };
237
238 static const value_string error_statuses[] = {
239         { SNMP_ERR_NOERROR,             "NO ERROR" },
240         { SNMP_ERR_TOOBIG,              "ERROR: TOOBIG" },
241         { SNMP_ERR_NOSUCHNAME,          "ERROR: NO SUCH NAME" },
242         { SNMP_ERR_BADVALUE,            "ERROR: BAD VALUE" },
243         { SNMP_ERR_READONLY,            "ERROR: READ ONLY" },
244         { SNMP_ERR_GENERR,              "ERROR: GENERIC ERROR" },
245         { SNMP_ERR_NOACCESS,            "ERROR: NO ACCESS" },
246         { SNMP_ERR_WRONGTYPE,           "ERROR: WRONG TYPE" },
247         { SNMP_ERR_WRONGLENGTH,         "ERROR: WRONG LENGTH" },
248         { SNMP_ERR_WRONGENCODING,       "ERROR: WRONG ENCODING" },
249         { SNMP_ERR_WRONGVALUE,          "ERROR: WRONG VALUE" },
250         { SNMP_ERR_NOCREATION,          "ERROR: NO CREATION" },
251         { SNMP_ERR_INCONSISTENTVALUE,   "ERROR: INCONSISTENT VALUE" },
252         { SNMP_ERR_RESOURCEUNAVAILABLE, "ERROR: RESOURCE UNAVAILABLE" },
253         { SNMP_ERR_COMMITFAILED,        "ERROR: COMMIT FAILED" },
254         { SNMP_ERR_UNDOFAILED,          "ERROR: UNDO FAILED" },
255         { SNMP_ERR_AUTHORIZATIONERROR,  "ERROR: AUTHORIZATION ERROR" },
256         { SNMP_ERR_NOTWRITABLE,         "ERROR: NOT WRITABLE" },
257         { SNMP_ERR_INCONSISTENTNAME,    "ERROR: INCONSISTENT NAME" },
258         { 0,                            NULL }
259 };
260
261 static const value_string trap_types[] = {
262         { SNMP_TRAP_COLDSTART,          "COLD START" },
263         { SNMP_TRAP_WARMSTART,          "WARM START" },
264         { SNMP_TRAP_LINKDOWN,           "LINK DOWN" },
265         { SNMP_TRAP_LINKUP,             "LINK UP" },
266         { SNMP_TRAP_AUTHFAIL,           "AUTHENTICATION FAILED" },
267         { SNMP_TRAP_EGPNEIGHBORLOSS,    "EGP NEIGHBORLOSS" },
268         { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
269         { 0,                            NULL }
270 };
271
272 static void
273 dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
274                    proto_tree *tree, const char *message)
275 {
276         if (check_col(fd, COL_INFO))
277                 col_add_str(fd, COL_INFO, message);
278
279         dissect_data(pd, offset, fd, tree);
280 }
281
282 void
283 dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
284 {
285         int length=fd->pkt_len-offset;
286         u_char *data, *tmp_data;
287
288         int all_length, header_length;
289         u_char type, pdu_type;
290         int pdu_type_length;
291         SNMP_INT request_id, error_status, error_index;
292         int request_id_length, error_status_length, error_index_length;
293         
294         SNMP_INT version;
295         u_char community[COMMUNITY_MAX_LEN];
296         int community_length = COMMUNITY_MAX_LEN;
297
298         oid enterprise[MAX_NAME_LEN];
299         int enterprise_length;
300         SNMP_INT trap_type, specific_type;
301         SNMP_UINT timestamp;
302         
303         int tmp_length;
304         oid vb_name[MAX_NAME_LEN];
305         int vb_name_length;
306         int vb_index;
307         u_char vb_type;
308         char vb_string[MAX_NAME_LEN*6]; /* TBC */
309         char vb_string2[2048]; /* TBC */
310         char tmp_string[12];
311         SNMP_INT vb_integer_value;
312         SNMP_UINT vb_unsigned_value;
313 #ifdef WITH_SNMP_UCD    
314         struct counter64 vb_counter64_value;
315 #endif  
316         oid vb_oid_value[MAX_NAME_LEN];
317         int vb_oid_value_length;
318         unsigned char vb_string_value[128];
319         int vb_string_value_length;
320 #ifdef WITH_SNMP_UCD    
321         float vb_float_value;
322         double vb_double_value;
323 #endif
324         
325         int i;
326
327         char *pdu_type_string;
328
329         proto_tree *snmp_tree=NULL;
330         proto_item *item=NULL;
331
332         if (check_col(fd, COL_PROTOCOL))
333                 col_add_str(fd, COL_PROTOCOL, "SNMP");
334
335         /* NOTE: we have to parse the message piece by piece, since the
336          * capture length may be less than the message length: a 'global'
337          * parsing is likely to fail.
338          */
339         
340 #ifdef WITH_SNMP_UCD    
341         /* parse the SNMP header */
342         if(NULL == asn_parse_header( &pd[offset], &length, &type)) {
343                 dissect_snmp_error(pd, offset, fd, tree,
344                         "Couldn't parse SNMP header");
345                 return;
346         }
347         
348         if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
349                 dissect_snmp_error(pd, offset, fd, tree, "Not an SNMP PDU");
350                 return;
351         }
352         
353         /* authenticates message */
354         length=fd->pkt_len-offset;
355         header_length=length;
356         data = snmp_comstr_parse(&pd[offset], &length, community, &community_length,&version);
357         if(NULL == data) {
358                 dissect_snmp_error(pd, offset, fd, tree,
359                     "Couldn't parse authentication");
360                 return;
361         }
362 #endif
363 #ifdef WITH_SNMP_CMU
364         /* initialize length variables */
365         /* length=fd->pkt_len-offset; */
366         header_length=length;   
367
368         /* parse the SNMP header */
369         data = asn_parse_header( &pd[offset], &length, &type);
370         if(NULL == data) {
371                 dissect_snmp_error(pd, offset, fd, tree,
372                         "Couldn't parse SNMP header");
373                 return;
374         }
375         
376         if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
377                 dissect_snmp_error(pd, offset, fd, tree, "Not an SNMP PDU");
378                 return;
379         }
380
381         data = asn_parse_int(data, &length, &type, &version, sizeof(SNMP_INT));
382         if(NULL == data) {
383                 dissect_snmp_error(pd, offset, fd, tree,
384                     "Couldn't parse SNMP version number");
385                 return;
386         }
387         data = asn_parse_string(data, &length, &type, community, &community_length);
388         if(NULL == data) {
389                 dissect_snmp_error(pd, offset, fd, tree,
390                     "Couldn't parse SNMP community");
391                 return;
392         }
393         community[community_length] = '\0';     
394 #endif 
395
396         header_length-=length;
397         /* printf("Community is %s, version is %d (header length is %d)\n", community, version, header_length); */
398         if(version != SNMP_VERSION_1) {
399                 dissect_snmp_error(pd, offset, fd, tree,
400                     "Non-version-1 SNMP PDU");
401                 return;
402         }
403
404         pdu_type_length=length;
405         data = asn_parse_header(data, &length, &pdu_type);
406         if (data == NULL) {
407                 dissect_snmp_error(pd, offset, fd, tree,
408                     "Couldn't parse PDU type");
409                 return;
410         }
411         pdu_type_length-=length;
412         /* printf("pdu type is %#x (length is %d)\n", type, pdu_type_length); */
413         
414         /* get the fields in the PDU preceeding the variable-bindings sequence */
415         if (pdu_type != SNMP_MSG_TRAP) {
416
417         /* request id */
418                 request_id_length=length;
419                 data = asn_parse_int(data, &length, &type, &request_id, sizeof(request_id));
420                 if (data == NULL) {
421                         dissect_snmp_error(pd, offset, fd, tree,
422                                 "Couldn't parse request ID");
423                         return;
424                 }
425                 request_id_length-=length;
426                 /* printf("request id is %#lx (length is %d)\n", request_id, request_id_length); */
427                 
428         /* error status (getbulk non-repeaters) */
429                 error_status_length=length;
430                 data = asn_parse_int(data, &length, &type, &error_status, sizeof(error_status));
431                 if (data == NULL) {
432                         dissect_snmp_error(pd, offset, fd, tree,
433                                 "Couldn't parse error status");
434                         return;
435                 }
436                 error_status_length-=length;
437
438         /* error index (getbulk max-repetitions) */
439                 error_index_length=length;
440                 data = asn_parse_int(data, &length, &type, &error_index, sizeof(error_index));
441                 if (data == NULL) {
442                         dissect_snmp_error(pd, offset, fd, tree,
443                                 "Couldn't parse error index");
444                         return;
445                 }
446                 error_index_length-=length;
447
448                 pdu_type_string = val_to_str(pdu_type, pdu_types,
449                     "Unknown PDU type %#x");
450                 if (check_col(fd, COL_INFO))
451                         col_add_str(fd, COL_INFO, pdu_type_string);
452                 if(tree) {
453                         /* all_length=header_length+pdu_type_length+request_id_length+error_status_length+error_index_length; */
454                         all_length=fd->pkt_len-offset;
455                         item = proto_tree_add_item(tree, offset, all_length, "Simple Network Management Protocol");
456                         snmp_tree = proto_tree_new();
457                         proto_item_add_subtree(item, snmp_tree, ETT_SNMP);
458                         proto_tree_add_item(snmp_tree, offset, header_length, "Community: \"%s\", Version: %s", community, val_to_str(version, versions, "Unknown version %#x"));
459                         offset+=header_length;
460                         proto_tree_add_item(snmp_tree, offset, pdu_type_length, "%s", pdu_type_string);
461                         offset+=pdu_type_length;
462                         proto_tree_add_item(snmp_tree, offset, request_id_length, "Request Id.: %#x", (unsigned int)request_id);
463                         offset+=request_id_length;
464                         proto_tree_add_item(snmp_tree, offset, error_status_length, "Error Status: %s", val_to_str(error_status, error_statuses, "Unknown (%d)"));
465                         offset+=error_status_length;
466                         proto_tree_add_item(snmp_tree, offset, error_index_length, "Error Index: %d", (int)error_index);
467                         offset+=error_index_length;
468                 } else {
469                         offset+=header_length;
470                         offset+=pdu_type_length;
471                         offset+=request_id_length;
472                         offset+=error_status_length;
473                         offset+=error_index_length;             
474                 }
475                 
476         } else {
477                 /* an SNMPv1 trap PDU */
478                 pdu_type_string = val_to_str(pdu_type, pdu_types,
479                     "Unknown PDU type %#x");
480                 if (check_col(fd, COL_INFO))
481                         col_add_str(fd, COL_INFO, pdu_type_string);
482                 if(tree) {
483                         all_length=fd->pkt_len-offset;
484                         item = proto_tree_add_item(tree, offset, all_length, "Simple Network Management Protocol");
485                         snmp_tree = proto_tree_new();
486                         proto_item_add_subtree(item, snmp_tree, ETT_SNMP);
487                         proto_tree_add_item(snmp_tree, offset, header_length, "Community: \"%s\", Version: %s", community, val_to_str(version, versions, "Unknown version %#x"));
488                         offset+=header_length;
489                         proto_tree_add_item(snmp_tree, offset, pdu_type_length, "Pdu type: %s", pdu_type_string);
490                         offset+=pdu_type_length;
491                 } else {
492                         offset+=header_length;
493                         offset+=pdu_type_length;
494                 }
495                 
496         /* enterprise */
497                 enterprise_length = MAX_NAME_LEN;
498                 tmp_length=length;
499                 data = asn_parse_objid(data, &length, &type, enterprise,  &enterprise_length);
500                 if (data == NULL) {
501                         dissect_snmp_error(pd, offset, fd, tree,
502                                 "Couldn't parse enterprise OID");
503                         return;
504                 }
505                 tmp_length-=length;
506
507                 sprintf(vb_string, OID_FORMAT_STRING, enterprise[0]);
508                 for(i=1; i<enterprise_length;i++) {
509                         sprintf(tmp_string, OID_FORMAT_STRING1, enterprise[i]);
510                         strcat(vb_string,tmp_string);
511                 }
512                 if(tree) {
513                         proto_tree_add_item(snmp_tree, offset, tmp_length, "Enterprise: %s", vb_string);
514                 }
515                 offset+=tmp_length;
516
517         /* agent address */
518                 vb_string_value_length = 4;
519                 tmp_length=length;
520                 data = asn_parse_string(data, &length, &type, vb_string_value, &vb_string_value_length);
521                 if (data == NULL) {
522                         dissect_snmp_error(pd, offset, fd, tree,
523                                 "Couldn't parse agent address");
524                         return;
525                 }
526                 tmp_length-=length;
527                 if(tree) {
528                         proto_tree_add_item(snmp_tree, offset, tmp_length, "Agent address: %d.%d.%d.%d",
529                                                          vb_string_value[0],vb_string_value[1],vb_string_value[2],vb_string_value[3]);
530                 }
531                 offset+=tmp_length;
532                 
533         /* generic trap */
534                 tmp_length=length;
535                 data = asn_parse_int(data, &length, &type, &trap_type, sizeof(trap_type));
536                 if (data == NULL) {
537                         dissect_snmp_error(pd, offset, fd, tree,
538                                 "Couldn't parse trap type");
539                         return;
540                 }
541                 tmp_length-=length;
542                 if(tree) {
543                         proto_tree_add_item(snmp_tree, offset, tmp_length, "Trap type: %s", val_to_str(trap_type, trap_types, "Unknown (%d)"));
544                 }               
545                 offset+=tmp_length;
546                 
547         /* specific trap */
548                 tmp_length=length;
549                 data = asn_parse_int(data, &length, &type, &specific_type, sizeof(specific_type));
550                 if (data == NULL) {
551                         dissect_snmp_error(pd, offset, fd, tree,
552                                 "Couldn't parse specific trap type");
553                         return;
554                 }
555                 tmp_length-=length;
556                 if(tree) {
557                         proto_tree_add_item(snmp_tree, offset, tmp_length, "Specific trap type: %ld (%#lx)", (long)specific_type, (long)specific_type);
558                 }               
559                 offset+=tmp_length;
560                 
561         /* timestamp  */
562                 tmp_length=length;
563                 data = asn_parse_unsigned_int(data, &length, &type, &timestamp, sizeof(timestamp));
564                 if (data == NULL) {
565                         dissect_snmp_error(pd, offset, fd, tree,
566                                 "Couldn't parse time stamp");
567                         return;
568                 }
569                 tmp_length-=length;
570                 if(tree) {
571                         proto_tree_add_item(snmp_tree, offset, tmp_length, "Timestamp: %lu", (unsigned long)timestamp);
572                 }               
573                 offset+=tmp_length;
574         }
575         
576         /* variable bindings */
577     /* get header for variable-bindings sequence */
578         tmp_length=length;
579         data = asn_parse_header(data, &length, &type);
580         if (data == NULL) {
581                 dissect_snmp_error(pd, offset, fd, tree,
582                         "Couldn't variable-bindings header");
583                 return;
584         }
585         tmp_length-=length;
586         if (type != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
587                 dissect_snmp_error(pd, offset, fd, tree,
588                         "Bad type for variable-bindings header");
589                 return;
590         }
591         offset+=tmp_length;
592         /* printf("VB header: offset is %d; length is %d.\n", offset, tmp_length); */
593
594         /* loop on variable bindings */
595         vb_index=0;
596         while(length>0) {
597                 vb_index++;
598                 /* printf("VB index is %d (offset=%d; length=%d).\n", vb_index, offset, length); */
599                 /* parse type */
600                 tmp_length=length;
601                 tmp_data=data;
602                 data = asn_parse_header(data, &tmp_length, &type);
603                 if (data == NULL) {
604                         dissect_snmp_error(pd, offset, fd, tree,
605                                 "Couldn't parse variable-binding header");
606                         return;
607                 }
608                 if (type != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
609                         dissect_snmp_error(pd, offset, fd, tree,
610                                 "Bad type for variable-binding header");
611                         return;
612                 }
613                 tmp_length=(int)(data-tmp_data);
614                 length-=tmp_length;
615                 offset+=tmp_length;
616                 
617                 /* parse object identifier */
618                 vb_name_length=MAX_NAME_LEN;
619                 tmp_length=length;
620                 data = asn_parse_objid(data, &length, &type, vb_name, &vb_name_length);
621                 if (data == NULL) {
622                         dissect_snmp_error(pd, offset, fd, tree,
623                                 "No object-identifier for variable-binding");
624                         return;
625                 }
626
627                 if (type != (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID)) {
628                         dissect_snmp_error(pd, offset, fd, tree,
629                                 "Bad type for variable-binding");
630                         return;
631                 }
632                 tmp_length-=length;
633
634                 if(tree) {
635                         sprintf(vb_string, OID_FORMAT_STRING, vb_name[0]);
636                         for(i=1; i<vb_name_length;i++) {
637                                 sprintf(tmp_string, OID_FORMAT_STRING1, vb_name[i]);
638                                 strcat(vb_string,tmp_string);
639                         }
640                         
641                         sprint_objid(vb_string2, vb_name, vb_name_length);
642                         
643                         proto_tree_add_item(snmp_tree, offset, tmp_length, "Object identifier %d: %s (%s)", vb_index, vb_string, vb_string2);
644                 }
645                 offset+=tmp_length;
646                                 
647                 /* parse the type of the object */
648                 tmp_length=length;
649                 if (NULL == asn_parse_header(data, &tmp_length, &vb_type)){
650                         dissect_snmp_error(pd, offset, fd, tree,
651                                 "Bad type for variable-binding value");
652                         return;
653                 }
654
655                 /* parse the value */
656                 switch(vb_type) {
657                 case ASN_NULL:
658                         tmp_length=length;
659                         data=asn_parse_null(data, &length, &type);
660                         tmp_length-=length;
661                         if (data == NULL){
662                                 dissect_snmp_error(pd, offset, fd, tree,
663                                         "Couldn't parse null value");
664                                 return;
665                         }
666                         if(tree) {
667                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: NULL");
668                         }
669                         offset+=tmp_length;
670                         break;
671                         
672                 case ASN_INTEGER:
673                         tmp_length=length;
674                         data=asn_parse_int(data,  &length, &type, &vb_integer_value, sizeof(vb_integer_value));
675                         tmp_length-=length;
676                         if (data == NULL){
677                                 dissect_snmp_error(pd, offset, fd, tree,
678                                         "Couldn't parse integer value");
679                                 return;
680                         }
681                         if(tree) {
682                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <i> %ld (%#lx)", (long)vb_integer_value, (long)vb_integer_value);
683                         }
684                         offset+=tmp_length;
685                         break;
686
687                 case ASN_COUNTER:
688                 case ASN_GAUGE:
689                 case ASN_TIMETICKS:
690                 case ASN_UINTEGER:
691                         tmp_length=length;
692                         data=asn_parse_unsigned_int(data, &length, &type, &vb_unsigned_value, sizeof(vb_unsigned_value));
693                         tmp_length-=length;
694                         if (data == NULL){
695                                 dissect_snmp_error(pd, offset, fd, tree,
696                                         "Couldn't parse unsigned value");
697                                 return;
698                         }
699                         if(tree) {
700                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <u> %lu (%#lx)", (unsigned long)vb_unsigned_value, (unsigned long)vb_unsigned_value);
701                         }
702                         offset+=tmp_length;
703                         break;
704
705 #ifdef WITH_SNMP_UCD
706                         /* only ucd support 64bits types */
707                 case ASN_COUNTER64:
708 #ifdef OPAQUE_SPECIAL_TYPES
709                 case ASN_OPAQUE_COUNTER64:
710                 case ASN_OPAQUE_U64:
711 #endif /* OPAQUE_SPECIAL_TYPES */
712                         tmp_length=length;
713                         data=asn_parse_unsigned_int64(data, &length, &type, &vb_counter64_value, sizeof(vb_counter64_value));
714                         tmp_length-=length;
715                         if (data == NULL){
716                                 dissect_snmp_error(pd, offset, fd, tree,
717                                         "Couldn't parse counter64 value");
718                                 return;
719                         }
720                         if(tree) {
721                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <i64> %lu:%lu (%#lx:%lx)",
722                                                                  vb_counter64_value.high,
723                                                                  vb_counter64_value.low,
724                                                                  vb_counter64_value.high,
725                                                                  vb_counter64_value.low);
726                         }
727                         offset+=tmp_length;
728                         break;
729 #endif /* WITH_SNMP_UCD */
730                         
731                 case ASN_OBJECT_ID:
732                         vb_oid_value_length = MAX_NAME_LEN;
733                         tmp_length=length;
734                         data=asn_parse_objid(data, &length, &type, vb_oid_value, &vb_oid_value_length);
735                         tmp_length-=length;
736                         if (data == NULL){
737                                 dissect_snmp_error(pd, offset, fd, tree,
738                                         "Couldn't parse OID value");
739                                 return;
740                         }
741                         if(tree) {
742                                 sprintf(vb_string, OID_FORMAT_STRING, vb_oid_value[0]);
743                                 for(i=1; i<vb_oid_value_length;i++) {
744                                         sprintf(tmp_string, OID_FORMAT_STRING1, vb_oid_value[i]);
745                                         strcat(vb_string,tmp_string);
746                                 }
747                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <oid> %s", vb_string);
748                         }                       
749                         offset+=tmp_length;
750                         break;
751                 case ASN_OCTET_STR:
752                 case ASN_IPADDRESS:
753                 case ASN_OPAQUE:
754                 case ASN_NSAP:
755                         vb_string_value_length=128;
756                         tmp_length=length;
757                         data=asn_parse_string(data, &length, &type, vb_string_value, &vb_string_value_length);
758                         tmp_length-=length;
759                         if (data == NULL){
760                                 dissect_snmp_error(pd, offset, fd, tree,
761                                         "Couldn't parse octet string value");
762                                 return;
763                         }
764                         if(tree) {
765                                 vb_string_value[vb_string_value_length]=0;
766                                 /* if some characters are not printable, display the string as
767                                  * bytes */
768                                 for(i=0; i<vb_string_value_length; i++) {
769                                         if(!(isprint(vb_string_value[i]) || isspace(vb_string_value[i]))) break;
770                                 }
771                                 if(i<vb_string_value_length) {
772                                         sprintf(vb_string, "%03d", (int)vb_string_value[0]);
773                                         for(i=1; i<vb_string_value_length; i++) {
774                                                 sprintf(tmp_string, ".%03d", (int)vb_string_value[i]);
775                                                 strcat(vb_string,tmp_string);
776                                         }
777                                         proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <str> %s", vb_string);
778                                 }else {
779                                         proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <str> %s", vb_string_value);
780                                 }
781                         }
782                         offset+=tmp_length;
783                         break;                  
784
785 #ifdef OPAQUE_SPECIAL_TYPES
786                 case ASN_OPAQUE_I64:
787                         tmp_length=length;
788                         data=asn_parse_signed_int64(data, &length, &type, &vb_counter64_value, sizeof(vb_counter64_value));
789                         tmp_length-=length;
790                         if (data == NULL){
791                                 dissect_snmp_error(pd, offset, fd, tree,
792                                         "Couldn't parse integer64 value");
793                                 return;
794                         }
795                         if(tree) {
796                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <i64> %ld:%lu (%#lx:%lx)",
797                                                                  vb_counter64_value.high,
798                                                                  vb_counter64_value.low,
799                                                                  vb_counter64_value.high,
800                                                                  vb_counter64_value.low);
801                         }
802                         offset+=tmp_length;
803                         break;
804                         break;
805
806                 case ASN_OPAQUE_FLOAT:
807                         tmp_length=length;
808                         data=asn_parse_float(data, &length, &type,&vb_float_value, sizeof(vb_float_value));
809                         tmp_length-=length;
810                         if (data == NULL){
811                                 dissect_snmp_error(pd, offset, fd, tree,
812                                         "Couldn't parse float value");
813                                 return;
814                         }
815                         if(tree) {
816                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <f> %f", (double)vb_float_value);
817                         }
818                         offset+=tmp_length;
819                         break;
820                         
821                 case ASN_OPAQUE_DOUBLE:
822                         tmp_length=length;
823                         data=asn_parse_double(data, &length, &type,&vb_double_value, sizeof(vb_double_value));
824                         tmp_length-=length;
825                         if (data == NULL){
826                                 dissect_snmp_error(pd, offset, fd, tree,
827                                         "Couldn't parse double value");
828                                 return;
829                         }
830                         if(tree) {
831                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <d> %f", vb_double_value);
832                         }
833                         offset+=tmp_length;
834                         break;
835 #endif /* OPAQUE_SPECIAL_TYPES */
836                         
837                 case SNMP_NOSUCHOBJECT:
838                         if(tree) {
839                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <err> no such object");
840                         }                       
841                         break;
842                 case SNMP_NOSUCHINSTANCE:
843                         if(tree) {
844                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <err> no such instance");
845                         }                       
846                         break;
847                 case SNMP_ENDOFMIBVIEW:
848                         if(tree) {
849                                 proto_tree_add_item(snmp_tree, offset, tmp_length, "Value: <err> end of mib view");
850                         }                       
851                         break;
852                         
853                 default:
854                         dissect_snmp_error(pd, offset, fd, tree,
855                                 "Unsupported type for variable-binding value");
856                         return;
857                 }                       
858         }
859 }
860
861 #endif /* WITH_SNMP: CMU or UCD */