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