Move the declarations of the routines in "gtk/file_dlg.c" out of
[obnox/wireshark/wip.git] / packet-wccp.c
1 /* packet-wccp.c
2  * Routines for Web Cache Coordination Protocol dissection
3  * Jerry Talkington <jerryt@netapp.com>
4  *
5  * $Id: packet-wccp.c,v 1.4 1999/12/14 02:09:52 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 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
37 #endif
38
39 #include <glib.h>
40 #include "packet.h"
41
42 static int proto_wccp = -1;
43 static int hf_wccp_message_type = -1;   /* the message type */
44 static int hf_wccp_version = -1;        /* protocol version */
45 static int hf_hash_revision = -1;       /* the version of the hash */
46 static int hf_change_num = -1;          /* change number */
47 static int hf_recvd_id = -1;                    
48 static int hf_cache_ip = -1;
49
50 static gint ett_wccp = -1;
51 static gint ett_cache_count = -1;
52 static gint ett_buckets = -1;
53 static gint ett_flags = -1;
54 static gint ett_cache_info = -1;
55
56 /*
57  * See
58  *
59  *      http://search.ietf.org/internet-drafts/draft-ietf-wrec-web-pro-00.txt
60  *
61  * if it hasn't expired yet.
62  */
63 #define WCCPv1                  0x0004
64 #define WCCP_HERE_I_AM          7
65 #define WCCP_I_SEE_YOU          8
66 #define WCCP_ASSIGN_BUCKET      9
67
68 static const value_string wccp_type_vals[] = {
69     { WCCP_HERE_I_AM,     "Here I am" },
70     { WCCP_I_SEE_YOU,     "I see you" },
71     { WCCP_ASSIGN_BUCKET, "Assign bucket" },
72     { 0,                  NULL }
73 };
74
75 static const value_string wccp_version_val[] = {
76         { WCCPv1, "1"},
77         { 0, NULL}
78 };
79
80 #define HASH_INFO_SIZE  (4*(1+8+1))
81
82 #define WCCP_U_FLAG     0x80000000
83
84 static void dissect_hash_data(const u_char *pd, int offset,
85     proto_tree *wccp_tree);
86 static void dissect_web_cache_list_entry(const u_char *pd, int offset,
87     int index, proto_tree *wccp_tree);
88 static int wccp_bucket_info(guint8 bucket_info, proto_tree *bucket_tree,
89     guint32 start, int offset);
90 static gchar *bucket_name(guint8 bucket);
91
92 void 
93 dissect_wccp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
94 {
95         proto_tree *wccp_tree = NULL;
96         proto_item *wccp_tree_item;
97         guint32 wccp_message_type;
98         guint32 wccp_version;
99         guint32 cache_count;
100         int i;
101
102         if(check_col(fd, COL_PROTOCOL)) {
103                 col_add_str(fd, COL_PROTOCOL, "WCCP");
104         }
105
106         wccp_message_type = pntohl(&pd[offset]);
107
108         if(check_col(fd, COL_INFO)) {
109                 col_add_str(fd, COL_INFO, val_to_str(wccp_message_type,
110                     wccp_type_vals, "Unknown WCCP message (%u)"));
111         }
112
113         if(tree != NULL) {
114                 wccp_tree_item = proto_tree_add_item(tree, proto_wccp, offset,
115                     END_OF_FRAME, NULL);
116                 wccp_tree = proto_item_add_subtree(wccp_tree_item, ett_wccp);
117
118                 proto_tree_add_item(wccp_tree, hf_wccp_message_type, offset,
119                     sizeof(wccp_message_type), wccp_message_type);
120                 offset += sizeof(wccp_message_type);
121
122                 switch (wccp_message_type) {
123
124                 case WCCP_HERE_I_AM:
125                         wccp_version = pntohl(&pd[offset]);
126                         proto_tree_add_item(wccp_tree, hf_wccp_version,
127                             offset, 4, wccp_version);
128                         offset += 4;
129                         dissect_hash_data(pd, offset, wccp_tree);
130                         offset += HASH_INFO_SIZE;
131                         proto_tree_add_item(wccp_tree, hf_recvd_id, offset,
132                             4, pntohl(&pd[offset]));
133                         offset += 4;
134                         break;
135
136                 case WCCP_I_SEE_YOU:
137                         wccp_version = pntohl(&pd[offset]);
138                         proto_tree_add_item(wccp_tree, hf_wccp_version,
139                             offset, 4, wccp_version);
140                         offset += 4;
141                         proto_tree_add_item(wccp_tree, hf_change_num, offset,
142                             4, pntohl(&pd[offset]));
143                         offset += 4;
144                         proto_tree_add_item(wccp_tree, hf_recvd_id, offset,
145                             4, pntohl(&pd[offset]));
146                         offset += 4;
147                         cache_count = pntohl(&pd[offset]);
148                         proto_tree_add_text(wccp_tree, offset, 4,
149                             "Number of Web Caches: %u", cache_count);
150                         offset += 4;
151                         for (i = 0; i < cache_count; i++) {
152                                 dissect_web_cache_list_entry(pd, offset, i,
153                                     wccp_tree);
154                                 offset += 4 + HASH_INFO_SIZE;
155                         }
156                         break;
157
158                 case WCCP_ASSIGN_BUCKET:
159                         /*
160                          * This hasn't been tested, since I don't have any
161                          * traces with this in it.
162                          */
163                         proto_tree_add_item(wccp_tree, hf_recvd_id, offset,
164                             4, pntohl(&pd[offset]));
165                         offset += 4;
166                         cache_count = pntohl(&pd[offset]);
167                         proto_tree_add_text(wccp_tree, offset, 4,
168                             "Number of Web Caches: %u", cache_count);
169                         offset += 4;
170                         for (i = 0; i < cache_count; i++) {
171                                 proto_tree_add_item_format(wccp_tree,
172                                     hf_cache_ip, offset, 4,
173                                     pntohl(&pd[offset]),
174                                     "Web Cache %d IP Address: %s", i,
175                                     ip_to_str((guint8 *) &pd[offset]));
176                                 offset += 4;
177                         }
178                         for (i = 0; i < 256; i += 4) {
179                                 proto_tree_add_text(wccp_tree, offset, 4,
180                                     "Buckets %d - %d: %10s %10s %10s %10s",
181                                     i, i + 3,
182                                     bucket_name(pd[offset]),
183                                     bucket_name(pd[offset+1]),
184                                     bucket_name(pd[offset+2]),
185                                     bucket_name(pd[offset+3]));
186                                 offset += 4;
187                         }
188                         break;
189
190                 default:
191                         wccp_version = pntohl(&pd[offset]);
192                         proto_tree_add_item(wccp_tree, hf_wccp_version,
193                             offset, 4, wccp_version);
194                         offset += 4;
195                         dissect_data(pd, offset, fd, wccp_tree);
196                         break;
197                 }
198         }
199 }
200
201 static void
202 dissect_hash_data(const u_char *pd, int offset, proto_tree *wccp_tree)
203 {
204         proto_item *bucket_item;
205         proto_tree *bucket_tree;
206         proto_item *tf;
207         proto_tree *field_tree;
208         int i;
209         guint8 bucket_info;
210         int n;
211         guint32 flags;
212
213         proto_tree_add_item(wccp_tree, hf_hash_revision, offset, 4,
214             pntohl(&pd[offset]));
215         offset += 4;
216
217         bucket_item = proto_tree_add_text(wccp_tree, offset, 32,
218             "Hash information");
219         bucket_tree = proto_item_add_subtree(bucket_item, ett_buckets);
220
221         for (i = 0, n = 0; i < 32; i++) {
222                 bucket_info = pd[offset];
223                 n = wccp_bucket_info(bucket_info, bucket_tree, n, offset);
224                 offset += 1;
225         }
226         flags = pntohl(&pd[offset]);
227         tf = proto_tree_add_text(wccp_tree, offset, 4,
228             "Flags: 0x%08X (%s)", flags,
229             ((flags & WCCP_U_FLAG) ?
230               "Hash information is historical" :
231               "Hash information is current"));
232         field_tree = proto_item_add_subtree(tf, ett_flags);
233         proto_tree_add_text(field_tree, offset, 4, "%s",
234             decode_boolean_bitfield(flags, WCCP_U_FLAG,
235               sizeof (flags)*8,
236               "Hash information is historical",
237               "Hash information is current"));
238 }
239
240 static void
241 dissect_web_cache_list_entry(const u_char *pd, int offset, int index,
242     proto_tree *wccp_tree)
243 {
244         proto_item *tl;
245         proto_tree *list_entry_tree;
246
247         tl = proto_tree_add_text(wccp_tree, offset, 4 + HASH_INFO_SIZE,
248             "Web-Cache List Entry(%d)", index);
249         list_entry_tree = proto_item_add_subtree(tl,
250             ett_cache_info);
251         proto_tree_add_item(list_entry_tree, hf_cache_ip, offset, 4,
252             pntohl(&pd[offset]));
253         dissect_hash_data(pd, offset + 4, list_entry_tree);
254 }
255
256 /*
257  * wccp_bucket_info()
258  * takes an integer representing a "Hash Information" bitmap, and spits out
259  * the corresponding proto_tree entries, returning the next bucket number.
260  */
261 static int
262 wccp_bucket_info(guint8 bucket_info, proto_tree *bucket_tree, guint32 start,
263     int offset)
264 {
265         guint32 i;
266
267         for(i = 0; i < 8; i++) {
268                 proto_tree_add_text(bucket_tree, offset, sizeof(bucket_info), "Bucket %3d: %s", start, (bucket_info & 1<<i ? "Assigned" : "Not Assigned") );
269                 start++;
270         }
271         return(start);
272 }
273
274 static gchar *
275 bucket_name(guint8 bucket)
276 {
277         static gchar str[4][10+1];
278         static gchar *cur;
279
280         if (cur == &str[0][0])
281                 cur = &str[1][0];
282         else if (cur == &str[1][0])
283                 cur = &str[2][0];
284         else if (cur == &str[2][0])
285                 cur = &str[3][0];
286         else
287                 cur = &str[0][0];
288         if (bucket == 0xff)
289                 strcpy(cur, "Unassigned");
290         else
291                 sprintf(cur, "%u", bucket);
292         return cur;
293 }
294
295 void
296 proto_register_wccp(void)
297 {
298         static hf_register_info hf[] = {
299                 { &hf_wccp_message_type,
300                         { "WCCP Message Type", "wccp.message", FT_UINT32, BASE_DEC, VALS(wccp_type_vals), 0x0,
301                                 "The WCCP message that was sent"}
302                 },
303                 { &hf_wccp_version, 
304                         { "WCCP Version", "wccp.version", FT_UINT32, BASE_DEC, VALS(wccp_version_val), 0x0,
305                                 "The WCCP version"}
306                 },
307                 { &hf_hash_revision,
308                         { "Hash Revision", "wccp.hash_revision", FT_UINT32, BASE_DEC, 0x0, 0x0,
309                                 "The cache hash revision"}
310                 },
311                 { &hf_change_num,
312                         { "Change Number", "wccp.change_num", FT_UINT32, BASE_DEC, 0x0, 0x0,
313                                 "The Web-Cache list entry change number"}
314                 },
315                 { &hf_recvd_id,
316                         { "Received ID", "wccp.recvd_id", FT_UINT32, BASE_DEC, 0x0, 0x0,
317                                 "The number of I_SEE_YOU's that have been sent"}
318                 },
319                 { &hf_cache_ip,
320                         { "Web Cache IP address", "wccp.cache_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
321                                 "The IP address of a Web cache"}
322                 },
323         };
324         static gint *ett[] = {
325                 &ett_wccp,
326                 &ett_cache_count,
327                 &ett_buckets,
328                 &ett_flags,
329                 &ett_cache_info,
330         };
331
332         proto_wccp = proto_register_protocol("Web Cache Coordination Protocol",
333             "wccp");
334         proto_register_field_array(proto_wccp, hf, array_length(hf));
335         proto_register_subtree_array(ett, array_length(ett));
336 }