Replace the ETT_ "enum" members, declared in "packet.h", with
[obnox/wireshark/wip.git] / packet-cdp.c
1 /* packet-cdp.c
2  * Routines for the disassembly of the "Cisco Discovery Protocol"
3  * (c) Copyright Hannes R. Boehm <hannes@boehm.org>
4  *
5  * $Id: packet-cdp.c,v 1.17 1999/11/16 11:42:28 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
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 #include "config.h"
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <glib.h>
37 #include "packet.h"
38
39 /* Offsets in TLV structure. */
40 #define TLV_TYPE        0
41 #define TLV_LENGTH      2
42
43 static int proto_cdp = -1;
44 static int hf_cdp_version = -1;
45 static int hf_cdp_flags = -1;
46 static int hf_cdp_ttl = -1;
47 static int hf_cdp_tlvtype = -1;
48 static int hf_cdp_tlvlength = -1;
49
50 static gint ett_cdp = -1;
51 static gint ett_cdp_tlv = -1;
52
53 static void
54 add_multi_line_string_to_tree(proto_tree *tree, gint start, gint len,
55   const gchar *prefix, const gchar *string);
56
57 #define TYPE_MGMT_ADDR          0
58 #define TYPE_CHASSIS_ID         1
59 #define TYPE_2                  2
60 #define TYPE_PORT               3
61 #define TYPE_IOS_VERSION        5
62 #define TYPE_PLATFORM           6
63 #define TYPE_MGMT_IP_ADDR       0x01cc
64
65 static const value_string type_vals[] = {
66         { TYPE_MGMT_ADDR,    "Mgmt addr?" },
67         { TYPE_CHASSIS_ID,   "Chassis ID" },
68         { TYPE_2,            "Unknown" },
69         { TYPE_PORT,         "Port" },
70         { TYPE_IOS_VERSION,  "Software version" },
71         { TYPE_PLATFORM,     "Platform" },
72         { TYPE_MGMT_IP_ADDR, "Mgmt IP" },
73         { 0,                 NULL },
74 };
75         
76 void 
77 dissect_cdp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
78     proto_item *ti; 
79     proto_tree *cdp_tree = NULL;
80     guint16 type;
81     guint16 length;
82     char *type_str;
83     char *stringmem;
84     proto_item *tlvi;
85     proto_tree *tlv_tree;
86
87     if (check_col(fd, COL_PROTOCOL))
88         col_add_str(fd, COL_PROTOCOL, "CDP");
89     if (check_col(fd, COL_INFO))
90         col_add_str(fd, COL_INFO, "Cisco Discovery Protocol"); 
91
92     if(tree){
93         ti = proto_tree_add_item(tree, proto_cdp, offset, END_OF_FRAME, NULL);
94         cdp_tree = proto_item_add_subtree(ti, ett_cdp);
95         
96         /* CDP header */
97         proto_tree_add_item(cdp_tree, hf_cdp_version, offset, 1, pd[offset]);
98         offset += 1;
99         proto_tree_add_item_format(cdp_tree, hf_cdp_flags, offset, 1,
100                                    pd[offset], 
101                                    "Flags: %x (unknown)", pd[offset]);
102         offset += 1;
103         proto_tree_add_item_format(cdp_tree, hf_cdp_ttl, offset, 2, 
104                                    pntohs(&pd[offset]),
105                                    "TTL: %u (unknown)", pntohs(&pd[offset]));
106         offset += 2;
107
108         while( IS_DATA_IN_FRAME(offset) ){
109                 type = pntohs(&pd[offset + TLV_TYPE]);
110                 length = pntohs(&pd[offset + TLV_LENGTH]);
111                 type_str = val_to_str(type, type_vals,
112                     "Unknown (0x%04x)");
113
114                 switch( type ){
115                         case TYPE_MGMT_ADDR:
116                                 /* ??? Mgmt Addr; in this one, the "length"
117                                    field doesn't include the length of the
118                                    type and length fields. */
119                                 tlvi = proto_tree_add_text(cdp_tree, offset,
120                                     length + 4, "Type: %s, length: %u",
121                                     type_str, length);
122                                 tlv_tree = proto_item_add_subtree(tlvi,
123                                     ett_cdp_tlv);
124                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype,
125                                     offset + TLV_TYPE, 2, type);
126                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength,
127                                     offset + TLV_LENGTH, 2, length);
128                                 if (length > 0) {
129                                         proto_tree_add_text(tlv_tree,
130                                             offset + 4, length, "Data");
131                                 }
132                                 offset+=length + 4;
133                                 break;
134                         case TYPE_CHASSIS_ID:
135                                 /* ??? Chassis ID */
136                                 tlvi = proto_tree_add_text(cdp_tree, offset,
137                                     length, "Chassis ID: %s",
138                                     &pd[offset+4]);
139                                 tlv_tree = proto_item_add_subtree(tlvi,
140                                     ett_cdp_tlv);
141                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype,
142                                     offset + TLV_TYPE, 2, type);
143                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength,
144                                     offset + TLV_LENGTH, 2, length);
145                                 proto_tree_add_text(tlv_tree, offset + 4,
146                                     length - 4, "Chassis ID: %s",
147                                     &pd[offset+4]);
148                                 offset+=length;
149                                 break;
150                         case TYPE_2:
151                                 /* this is quite strange: this tlv contains
152                                    no data itself but two tlvs which
153                                    calculate the length without the 2 byte
154                                    type and 2 byte length field */
155                                 tlvi = proto_tree_add_text(cdp_tree, offset,
156                                     4, "Type: %u (unknown), second field: %u",
157                                     type, length);
158                                 tlv_tree = proto_item_add_subtree(tlvi,
159                                     ett_cdp_tlv);
160                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype,
161                                     offset + TLV_TYPE, 2, type);
162                                 proto_tree_add_text(tlv_tree,
163                                     offset + TLV_LENGTH, 2, "Second field: %u",
164                                     length);
165                                 offset+=4;
166                                 break;
167                         case TYPE_PORT:
168                                 /* ??? Port  */    
169                                 tlvi = proto_tree_add_text(cdp_tree, offset,
170                                     length, "Sent through Interface: %s",
171                                     &pd[offset+4]);
172                                 tlv_tree = proto_item_add_subtree(tlvi,
173                                     ett_cdp_tlv);
174                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype,
175                                     offset + TLV_TYPE, 2, type);
176                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength,
177                                     offset + TLV_LENGTH, 2, length);
178                                 proto_tree_add_text(tlv_tree, offset + 4,
179                                     length - 4, "Sent through Interface: %s",
180                                     &pd[offset+4]);
181                                 offset+=length;
182                                 break;
183                         case TYPE_IOS_VERSION:
184                                 /* ??? IOS Version */
185                                 add_multi_line_string_to_tree(cdp_tree,
186                                     offset + 4, length - 4, "Software Version: ",
187                                     &pd[offset+4] );
188                                 offset+=length;
189                                 break;
190                         case TYPE_PLATFORM:
191                                 /* ??? platform */
192                                 stringmem = malloc(length);
193                                 memset(stringmem, '\0', length);
194                                 memcpy(stringmem, &pd[offset+4], length - 4 );
195                                 tlvi = proto_tree_add_text(cdp_tree,
196                                     offset, length, "Platform: %s",
197                                     stringmem);
198                                 tlv_tree = proto_item_add_subtree(tlvi,
199                                     ett_cdp_tlv);
200                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype,
201                                     offset + TLV_TYPE, 2, type);
202                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength,
203                                     offset + TLV_LENGTH, 2, length);
204                                 proto_tree_add_text(tlv_tree, offset + 4,
205                                     length - 4, "Platform: %s", stringmem);
206                                 free(stringmem);
207                                 offset+=length;
208                                 break;
209                         case TYPE_MGMT_IP_ADDR:
210                                 /* ??? Mgmt IP Addr; in this one, the "length"
211                                    field doesn't include the length of the
212                                    type and length fields. */
213                                 tlvi = proto_tree_add_text(cdp_tree,
214                                     offset, length + 4, "Mgmt IP: %s",
215                                     ip_to_str(&pd[offset+4]));
216                                 tlv_tree = proto_item_add_subtree(tlvi,
217                                     ett_cdp_tlv);
218                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype,
219                                     offset + TLV_TYPE, 2, type);
220                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength,
221                                     offset + TLV_LENGTH, 2, length);
222                                 proto_tree_add_text(tlv_tree, offset + 4,
223                                     length, "IP address: %s",
224                                     ip_to_str(&pd[offset+4]));
225                                 offset+=length + 4;
226                                 break;
227                         default:
228                                 tlvi = proto_tree_add_text(cdp_tree, offset,
229                                     length, "Type: %s, length: %u",
230                                     type_str, length);
231                                 tlv_tree = proto_item_add_subtree(tlvi,
232                                     ett_cdp_tlv);
233                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvtype,
234                                     offset + TLV_TYPE, 2, type);
235                                 proto_tree_add_item(tlv_tree, hf_cdp_tlvlength,
236                                     offset + TLV_LENGTH, 2, length);
237                                 if (length > 4) {
238                                         proto_tree_add_text(tlv_tree,
239                                             offset + 4, length - 4, "Data");
240                                 } else
241                                         return;
242                                 offset+=length;
243                 }
244         }
245         dissect_data(pd, offset, fd, cdp_tree);
246     }
247 }
248
249 static void
250 add_multi_line_string_to_tree(proto_tree *tree, gint start, gint len,
251   const gchar *prefix, const gchar *string)
252 {
253     int prefix_len;
254     int i;
255     char blanks[64+1];
256     const gchar *p, *q;
257     int line_len;
258     int data_len;
259
260     prefix_len = strlen(prefix);
261     if (prefix_len > 64)
262         prefix_len = 64;
263     for (i = 0; i < prefix_len; i++)
264         blanks[i] = ' ';
265     blanks[i] = '\0';
266     p = string;
267     for (;;) {
268         q = strchr(p, '\n');
269         if (q != NULL) {
270             line_len = q - p;
271             data_len = line_len + 1;
272         } else {
273             line_len = strlen(p);
274             data_len = line_len;
275         }
276         proto_tree_add_text(tree, start, data_len, "%s%.*s", prefix,
277            line_len, p);
278         if (q == NULL)
279             break;
280         p += data_len;
281         start += data_len;
282         prefix = blanks;
283     }
284 }
285
286 void
287 proto_register_cdp(void)
288 {
289         static hf_register_info hf[] = {
290                 { &hf_cdp_version,
291                 { "Version",            "cdp.version",  FT_UINT8, BASE_DEC, NULL, 0x0,
292                         "" }},
293
294                 { &hf_cdp_flags,
295                 { "Flags",              "cdp.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
296                         "" }},
297
298                 { &hf_cdp_ttl,
299                 { "TTL",                "cdp.ttl", FT_UINT16, BASE_DEC, NULL, 0x0,
300                         "" }},
301
302                 { &hf_cdp_tlvtype,
303                 { "Type",               "cdp.tlv.type", FT_UINT16, BASE_HEX, VALS(type_vals), 0x0,
304                         "" }},
305
306                 { &hf_cdp_tlvlength,
307                 { "Length",             "cdp.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0,
308                         "" }},
309         };
310         static gint *ett[] = {
311                 &ett_cdp,
312                 &ett_cdp_tlv,
313         };
314
315         proto_cdp = proto_register_protocol("Cisco Discovery Protocol", "cdp");
316         proto_register_field_array(proto_cdp, hf, array_length(hf));
317         proto_register_subtree_array(ett, array_length(ett));
318 }