Fix it to build with CMU, as well as UCD, SNMP.
[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.6 1999/07/29 07:11:23 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 static int proto_snmp = -1;
58
59 #ifdef WITH_SNMP_UCD
60 /* should be defined only if supported in ucd-snmp */
61 #define OPAQUE_SPECIAL_TYPES 1
62 #include <ucd-snmp/asn1.h>
63 #include <ucd-snmp/snmp.h>
64 #include <ucd-snmp/snmp_api.h>
65 #include <ucd-snmp/snmp_impl.h>
66 #include <ucd-snmp/mib.h>
67
68 typedef long SNMP_INT;
69 typedef unsigned  long SNMP_UINT;
70 #define OID_FORMAT_STRING "%ld"
71 #define OID_FORMAT_STRING1 ".%ld"
72
73 #endif
74 #ifdef WITH_SNMP_CMU
75 #include <snmp/snmp.h>
76 #include <snmp/snmp_impl.h>
77
78
79 #ifndef MAX_NAME_LEN
80 #define MAX_NAME_LEN SNMP_MAX_LEN
81 #endif
82
83 #define SNMP_MSG_GET GET_REQ_MSG
84 #define SNMP_MSG_GETNEXT GETNEXT_REQ_MSG
85 #define SNMP_MSG_RESPONSE GET_RSP_MSG
86 #define SNMP_MSG_SET SET_REQ_MSG   
87 #define SNMP_MSG_TRAP TRP_REQ_MSG
88
89 #ifdef GETBULK_REQ_MSG
90 #define SNMP_MSG_GETBULK GETBULK_REQ_MSG
91 #else
92 #define SNMP_MSG_GETBULK SNMP_PDU_GETBULK
93 #endif
94
95 #ifdef INFORM_REQ_MSG
96 #define SNMP_MSG_INFORM INFORM_REQ_MSG
97 #else
98 #define SNMP_MSG_INFORM SNMP_PDU_INFORM
99 #endif
100
101 #ifdef TRP2_REQ_MSG
102 #define SNMP_MSG_TRAP2 TRP2_REQ_MSG
103 #else
104 #define SNMP_MSG_TRAP2 SNMP_PDU_V2TRAP
105 #endif
106
107 #ifdef REPORT_MSG
108 #define SNMP_MSG_REPORT REPORT_MSG
109 #else
110 #define SNMP_MSG_REPORT SNMP_PDU_REPORT
111 #endif
112
113
114 #ifndef SNMP_VERSION_2c
115 #define SNMP_VERSION_2c 1
116 #endif
117 #ifndef SNMP_VERSION_2u
118 #define SNMP_VERSION_2u 2
119 #endif
120 #ifndef SNMP_VERSION_3
121 #define SNMP_VERSION_3 3
122 #endif
123
124 #ifdef SNMP_TRAP_AUTHENTICATIONFAILURE
125 #define SNMP_TRAP_AUTHFAIL SNMP_TRAP_AUTHENTICATIONFAILURE
126 #endif
127
128 #ifndef COMMUNITY_MAX_LEN
129 #define COMMUNITY_MAX_LEN 256
130 #endif
131
132 #ifndef ASN_INTEGER
133 #define ASN_INTEGER SMI_INTEGER
134 #endif
135 #ifndef ASN_OCTET_STR
136 #define ASN_OCTET_STR SMI_STRING
137 #endif
138 #ifndef ASN_OBJECT_ID
139 #define ASN_OBJECT_ID SMI_OBJID
140 #endif
141 #ifndef ASN_NULL
142 #define ASN_NULL SMI_NULLOBJ
143 #endif
144
145 #ifndef ASN_IPADDRESS
146         #ifdef IPADDRESS
147         #define ASN_IPADDRESS IPADDRESS
148         #else
149         #define ASN_IPADDRESS SMI_IPADDRESS
150         #endif
151 #endif
152
153 #ifndef ASN_COUNTER
154         #ifdef COUNTER
155         #define ASN_COUNTER COUNTER
156         #else
157         #define ASN_COUNTER SMI_COUNTER32
158         #endif
159 #endif
160
161 #ifndef ASN_GAUGE
162         #ifdef GAUGE
163         #define ASN_GAUGE GAUGE
164         #else
165         #define ASN_GAUGE SMI_GAUGE32
166         #endif
167 #endif
168
169 #ifndef ASN_TIMETICKS
170         #ifdef TIMETICKS
171         #define ASN_TIMETICKS TIMETICKS
172         #else
173         #define ASN_TIMETICKS SMI_TIMETICKS
174         #endif
175 #endif
176
177 #ifndef ASN_OPAQUE
178         #ifdef OPAQUE
179         #define ASN_OPAQUE OPAQUE
180         #else
181         #define ASN_OPAQUE SMI_OPAQUE
182         #endif
183 #endif
184
185 #ifndef ASN_COUNTER64
186         #ifdef COUNTER64
187         #define ASN_COUNTER64 COUNTER64
188         #else
189         #define ASN_COUNTER64 SMI_COUNTER64
190         #endif
191 #endif
192
193 #ifndef ASN_UINTEGER
194 /* historic: should not be used! */
195 #define ASN_UINTEGER (ASN_APPLICATION | 7)
196 #endif
197 #ifndef ASN_NSAP
198 /* historic: should not be used! */
199 #define ASN_NSAP (ASN_APPLICATION | 5)
200 #endif
201 #ifndef SNMP_NOSUCHOBJECT
202 #define SNMP_NOSUCHOBJECT SMI_NOSUCHOBJECT
203 #endif
204 #ifndef SNMP_NOSUCHINSTANCE
205 #define SNMP_NOSUCHINSTANCE SMI_NOSUCHINSTANCE
206 #endif
207 #ifndef SNMP_ENDOFMIBVIEW
208 #define SNMP_ENDOFMIBVIEW SMI_ENDOFMIBVIEW
209 #endif
210
211
212 typedef int SNMP_INT;
213 typedef unsigned int SNMP_UINT;
214 #define OID_FORMAT_STRING "%d"
215 #define OID_FORMAT_STRING1 ".%d"
216
217 #endif
218
219 static const value_string versions[] = {
220         { SNMP_VERSION_1,       "VERSION 1" },
221         { SNMP_VERSION_2c,      "VERSION 2C" },
222         { SNMP_VERSION_2u,      "VERSION 2U" },
223         { SNMP_VERSION_3,       "VERSION 3" },
224         { 0,                    NULL },
225 };
226
227 static const value_string pdu_types[] = {
228         { SNMP_MSG_GET,         "GET" },
229         { SNMP_MSG_GETNEXT,     "GET-NEXT" },
230         { SNMP_MSG_SET,         "SET" },
231         { SNMP_MSG_RESPONSE,    "RESPONSE" },
232         { SNMP_MSG_TRAP,        "TRAP-V1" },
233         { SNMP_MSG_GETBULK,     "GETBULK" },
234         { SNMP_MSG_INFORM,      "INFORM" },
235         { SNMP_MSG_TRAP2,       "TRAP-V2" },
236         { SNMP_MSG_REPORT,      "REPORT" },
237         { 0,                    NULL }
238 };
239
240 static const value_string error_statuses[] = {
241         { SNMP_ERR_NOERROR,             "NO ERROR" },
242         { SNMP_ERR_TOOBIG,              "ERROR: TOOBIG" },
243         { SNMP_ERR_NOSUCHNAME,          "ERROR: NO SUCH NAME" },
244         { SNMP_ERR_BADVALUE,            "ERROR: BAD VALUE" },
245         { SNMP_ERR_READONLY,            "ERROR: READ ONLY" },
246         { SNMP_ERR_GENERR,              "ERROR: GENERIC ERROR" },
247         { SNMP_ERR_NOACCESS,            "ERROR: NO ACCESS" },
248         { SNMP_ERR_WRONGTYPE,           "ERROR: WRONG TYPE" },
249         { SNMP_ERR_WRONGLENGTH,         "ERROR: WRONG LENGTH" },
250         { SNMP_ERR_WRONGENCODING,       "ERROR: WRONG ENCODING" },
251         { SNMP_ERR_WRONGVALUE,          "ERROR: WRONG VALUE" },
252         { SNMP_ERR_NOCREATION,          "ERROR: NO CREATION" },
253         { SNMP_ERR_INCONSISTENTVALUE,   "ERROR: INCONSISTENT VALUE" },
254         { SNMP_ERR_RESOURCEUNAVAILABLE, "ERROR: RESOURCE UNAVAILABLE" },
255         { SNMP_ERR_COMMITFAILED,        "ERROR: COMMIT FAILED" },
256         { SNMP_ERR_UNDOFAILED,          "ERROR: UNDO FAILED" },
257         { SNMP_ERR_AUTHORIZATIONERROR,  "ERROR: AUTHORIZATION ERROR" },
258         { SNMP_ERR_NOTWRITABLE,         "ERROR: NOT WRITABLE" },
259         { SNMP_ERR_INCONSISTENTNAME,    "ERROR: INCONSISTENT NAME" },
260         { 0,                            NULL }
261 };
262
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" },
271         { 0,                            NULL }
272 };
273
274 static void
275 dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
276                    proto_tree *tree, const char *message)
277 {
278         if (check_col(fd, COL_INFO))
279                 col_add_str(fd, COL_INFO, message);
280
281         dissect_data(pd, offset, fd, tree);
282 }
283
284 void
285 dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
286 {
287         int length=fd->pkt_len-offset;
288         u_char *data, *tmp_data;
289
290         int all_length, header_length;
291         u_char type, pdu_type;
292         int pdu_type_length;
293         SNMP_INT request_id, error_status, error_index;
294         int request_id_length, error_status_length, error_index_length;
295         
296         SNMP_INT version;
297         u_char community[COMMUNITY_MAX_LEN];
298         int community_length = COMMUNITY_MAX_LEN;
299
300         oid enterprise[MAX_NAME_LEN];
301         int enterprise_length;
302         SNMP_INT trap_type, specific_type;
303         SNMP_UINT timestamp;
304         
305         int tmp_length;
306         oid vb_name[MAX_NAME_LEN];
307         int vb_name_length;
308         int vb_index;
309         u_char vb_type;
310         char vb_string[MAX_NAME_LEN*6]; /* TBC */
311         char vb_string2[2048]; /* TBC */
312         char tmp_string[12];
313         SNMP_INT vb_integer_value;
314         SNMP_UINT vb_unsigned_value;
315 #ifdef WITH_SNMP_UCD    
316         struct counter64 vb_counter64_value;
317 #endif  
318         oid vb_oid_value[MAX_NAME_LEN];
319         int vb_oid_value_length;
320         unsigned char vb_string_value[128];
321         int vb_string_value_length;
322 #ifdef WITH_SNMP_UCD    
323         float vb_float_value;
324         double vb_double_value;
325 #endif
326         
327         int i;
328
329         char *pdu_type_string;
330
331         proto_tree *snmp_tree=NULL;
332         proto_item *item=NULL;
333
334         if (check_col(fd, COL_PROTOCOL))
335                 col_add_str(fd, COL_PROTOCOL, "SNMP");
336
337         /* NOTE: we have to parse the message piece by piece, since the
338          * capture length may be less than the message length: a 'global'
339          * parsing is likely to fail.
340          */
341         
342 #ifdef WITH_SNMP_UCD    
343         /* parse the SNMP header */
344         if(NULL == asn_parse_header( &pd[offset], &length, &type)) {
345                 dissect_snmp_error(pd, offset, fd, tree,
346                         "Couldn't parse SNMP header");
347                 return;
348         }
349         
350         if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
351                 dissect_snmp_error(pd, offset, fd, tree, "Not an SNMP PDU");
352                 return;
353         }
354         
355         /* authenticates message */
356         length=fd->pkt_len-offset;
357         header_length=length;
358         data = snmp_comstr_parse(&pd[offset], &length, community, &community_length,&version);
359         if(NULL == data) {
360                 dissect_snmp_error(pd, offset, fd, tree,
361                     "Couldn't parse authentication");
362                 return;
363         }
364 #endif
365 #ifdef WITH_SNMP_CMU
366         /* initialize length variables */
367         /* length=fd->pkt_len-offset; */
368         header_length=length;   
369
370         /* parse the SNMP header */
371         data = asn_parse_header( &pd[offset], &length, &type);
372         if(NULL == data) {
373                 dissect_snmp_error(pd, offset, fd, tree,
374                         "Couldn't parse SNMP header");
375                 return;
376         }
377         
378         if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
379                 dissect_snmp_error(pd, offset, fd, tree, "Not an SNMP PDU");
380                 return;
381         }
382
383         data = asn_parse_int(data, &length, &type, &version, sizeof(SNMP_INT));
384         if(NULL == data) {
385                 dissect_snmp_error(pd, offset, fd, tree,
386                     "Couldn't parse SNMP version number");
387                 return;
388         }
389         data = asn_parse_string(data, &length, &type, community, &community_length);
390         if(NULL == data) {
391                 dissect_snmp_error(pd, offset, fd, tree,
392                     "Couldn't parse SNMP community");
393                 return;
394         }
395         community[community_length] = '\0';     
396 #endif 
397
398         header_length-=length;
399         /* printf("Community is %s, version is %d (header length is %d)\n", community, version, header_length); */
400         if(version != SNMP_VERSION_1) {
401                 dissect_snmp_error(pd, offset, fd, tree,
402                     "Non-version-1 SNMP PDU");
403                 return;
404         }
405
406         pdu_type_length=length;
407         data = asn_parse_header(data, &length, &pdu_type);
408         if (data == NULL) {
409                 dissect_snmp_error(pd, offset, fd, tree,
410                     "Couldn't parse PDU type");
411                 return;
412         }
413         pdu_type_length-=length;
414         /* printf("pdu type is %#x (length is %d)\n", type, pdu_type_length); */
415         
416         /* get the fields in the PDU preceeding the variable-bindings sequence */
417         if (pdu_type != SNMP_MSG_TRAP) {
418
419         /* request id */
420                 request_id_length=length;
421                 data = asn_parse_int(data, &length, &type, &request_id, sizeof(request_id));
422                 if (data == NULL) {
423                         dissect_snmp_error(pd, offset, fd, tree,
424                                 "Couldn't parse request ID");
425                         return;
426                 }
427                 request_id_length-=length;
428                 /* printf("request id is %#lx (length is %d)\n", request_id, request_id_length); */
429                 
430         /* error status (getbulk non-repeaters) */
431                 error_status_length=length;
432                 data = asn_parse_int(data, &length, &type, &error_status, sizeof(error_status));
433                 if (data == NULL) {
434                         dissect_snmp_error(pd, offset, fd, tree,
435                                 "Couldn't parse error status");
436                         return;
437                 }
438                 error_status_length-=length;
439
440         /* error index (getbulk max-repetitions) */
441                 error_index_length=length;
442                 data = asn_parse_int(data, &length, &type, &error_index, sizeof(error_index));
443                 if (data == NULL) {
444                         dissect_snmp_error(pd, offset, fd, tree,
445                                 "Couldn't parse error index");
446                         return;
447                 }
448                 error_index_length-=length;
449
450                 pdu_type_string = val_to_str(pdu_type, pdu_types,
451                     "Unknown PDU type %#x");
452                 if (check_col(fd, COL_INFO))
453                         col_add_str(fd, COL_INFO, pdu_type_string);
454                 if (tree) {
455                         /* all_length=header_length+pdu_type_length+request_id_length+error_status_length+error_index_length; */
456                         all_length=fd->pkt_len-offset;
457                         item = proto_tree_add_item(tree, proto_snmp, offset, all_length, NULL);
458                         snmp_tree = proto_item_add_subtree(item, ETT_SNMP);
459                         proto_tree_add_text(snmp_tree, offset, header_length, "Community: \"%s\", Version: %s", community, val_to_str(version, versions, "Unknown version %#x"));
460                         offset+=header_length;
461                         proto_tree_add_text(snmp_tree, offset, pdu_type_length, "%s", pdu_type_string);
462                         offset+=pdu_type_length;
463                         proto_tree_add_text(snmp_tree, offset, request_id_length, "Request Id.: %#x", (unsigned int)request_id);
464                         offset+=request_id_length;
465                         proto_tree_add_text(snmp_tree, offset, error_status_length, "Error Status: %s", val_to_str(error_status, error_statuses, "Unknown (%d)"));
466                         offset+=error_status_length;
467                         proto_tree_add_text(snmp_tree, offset, error_index_length, "Error Index: %d", (int)error_index);
468                         offset+=error_index_length;
469                 } else {
470                         offset+=header_length;
471                         offset+=pdu_type_length;
472                         offset+=request_id_length;
473                         offset+=error_status_length;
474                         offset+=error_index_length;             
475                 }
476                 
477         } else {
478                 /* an SNMPv1 trap PDU */
479                 pdu_type_string = val_to_str(pdu_type, pdu_types,
480                     "Unknown PDU type %#x");
481                 if (check_col(fd, COL_INFO))
482                         col_add_str(fd, COL_INFO, pdu_type_string);
483                 if(tree) {
484                         all_length=fd->pkt_len-offset;
485                         item = proto_tree_add_item(tree, proto_snmp, offset, all_length, NULL);
486                         snmp_tree = proto_item_add_subtree(item, ETT_SNMP);
487                         proto_tree_add_text(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_text(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_text(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_text(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_text(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_text(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_text(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_text(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_text(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_text(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_text(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_text(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_text(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_text(snmp_tree, offset, tmp_length, "Value: <str> %s", vb_string);
778                                 }else {
779                                         proto_tree_add_text(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_text(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_text(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_text(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_text(snmp_tree, offset, tmp_length, "Value: <err> no such object");
840                         }                       
841                         break;
842                 case SNMP_NOSUCHINSTANCE:
843                         if(tree) {
844                                 proto_tree_add_text(snmp_tree, offset, tmp_length, "Value: <err> no such instance");
845                         }                       
846                         break;
847                 case SNMP_ENDOFMIBVIEW:
848                         if(tree) {
849                                 proto_tree_add_text(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 void
862 proto_register_snmp(void)
863 {
864 /*        static hf_register_info hf[] = {
865                 { &variable,
866                 { "Name",           "snmp.abbreviation", TYPE, VALS_POINTER }},
867         };*/
868
869         proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp");
870  /*       proto_register_field_array(proto_snmp, hf, array_length(hf));*/
871 }
872
873 #endif /* WITH_SNMP: CMU or UCD */