Created a new protocol tree implementation and a new display filter
[obnox/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.4 1999/07/07 22:51:54 gram 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_text(tree, offset, all_length, "Simple Network Management Protocol");
456                         snmp_tree = proto_item_add_subtree(item, ETT_SNMP);
457                         proto_tree_add_text(snmp_tree, offset, header_length, "Community: \"%s\", Version: %s", community, val_to_str(version, versions, "Unknown version %#x"));
458                         offset+=header_length;
459                         proto_tree_add_text(snmp_tree, offset, pdu_type_length, "%s", pdu_type_string);
460                         offset+=pdu_type_length;
461                         proto_tree_add_text(snmp_tree, offset, request_id_length, "Request Id.: %#x", (unsigned int)request_id);
462                         offset+=request_id_length;
463                         proto_tree_add_text(snmp_tree, offset, error_status_length, "Error Status: %s", val_to_str(error_status, error_statuses, "Unknown (%d)"));
464                         offset+=error_status_length;
465                         proto_tree_add_text(snmp_tree, offset, error_index_length, "Error Index: %d", (int)error_index);
466                         offset+=error_index_length;
467                 } else {
468                         offset+=header_length;
469                         offset+=pdu_type_length;
470                         offset+=request_id_length;
471                         offset+=error_status_length;
472                         offset+=error_index_length;             
473                 }
474                 
475         } else {
476                 /* an SNMPv1 trap PDU */
477                 pdu_type_string = val_to_str(pdu_type, pdu_types,
478                     "Unknown PDU type %#x");
479                 if (check_col(fd, COL_INFO))
480                         col_add_str(fd, COL_INFO, pdu_type_string);
481                 if(tree) {
482                         all_length=fd->pkt_len-offset;
483                         item = proto_tree_add_text(tree, offset, all_length, "Simple Network Management Protocol");
484                         snmp_tree = proto_item_add_subtree(item, ETT_SNMP);
485                         proto_tree_add_text(snmp_tree, offset, header_length, "Community: \"%s\", Version: %s", community, val_to_str(version, versions, "Unknown version %#x"));
486                         offset+=header_length;
487                         proto_tree_add_text(snmp_tree, offset, pdu_type_length, "Pdu type: %s", pdu_type_string);
488                         offset+=pdu_type_length;
489                 } else {
490                         offset+=header_length;
491                         offset+=pdu_type_length;
492                 }
493                 
494         /* enterprise */
495                 enterprise_length = MAX_NAME_LEN;
496                 tmp_length=length;
497                 data = asn_parse_objid(data, &length, &type, enterprise,  &enterprise_length);
498                 if (data == NULL) {
499                         dissect_snmp_error(pd, offset, fd, tree,
500                                 "Couldn't parse enterprise OID");
501                         return;
502                 }
503                 tmp_length-=length;
504
505                 sprintf(vb_string, OID_FORMAT_STRING, enterprise[0]);
506                 for(i=1; i<enterprise_length;i++) {
507                         sprintf(tmp_string, OID_FORMAT_STRING1, enterprise[i]);
508                         strcat(vb_string,tmp_string);
509                 }
510                 if(tree) {
511                         proto_tree_add_text(snmp_tree, offset, tmp_length, "Enterprise: %s", vb_string);
512                 }
513                 offset+=tmp_length;
514
515         /* agent address */
516                 vb_string_value_length = 4;
517                 tmp_length=length;
518                 data = asn_parse_string(data, &length, &type, vb_string_value, &vb_string_value_length);
519                 if (data == NULL) {
520                         dissect_snmp_error(pd, offset, fd, tree,
521                                 "Couldn't parse agent address");
522                         return;
523                 }
524                 tmp_length-=length;
525                 if(tree) {
526                         proto_tree_add_text(snmp_tree, offset, tmp_length, "Agent address: %d.%d.%d.%d",
527                                                          vb_string_value[0],vb_string_value[1],vb_string_value[2],vb_string_value[3]);
528                 }
529                 offset+=tmp_length;
530                 
531         /* generic trap */
532                 tmp_length=length;
533                 data = asn_parse_int(data, &length, &type, &trap_type, sizeof(trap_type));
534                 if (data == NULL) {
535                         dissect_snmp_error(pd, offset, fd, tree,
536                                 "Couldn't parse trap type");
537                         return;
538                 }
539                 tmp_length-=length;
540                 if(tree) {
541                         proto_tree_add_text(snmp_tree, offset, tmp_length, "Trap type: %s", val_to_str(trap_type, trap_types, "Unknown (%d)"));
542                 }               
543                 offset+=tmp_length;
544                 
545         /* specific trap */
546                 tmp_length=length;
547                 data = asn_parse_int(data, &length, &type, &specific_type, sizeof(specific_type));
548                 if (data == NULL) {
549                         dissect_snmp_error(pd, offset, fd, tree,
550                                 "Couldn't parse specific trap type");
551                         return;
552                 }
553                 tmp_length-=length;
554                 if(tree) {
555                         proto_tree_add_text(snmp_tree, offset, tmp_length, "Specific trap type: %ld (%#lx)", (long)specific_type, (long)specific_type);
556                 }               
557                 offset+=tmp_length;
558                 
559         /* timestamp  */
560                 tmp_length=length;
561                 data = asn_parse_unsigned_int(data, &length, &type, &timestamp, sizeof(timestamp));
562                 if (data == NULL) {
563                         dissect_snmp_error(pd, offset, fd, tree,
564                                 "Couldn't parse time stamp");
565                         return;
566                 }
567                 tmp_length-=length;
568                 if(tree) {
569                         proto_tree_add_text(snmp_tree, offset, tmp_length, "Timestamp: %lu", (unsigned long)timestamp);
570                 }               
571                 offset+=tmp_length;
572         }
573         
574         /* variable bindings */
575     /* get header for variable-bindings sequence */
576         tmp_length=length;
577         data = asn_parse_header(data, &length, &type);
578         if (data == NULL) {
579                 dissect_snmp_error(pd, offset, fd, tree,
580                         "Couldn't variable-bindings header");
581                 return;
582         }
583         tmp_length-=length;
584         if (type != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
585                 dissect_snmp_error(pd, offset, fd, tree,
586                         "Bad type for variable-bindings header");
587                 return;
588         }
589         offset+=tmp_length;
590         /* printf("VB header: offset is %d; length is %d.\n", offset, tmp_length); */
591
592         /* loop on variable bindings */
593         vb_index=0;
594         while(length>0) {
595                 vb_index++;
596                 /* printf("VB index is %d (offset=%d; length=%d).\n", vb_index, offset, length); */
597                 /* parse type */
598                 tmp_length=length;
599                 tmp_data=data;
600                 data = asn_parse_header(data, &tmp_length, &type);
601                 if (data == NULL) {
602                         dissect_snmp_error(pd, offset, fd, tree,
603                                 "Couldn't parse variable-binding header");
604                         return;
605                 }
606                 if (type != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
607                         dissect_snmp_error(pd, offset, fd, tree,
608                                 "Bad type for variable-binding header");
609                         return;
610                 }
611                 tmp_length=(int)(data-tmp_data);
612                 length-=tmp_length;
613                 offset+=tmp_length;
614                 
615                 /* parse object identifier */
616                 vb_name_length=MAX_NAME_LEN;
617                 tmp_length=length;
618                 data = asn_parse_objid(data, &length, &type, vb_name, &vb_name_length);
619                 if (data == NULL) {
620                         dissect_snmp_error(pd, offset, fd, tree,
621                                 "No object-identifier for variable-binding");
622                         return;
623                 }
624
625                 if (type != (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID)) {
626                         dissect_snmp_error(pd, offset, fd, tree,
627                                 "Bad type for variable-binding");
628                         return;
629                 }
630                 tmp_length-=length;
631
632                 if(tree) {
633                         sprintf(vb_string, OID_FORMAT_STRING, vb_name[0]);
634                         for(i=1; i<vb_name_length;i++) {
635                                 sprintf(tmp_string, OID_FORMAT_STRING1, vb_name[i]);
636                                 strcat(vb_string,tmp_string);
637                         }
638                         
639                         sprint_objid(vb_string2, vb_name, vb_name_length);
640                         
641                         proto_tree_add_text(snmp_tree, offset, tmp_length, "Object identifier %d: %s (%s)", vb_index, vb_string, vb_string2);
642                 }
643                 offset+=tmp_length;
644                                 
645                 /* parse the type of the object */
646                 tmp_length=length;
647                 if (NULL == asn_parse_header(data, &tmp_length, &vb_type)){
648                         dissect_snmp_error(pd, offset, fd, tree,
649                                 "Bad type for variable-binding value");
650                         return;
651                 }
652
653                 /* parse the value */
654                 switch(vb_type) {
655                 case ASN_NULL:
656                         tmp_length=length;
657                         data=asn_parse_null(data, &length, &type);
658                         tmp_length-=length;
659                         if (data == NULL){
660                                 dissect_snmp_error(pd, offset, fd, tree,
661                                         "Couldn't parse null value");
662                                 return;
663                         }
664                         if(tree) {
665                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: NULL");
666                         }
667                         offset+=tmp_length;
668                         break;
669                         
670                 case ASN_INTEGER:
671                         tmp_length=length;
672                         data=asn_parse_int(data,  &length, &type, &vb_integer_value, sizeof(vb_integer_value));
673                         tmp_length-=length;
674                         if (data == NULL){
675                                 dissect_snmp_error(pd, offset, fd, tree,
676                                         "Couldn't parse integer value");
677                                 return;
678                         }
679                         if(tree) {
680                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <i> %ld (%#lx)", (long)vb_integer_value, (long)vb_integer_value);
681                         }
682                         offset+=tmp_length;
683                         break;
684
685                 case ASN_COUNTER:
686                 case ASN_GAUGE:
687                 case ASN_TIMETICKS:
688                 case ASN_UINTEGER:
689                         tmp_length=length;
690                         data=asn_parse_unsigned_int(data, &length, &type, &vb_unsigned_value, sizeof(vb_unsigned_value));
691                         tmp_length-=length;
692                         if (data == NULL){
693                                 dissect_snmp_error(pd, offset, fd, tree,
694                                         "Couldn't parse unsigned value");
695                                 return;
696                         }
697                         if(tree) {
698                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <u> %lu (%#lx)", (unsigned long)vb_unsigned_value, (unsigned long)vb_unsigned_value);
699                         }
700                         offset+=tmp_length;
701                         break;
702
703 #ifdef WITH_SNMP_UCD
704                         /* only ucd support 64bits types */
705                 case ASN_COUNTER64:
706 #ifdef OPAQUE_SPECIAL_TYPES
707                 case ASN_OPAQUE_COUNTER64:
708                 case ASN_OPAQUE_U64:
709 #endif /* OPAQUE_SPECIAL_TYPES */
710                         tmp_length=length;
711                         data=asn_parse_unsigned_int64(data, &length, &type, &vb_counter64_value, sizeof(vb_counter64_value));
712                         tmp_length-=length;
713                         if (data == NULL){
714                                 dissect_snmp_error(pd, offset, fd, tree,
715                                         "Couldn't parse counter64 value");
716                                 return;
717                         }
718                         if(tree) {
719                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <i64> %lu:%lu (%#lx:%lx)",
720                                                                  vb_counter64_value.high,
721                                                                  vb_counter64_value.low,
722                                                                  vb_counter64_value.high,
723                                                                  vb_counter64_value.low);
724                         }
725                         offset+=tmp_length;
726                         break;
727 #endif /* WITH_SNMP_UCD */
728                         
729                 case ASN_OBJECT_ID:
730                         vb_oid_value_length = MAX_NAME_LEN;
731                         tmp_length=length;
732                         data=asn_parse_objid(data, &length, &type, vb_oid_value, &vb_oid_value_length);
733                         tmp_length-=length;
734                         if (data == NULL){
735                                 dissect_snmp_error(pd, offset, fd, tree,
736                                         "Couldn't parse OID value");
737                                 return;
738                         }
739                         if(tree) {
740                                 sprintf(vb_string, OID_FORMAT_STRING, vb_oid_value[0]);
741                                 for(i=1; i<vb_oid_value_length;i++) {
742                                         sprintf(tmp_string, OID_FORMAT_STRING1, vb_oid_value[i]);
743                                         strcat(vb_string,tmp_string);
744                                 }
745                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <oid> %s", vb_string);
746                         }                       
747                         offset+=tmp_length;
748                         break;
749                 case ASN_OCTET_STR:
750                 case ASN_IPADDRESS:
751                 case ASN_OPAQUE:
752                 case ASN_NSAP:
753                         vb_string_value_length=128;
754                         tmp_length=length;
755                         data=asn_parse_string(data, &length, &type, vb_string_value, &vb_string_value_length);
756                         tmp_length-=length;
757                         if (data == NULL){
758                                 dissect_snmp_error(pd, offset, fd, tree,
759                                         "Couldn't parse octet string value");
760                                 return;
761                         }
762                         if(tree) {
763                                 vb_string_value[vb_string_value_length]=0;
764                                 /* if some characters are not printable, display the string as
765                                  * bytes */
766                                 for(i=0; i<vb_string_value_length; i++) {
767                                         if(!(isprint(vb_string_value[i]) || isspace(vb_string_value[i]))) break;
768                                 }
769                                 if(i<vb_string_value_length) {
770                                         sprintf(vb_string, "%03d", (int)vb_string_value[0]);
771                                         for(i=1; i<vb_string_value_length; i++) {
772                                                 sprintf(tmp_string, ".%03d", (int)vb_string_value[i]);
773                                                 strcat(vb_string,tmp_string);
774                                         }
775                                         proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <str> %s", vb_string);
776                                 }else {
777                                         proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <str> %s", vb_string_value);
778                                 }
779                         }
780                         offset+=tmp_length;
781                         break;                  
782
783 #ifdef OPAQUE_SPECIAL_TYPES
784                 case ASN_OPAQUE_I64:
785                         tmp_length=length;
786                         data=asn_parse_signed_int64(data, &length, &type, &vb_counter64_value, sizeof(vb_counter64_value));
787                         tmp_length-=length;
788                         if (data == NULL){
789                                 dissect_snmp_error(pd, offset, fd, tree,
790                                         "Couldn't parse integer64 value");
791                                 return;
792                         }
793                         if(tree) {
794                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <i64> %ld:%lu (%#lx:%lx)",
795                                                                  vb_counter64_value.high,
796                                                                  vb_counter64_value.low,
797                                                                  vb_counter64_value.high,
798                                                                  vb_counter64_value.low);
799                         }
800                         offset+=tmp_length;
801                         break;
802                         break;
803
804                 case ASN_OPAQUE_FLOAT:
805                         tmp_length=length;
806                         data=asn_parse_float(data, &length, &type,&vb_float_value, sizeof(vb_float_value));
807                         tmp_length-=length;
808                         if (data == NULL){
809                                 dissect_snmp_error(pd, offset, fd, tree,
810                                         "Couldn't parse float value");
811                                 return;
812                         }
813                         if(tree) {
814                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <f> %f", (double)vb_float_value);
815                         }
816                         offset+=tmp_length;
817                         break;
818                         
819                 case ASN_OPAQUE_DOUBLE:
820                         tmp_length=length;
821                         data=asn_parse_double(data, &length, &type,&vb_double_value, sizeof(vb_double_value));
822                         tmp_length-=length;
823                         if (data == NULL){
824                                 dissect_snmp_error(pd, offset, fd, tree,
825                                         "Couldn't parse double value");
826                                 return;
827                         }
828                         if(tree) {
829                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <d> %f", vb_double_value);
830                         }
831                         offset+=tmp_length;
832                         break;
833 #endif /* OPAQUE_SPECIAL_TYPES */
834                         
835                 case SNMP_NOSUCHOBJECT:
836                         if(tree) {
837                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <err> no such object");
838                         }                       
839                         break;
840                 case SNMP_NOSUCHINSTANCE:
841                         if(tree) {
842                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <err> no such instance");
843                         }                       
844                         break;
845                 case SNMP_ENDOFMIBVIEW:
846                         if(tree) {
847                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <err> end of mib view");
848                         }                       
849                         break;
850                         
851                 default:
852                         dissect_snmp_error(pd, offset, fd, tree,
853                                 "Unsupported type for variable-binding value");
854                         return;
855                 }                       
856         }
857 }
858
859 #endif /* WITH_SNMP: CMU or UCD */