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