2 * Routines for Web Cache Coordination Protocol dissection
3 * Jerry Talkington <jerryt@netapp.com>
5 * $Id: packet-wccp.c,v 1.16 2001/01/09 06:31:44 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@zing.org>
9 * Copyright 1998 Gerald Combs
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.
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.
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.
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
43 #include "packet-wccp.h"
45 static int proto_wccp = -1;
46 static int hf_wccp_message_type = -1; /* the message type */
47 static int hf_wccp_version = -1; /* protocol version */
48 static int hf_hash_revision = -1; /* the version of the hash */
49 static int hf_change_num = -1; /* change number */
50 static int hf_recvd_id = -1;
51 static int hf_cache_ip = -1;
53 static gint ett_wccp = -1;
54 static gint ett_cache_count = -1;
55 static gint ett_buckets = -1;
56 static gint ett_flags = -1;
57 static gint ett_cache_info = -1;
58 static gint ett_security_info = -1;
59 static gint ett_service_info = -1;
60 static gint ett_service_flags = -1;
61 static gint ett_router_identity_element = -1;
62 static gint ett_router_identity_info = -1;
63 static gint ett_wc_identity_element = -1;
64 static gint ett_wc_identity_info = -1;
65 static gint ett_router_view_info = -1;
66 static gint ett_wc_view_info = -1;
67 static gint ett_router_assignment_element = -1;
68 static gint ett_router_assignment_info = -1;
69 static gint ett_query_info = -1;
70 static gint ett_unknown_info = -1;
71 static gint ett_capabilities_info = -1;
72 static gint ett_capability_element = -1;
77 * http://www.ietf.org/internet-drafts/draft-forster-wrec-wccp-v1-00.txt
81 * http://www.ietf.org/internet-drafts/draft-wilson-wrec-wccp-v2-00.txt
83 * for WCCP 2.0, if they haven't expired yet.
86 #define UDP_PORT_WCCP 2048
89 #define WCCP_HERE_I_AM 7
90 #define WCCP_I_SEE_YOU 8
91 #define WCCP_ASSIGN_BUCKET 9
92 #define WCCP2_HERE_I_AM 10
93 #define WCCP2_I_SEE_YOU 11
94 #define WCCP2_REDIRECT_ASSIGN 12
95 #define WCCP2_REMOVAL_QUERY 13
97 static const value_string wccp_type_vals[] = {
98 { WCCP_HERE_I_AM, "1.0 Here I am" },
99 { WCCP_I_SEE_YOU, "1.0 I see you" },
100 { WCCP_ASSIGN_BUCKET, "1.0 Assign bucket" },
101 { WCCP2_HERE_I_AM, "2.0 Here I am" },
102 { WCCP2_I_SEE_YOU, "2.0 I see you" },
103 { WCCP2_REDIRECT_ASSIGN, "2.0 Redirect assign" },
104 { WCCP2_REMOVAL_QUERY, "2.0 Removal query" },
108 static const value_string wccp_version_val[] = {
113 #define HASH_INFO_SIZE (4*(1+8+1))
115 #define WCCP_U_FLAG 0x80000000
117 #define WCCP2_SECURITY_INFO 0
118 #define WCCP2_SERVICE_INFO 1
119 #define WCCP2_ROUTER_ID_INFO 2
120 #define WCCP2_WC_ID_INFO 3
121 #define WCCP2_RTR_VIEW_INFO 4
122 #define WCCP2_WC_VIEW_INFO 5
123 #define WCCP2_REDIRECT_ASSIGNMENT 6
124 #define WCCP2_QUERY_INFO 7
125 #define WCCP2_CAPABILITIES_INFO 8
126 #define WCCP2_ALT_ASSIGNMENT 13
127 #define WCCP2_ASSIGN_MAP 14
128 #define WCCP2_COMMAND_EXTENSION 15
130 static const value_string info_type_vals[] = {
131 { WCCP2_SECURITY_INFO, "Security Info" },
132 { WCCP2_SERVICE_INFO, "Service Info" },
133 { WCCP2_ROUTER_ID_INFO, "Router Identity Info" },
134 { WCCP2_WC_ID_INFO, "Web-Cache Identity Info" },
135 { WCCP2_RTR_VIEW_INFO, "Router View Info" },
136 { WCCP2_WC_VIEW_INFO, "Web-Cache View Info" },
137 { WCCP2_REDIRECT_ASSIGNMENT, "Assignment Info" },
138 { WCCP2_QUERY_INFO, "Query Info" },
139 { WCCP2_CAPABILITIES_INFO, "Capabilities Info" },
140 { WCCP2_COMMAND_EXTENSION, "Command Extension" },
144 const value_string service_id_vals[] = {
149 static void dissect_hash_data(tvbuff_t *tvb, int offset,
150 proto_tree *wccp_tree);
151 static void dissect_web_cache_list_entry(tvbuff_t *tvb, int offset,
152 int index, proto_tree *wccp_tree);
153 static int wccp_bucket_info(guint8 bucket_info, proto_tree *bucket_tree,
154 guint32 start, tvbuff_t *tvb, int offset);
155 static gchar *bucket_name(guint8 bucket);
156 static guint16 dissect_wccp2_header(tvbuff_t *tvb, int offset,
157 proto_tree *wccp_tree);
158 static void dissect_wccp2_info(tvbuff_t *tvb, int offset, guint16 length,
159 proto_tree *wccp_tree);
160 static gboolean dissect_wccp2_security_info(tvbuff_t *tvb, int offset,
161 int length, proto_tree *info_tree);
162 static gboolean dissect_wccp2_service_info(tvbuff_t *tvb, int offset,
163 int length, proto_tree *info_tree);
164 static gboolean dissect_wccp2_router_identity_info(tvbuff_t *tvb,
165 int offset, int length, proto_tree *info_tree);
166 static gboolean dissect_wccp2_wc_identity_info(tvbuff_t *tvb, int offset,
167 int length, proto_tree *info_tree);
168 static gboolean dissect_wccp2_router_view_info(tvbuff_t *tvb, int offset,
169 int length, proto_tree *info_tree);
170 static gboolean dissect_wccp2_wc_view_info(tvbuff_t *tvb, int offset,
171 int length, proto_tree *info_tree);
172 static gboolean dissect_wccp2_assignment_info(tvbuff_t *tvb, int offset,
173 int length, proto_tree *info_tree);
174 static gboolean dissect_wccp2_router_query_info(tvbuff_t *tvb, int offset,
175 int length, proto_tree *info_tree);
176 static gboolean dissect_wccp2_capability_info(tvbuff_t *tvb, int offset,
177 int length, proto_tree *info_tree);
180 dissect_wccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
183 proto_tree *wccp_tree = NULL;
184 proto_item *wccp_tree_item;
185 guint32 wccp_message_type;
186 guint32 wccp_version;
191 CHECK_DISPLAY_AS_DATA(proto_wccp, tvb, pinfo, tree);
193 pinfo->current_proto = "WCCP";
195 if(check_col(pinfo->fd, COL_PROTOCOL)) {
196 col_set_str(pinfo->fd, COL_PROTOCOL, "WCCP");
199 wccp_message_type = tvb_get_ntohl(tvb, offset);
201 if(check_col(pinfo->fd, COL_INFO)) {
202 col_add_str(pinfo->fd, COL_INFO, val_to_str(wccp_message_type,
203 wccp_type_vals, "Unknown WCCP message (%u)"));
207 wccp_tree_item = proto_tree_add_item(tree, proto_wccp, tvb, offset,
208 tvb_length(tvb), FALSE);
209 wccp_tree = proto_item_add_subtree(wccp_tree_item, ett_wccp);
211 proto_tree_add_uint(wccp_tree, hf_wccp_message_type, tvb, offset,
212 sizeof(wccp_message_type), wccp_message_type);
213 offset += sizeof(wccp_message_type);
215 switch (wccp_message_type) {
218 wccp_version = tvb_get_ntohl(tvb, offset);
219 proto_tree_add_uint(wccp_tree, hf_wccp_version, tvb,
220 offset, 4, wccp_version);
222 dissect_hash_data(tvb, offset, wccp_tree);
223 offset += HASH_INFO_SIZE;
224 proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
230 wccp_version = tvb_get_ntohl(tvb, offset);
231 proto_tree_add_uint(wccp_tree, hf_wccp_version, tvb,
232 offset, 4, wccp_version);
234 proto_tree_add_item(wccp_tree, hf_change_num, tvb, offset,
237 proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
240 cache_count = tvb_get_ntohl(tvb, offset);
241 proto_tree_add_text(wccp_tree, tvb, offset, 4,
242 "Number of Web Caches: %u", cache_count);
244 for (i = 0; i < cache_count; i++) {
245 dissect_web_cache_list_entry(tvb, offset, i,
247 offset += 4 + HASH_INFO_SIZE;
251 case WCCP_ASSIGN_BUCKET:
253 * This hasn't been tested, since I don't have any
254 * traces with this in it.
256 proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
259 cache_count = tvb_get_ntohl(tvb, offset);
260 proto_tree_add_text(wccp_tree, tvb, offset, 4,
261 "Number of Web Caches: %u", cache_count);
263 for (i = 0; i < cache_count; i++) {
264 proto_tree_add_ipv4_format(wccp_tree,
265 hf_cache_ip, tvb, offset, 4,
266 tvb_get_ntohl(tvb, offset),
267 "Web Cache %d IP Address: %s", i,
268 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
271 for (i = 0; i < 256; i += 4) {
272 proto_tree_add_text(wccp_tree, tvb, offset, 4,
273 "Buckets %d - %d: %10s %10s %10s %10s",
275 bucket_name(tvb_get_guint8(tvb, offset)),
276 bucket_name(tvb_get_guint8(tvb, offset+1)),
277 bucket_name(tvb_get_guint8(tvb, offset+2)),
278 bucket_name(tvb_get_guint8(tvb, offset+3)));
283 case WCCP2_HERE_I_AM:
284 case WCCP2_I_SEE_YOU:
285 case WCCP2_REMOVAL_QUERY:
286 case WCCP2_REDIRECT_ASSIGN:
287 length = dissect_wccp2_header(tvb, offset, wccp_tree);
290 dissect_wccp2_info(tvb, offset, length, wccp_tree);
294 wccp_version = tvb_get_ntohl(tvb, offset);
295 proto_tree_add_uint(wccp_tree, hf_wccp_version, tvb,
296 offset, 4, wccp_version);
298 dissect_data(tvb, offset, pinfo, wccp_tree);
305 dissect_hash_data(tvbuff_t *tvb, int offset, proto_tree *wccp_tree)
307 proto_item *bucket_item;
308 proto_tree *bucket_tree;
310 proto_tree *field_tree;
316 proto_tree_add_item(wccp_tree, hf_hash_revision, tvb, offset, 4,
320 bucket_item = proto_tree_add_text(wccp_tree, tvb, offset, 32,
322 bucket_tree = proto_item_add_subtree(bucket_item, ett_buckets);
324 for (i = 0, n = 0; i < 32; i++) {
325 bucket_info = tvb_get_guint8(tvb, offset);
326 n = wccp_bucket_info(bucket_info, bucket_tree, n, tvb, offset);
329 flags = tvb_get_ntohl(tvb, offset);
330 tf = proto_tree_add_text(wccp_tree, tvb, offset, 4,
331 "Flags: 0x%08X (%s)", flags,
332 ((flags & WCCP_U_FLAG) ?
333 "Hash information is historical" :
334 "Hash information is current"));
335 field_tree = proto_item_add_subtree(tf, ett_flags);
336 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
337 decode_boolean_bitfield(flags, WCCP_U_FLAG,
339 "Hash information is historical",
340 "Hash information is current"));
344 dissect_web_cache_list_entry(tvbuff_t *tvb, int offset, int index,
345 proto_tree *wccp_tree)
348 proto_tree *list_entry_tree;
350 tl = proto_tree_add_text(wccp_tree, tvb, offset, 4 + HASH_INFO_SIZE,
351 "Web-Cache List Entry(%d)", index);
352 list_entry_tree = proto_item_add_subtree(tl, ett_cache_info);
353 proto_tree_add_item(list_entry_tree, hf_cache_ip, tvb, offset, 4,
355 dissect_hash_data(tvb, offset + 4, list_entry_tree);
360 * takes an integer representing a "Hash Information" bitmap, and spits out
361 * the corresponding proto_tree entries, returning the next bucket number.
364 wccp_bucket_info(guint8 bucket_info, proto_tree *bucket_tree, guint32 start,
365 tvbuff_t *tvb, int offset)
369 for(i = 0; i < 8; i++) {
370 proto_tree_add_text(bucket_tree, tvb, offset, sizeof(bucket_info), "Bucket %3d: %s", start, (bucket_info & 1<<i ? "Assigned" : "Not Assigned") );
377 bucket_name(guint8 bucket)
379 static gchar str[4][10+1];
382 if (cur == &str[0][0])
384 else if (cur == &str[1][0])
386 else if (cur == &str[2][0])
391 strcpy(cur, "Unassigned");
393 sprintf(cur, "%u", bucket);
398 dissect_wccp2_header(tvbuff_t *tvb, int offset, proto_tree *wccp_tree)
402 proto_tree_add_text(wccp_tree, tvb, offset, 2, "Version: 0x%04X",
403 tvb_get_ntohs(tvb, offset));
405 length = tvb_get_ntohs(tvb, offset);
406 proto_tree_add_text(wccp_tree, tvb, offset, 2, "Length: %u",
412 dissect_wccp2_info(tvbuff_t *tvb, int offset, guint16 length,
413 proto_tree *wccp_tree)
418 proto_tree *info_tree;
420 gboolean (*dissector)(tvbuff_t *, int, int, proto_tree *);
422 while (length != 0) {
423 type = tvb_get_ntohs(tvb, offset);
424 item_length = tvb_get_ntohs(tvb, offset+2);
428 case WCCP2_SECURITY_INFO:
429 ett = ett_security_info;
430 dissector = dissect_wccp2_security_info;
433 case WCCP2_SERVICE_INFO:
434 ett = ett_service_info;
435 dissector = dissect_wccp2_service_info;
438 case WCCP2_ROUTER_ID_INFO:
439 ett = ett_router_identity_info;
440 dissector = dissect_wccp2_router_identity_info;
443 case WCCP2_WC_ID_INFO:
444 ett = ett_wc_identity_info;
445 dissector = dissect_wccp2_wc_identity_info;
448 case WCCP2_RTR_VIEW_INFO:
449 ett = ett_router_view_info;
450 dissector = dissect_wccp2_router_view_info;
453 case WCCP2_WC_VIEW_INFO:
454 ett = ett_wc_view_info;
455 dissector = dissect_wccp2_wc_view_info;
458 case WCCP2_REDIRECT_ASSIGNMENT:
459 ett = ett_router_assignment_info;
460 dissector = dissect_wccp2_assignment_info;
463 case WCCP2_QUERY_INFO:
464 ett = ett_query_info;
465 dissector = dissect_wccp2_router_query_info;
468 case WCCP2_CAPABILITIES_INFO:
469 ett = ett_capabilities_info;
470 dissector = dissect_wccp2_capability_info;
474 ett = ett_unknown_info;
479 ti = proto_tree_add_text(wccp_tree, tvb, offset, item_length + 4,
480 val_to_str(type, info_type_vals, "Unknown info type (%u)"));
481 info_tree = proto_item_add_subtree(ti, ett);
482 proto_tree_add_text(info_tree, tvb, offset, 2,
484 val_to_str(type, info_type_vals, "Unknown info type (%u)"));
485 proto_tree_add_text(info_tree, tvb, offset+2, 2,
486 "Length: %u", item_length);
491 * XXX - pass in "length" and check for that as well.
493 if (dissector != NULL) {
494 if (!(*dissector)(tvb, offset, item_length, info_tree))
495 return; /* ran out of data */
497 proto_tree_add_text(info_tree, tvb, offset, item_length,
498 "Data: %u byte%s", item_length,
499 plurality(item_length, "", "s"));
501 offset += item_length;
502 length -= item_length;
506 #define SECURITY_INFO_LEN 4
508 #define WCCP2_NO_SECURITY 0
509 #define WCCP2_MD5_SECURITY 1
512 dissect_wccp2_security_info(tvbuff_t *tvb, int offset, int length,
513 proto_tree *info_tree)
515 guint32 security_option;
517 if (length < SECURITY_INFO_LEN) {
518 proto_tree_add_text(info_tree, tvb, offset, 0,
519 "Item length is %u, should be %u", length,
524 security_option = tvb_get_ntohl(tvb, offset);
525 switch (security_option) {
527 case WCCP2_NO_SECURITY:
528 proto_tree_add_text(info_tree, tvb, offset, 4,
529 "Security Option: None");
532 case WCCP2_MD5_SECURITY:
533 proto_tree_add_text(info_tree, tvb, offset, 4,
534 "Security Option: MD5");
537 proto_tree_add_text(info_tree, tvb, offset,
538 length - 4, "MD5 checksum: %s",
539 tvb_bytes_to_str(tvb, offset, length - 4));
544 proto_tree_add_text(info_tree, tvb, offset, 4,
545 "Security Option: Unknown (%u)", security_option);
551 #define SERVICE_INFO_LEN (4+4+8*2)
553 #define WCCP2_SERVICE_STANDARD 0
554 #define WCCP2_SERVICE_DYNAMIC 1
559 #define WCCP2_SI_SRC_IP_HASH 0x0001
560 #define WCCP2_SI_DST_IP_HASH 0x0002
561 #define WCCP2_SI_SRC_PORT_HASH 0x0004
562 #define WCCP2_SI_DST_PORT_HASH 0x0008
563 #define WCCP2_SI_PORTS_DEFINED 0x0010
564 #define WCCP2_SI_PORTS_SOURCE 0x0020
565 #define WCCP2_SI_SRC_IP_ALT_HASH 0x0100
566 #define WCCP2_SI_DST_IP_ALT_HASH 0x0200
567 #define WCCP2_SI_SRC_PORT_ALT_HASH 0x0400
568 #define WCCP2_SI_DST_PORT_ALT_HASH 0x0800
571 dissect_wccp2_service_info(tvbuff_t *tvb, int offset, int length,
572 proto_tree *info_tree)
577 proto_tree *field_tree;
580 if (length != SERVICE_INFO_LEN) {
581 proto_tree_add_text(info_tree, tvb, offset, 0,
582 "Item length is %u, should be %u", length,
587 service_type = tvb_get_guint8(tvb, offset);
588 switch (service_type) {
590 case WCCP2_SERVICE_STANDARD:
591 proto_tree_add_text(info_tree, tvb, offset, 1,
592 "Service Type: Well-known service");
593 proto_tree_add_text(info_tree, tvb, offset+1, 1,
595 val_to_str(tvb_get_guint8(tvb, offset+1), service_id_vals, "Unknown (0x%02X)"));
598 case WCCP2_SERVICE_DYNAMIC:
599 proto_tree_add_text(info_tree, tvb, offset, 1,
600 "Service Type: Dynamic service");
601 proto_tree_add_text(info_tree, tvb, offset+2, 1,
602 "Priority: %u", tvb_get_guint8(tvb, offset+2));
604 * XXX - does "IP protocol identifier" mean this is a
605 * protocol type of the sort you get in IP headers?
606 * If so, we should get a table of those from the
607 * IP dissector, and use that.
609 proto_tree_add_text(info_tree, tvb, offset+3, 1,
610 "Protocol: %u", tvb_get_guint8(tvb, offset+3)); /* IP protocol identifier */
614 proto_tree_add_text(info_tree, tvb, offset, 1,
615 "Service Type: Unknown (%u)", service_type);
620 flags = tvb_get_ntohl(tvb, offset);
621 tf = proto_tree_add_text(info_tree, tvb, offset, 4,
622 "Flags: 0x%08X", flags);
623 field_tree = proto_item_add_subtree(tf, ett_service_flags);
624 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
625 decode_boolean_bitfield(flags, WCCP2_SI_SRC_IP_HASH,
627 "Use source IP address in primary hash",
628 "Don't use source IP address in primary hash"));
629 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
630 decode_boolean_bitfield(flags, WCCP2_SI_DST_IP_HASH,
632 "Use destination IP address in primary hash",
633 "Don't use destination IP address in primary hash"));
634 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
635 decode_boolean_bitfield(flags, WCCP2_SI_SRC_PORT_HASH,
637 "Use source port in primary hash",
638 "Don't use source port in primary hash"));
639 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
640 decode_boolean_bitfield(flags, WCCP2_SI_DST_PORT_HASH,
642 "Use destination port in primary hash",
643 "Don't use destination port in primary hash"));
644 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
645 decode_boolean_bitfield(flags, WCCP2_SI_PORTS_DEFINED,
648 "Ports not defined"));
649 if (flags & WCCP2_SI_PORTS_DEFINED) {
650 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
651 decode_boolean_bitfield(flags, WCCP2_SI_PORTS_SOURCE,
653 "Ports refer to source port",
654 "Ports refer to destination port"));
656 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
657 decode_boolean_bitfield(flags, WCCP2_SI_SRC_IP_ALT_HASH,
659 "Use source IP address in secondary hash",
660 "Don't use source IP address in secondary hash"));
661 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
662 decode_boolean_bitfield(flags, WCCP2_SI_DST_IP_ALT_HASH,
664 "Use destination IP address in secondary hash",
665 "Don't use destination IP address in secondary hash"));
666 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
667 decode_boolean_bitfield(flags, WCCP2_SI_SRC_PORT_ALT_HASH,
669 "Use source port in secondary hash",
670 "Don't use source port in secondary hash"));
671 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
672 decode_boolean_bitfield(flags, WCCP2_SI_DST_PORT_ALT_HASH,
674 "Use destination port in secondary hash",
675 "Don't use destination port in secondary hash"));
678 if (flags & WCCP2_SI_PORTS_DEFINED) {
679 for (i = 0; i < 8; i++) {
680 proto_tree_add_text(info_tree, tvb, offset, 2,
681 "Port %d: %u", i, tvb_get_ntohs(tvb, offset));
689 #define ROUTER_ID_INFO_MIN_LEN (8+4+4)
692 dissect_wccp2_router_identity_element(tvbuff_t *tvb, int offset,
695 proto_tree_add_text(tree, tvb, offset, 4,
696 "IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
697 proto_tree_add_text(tree, tvb, offset + 4, 4,
698 "Receive ID: %u", tvb_get_ntohl(tvb, offset + 4));
702 dissect_wccp2_router_identity_info(tvbuff_t *tvb, int offset, int length,
703 proto_tree *info_tree)
705 guint32 n_received_from;
708 proto_tree *element_tree;
710 if (length < ROUTER_ID_INFO_MIN_LEN) {
711 proto_tree_add_text(info_tree, tvb, offset, 0,
712 "Item length is %u, should be >= %u", length,
713 ROUTER_ID_INFO_MIN_LEN);
717 te = proto_tree_add_text(info_tree, tvb, offset, 8,
718 "Router Identity Element: IP address %s",
719 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
720 element_tree = proto_item_add_subtree(te,
721 ett_router_identity_element);
722 dissect_wccp2_router_identity_element(tvb, offset, element_tree);
725 proto_tree_add_text(info_tree, tvb, offset, 4,
726 "Sent To IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
729 n_received_from = tvb_get_ntohl(tvb, offset);
730 proto_tree_add_text(info_tree, tvb, offset, 4,
731 "Number of Received From IP addresses: %u", n_received_from);
734 for (i = 0; i < n_received_from; i++) {
735 proto_tree_add_text(info_tree, tvb, offset, 4,
736 "Received From IP Address %d: %s", i,
737 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
744 #define WC_ID_INFO_LEN (4+4+8*4+4)
747 dissect_wccp2_web_cache_identity_element(tvbuff_t *tvb, int offset,
750 proto_item *bucket_item;
751 proto_tree *bucket_tree;
753 proto_tree *field_tree;
759 proto_tree_add_text(tree, tvb, offset, 4,
760 "Web-Cache IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
763 proto_tree_add_text(tree, tvb, offset, 2,
764 "Hash Revision %u", tvb_get_ntohs(tvb, offset));
767 flags = tvb_get_ntohs(tvb, offset);
768 tf = proto_tree_add_text(tree, tvb, offset, 2,
769 "Flags: 0x%04X (%s)", flags,
771 "Hash information is historical" :
772 "Hash information is current"));
773 field_tree = proto_item_add_subtree(tf, ett_flags);
774 proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
775 decode_boolean_bitfield(flags, 0x8000,
777 "Hash information is historical",
778 "Hash information is current"));
781 bucket_item = proto_tree_add_text(tree, tvb, offset, 8*4,
783 bucket_tree = proto_item_add_subtree(bucket_item, ett_buckets);
784 for (i = 0, n = 0; i < 32; i++) {
785 bucket_info = tvb_get_guint8(tvb, offset);
786 n = wccp_bucket_info(bucket_info, bucket_tree, n, tvb, offset);
790 proto_tree_add_text(tree, tvb, offset, 2,
791 "Assignment Weight: %u", tvb_get_ntohs(tvb, offset));
794 proto_tree_add_text(tree, tvb, offset, 2,
795 "Status: 0x%04X", tvb_get_ntohs(tvb, offset));
802 dissect_wccp2_wc_identity_info(tvbuff_t *tvb, int offset, int length,
803 proto_tree *info_tree)
806 proto_tree *element_tree;
808 if (length != WC_ID_INFO_LEN) {
809 proto_tree_add_text(info_tree, tvb, offset, 0,
810 "Item length is %u, should be %u", length, WC_ID_INFO_LEN);
814 te = proto_tree_add_text(info_tree, tvb, offset, 4+2+2+32+2+2,
815 "Web-Cache Identity Element: IP address %s",
816 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
817 element_tree = proto_item_add_subtree(te, ett_wc_identity_element);
818 if (!dissect_wccp2_web_cache_identity_element(tvb, offset,
820 return FALSE; /* ran out of data */
825 #define ROUTER_VIEW_INFO_MIN_LEN (4+8+4)
828 dissect_wccp2_assignment_key(tvbuff_t *tvb, int offset,
829 proto_tree *info_tree)
831 proto_tree_add_text(info_tree, tvb, offset, 4,
832 "Assignment Key IP Address: %s",
833 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
834 proto_tree_add_text(info_tree, tvb, offset + 4, 4,
835 "Assignment Key Change Number: %u", tvb_get_ntohl(tvb, offset + 4));
839 dissect_wccp2_router_view_info(tvbuff_t *tvb, int offset, int length,
840 proto_tree *info_tree)
843 guint32 n_web_caches;
846 proto_tree *element_tree;
848 if (length < ROUTER_VIEW_INFO_MIN_LEN) {
849 proto_tree_add_text(info_tree, tvb, offset, 0,
850 "Item length is %u, should be >= %u", length,
851 ROUTER_VIEW_INFO_MIN_LEN);
855 proto_tree_add_text(info_tree, tvb, offset, 4,
856 "Member Change Number: %u", tvb_get_ntohl(tvb, offset));
859 dissect_wccp2_assignment_key(tvb, offset, info_tree);
862 n_routers = tvb_get_ntohl(tvb, offset);
863 proto_tree_add_text(info_tree, tvb, offset, 4,
864 "Number of Routers: %u", n_routers);
867 for (i = 0; i < n_routers; i++) {
868 proto_tree_add_text(info_tree, tvb, offset, 4,
869 "Router %d IP Address: %s", i,
870 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
874 n_web_caches = tvb_get_ntohl(tvb, offset);
875 proto_tree_add_text(info_tree, tvb, offset, 4,
876 "Number of Web Caches: %u", n_web_caches);
879 for (i = 0; i < n_web_caches; i++) {
880 te = proto_tree_add_text(info_tree, tvb, offset, WC_ID_INFO_LEN,
881 "Web-Cache Identity Element %d: IP address %s", i,
882 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
883 element_tree = proto_item_add_subtree(te,
884 ett_wc_identity_element);
885 if (!dissect_wccp2_web_cache_identity_element(tvb,
886 offset, element_tree))
887 return FALSE; /* ran out of data */
888 offset += WC_ID_INFO_LEN;
894 #define WC_VIEW_INFO_MIN_LEN (4+4)
897 dissect_wccp2_wc_view_info(tvbuff_t *tvb, int offset, int length,
898 proto_tree *info_tree)
901 guint32 n_web_caches;
904 proto_tree *element_tree;
906 if (length < WC_VIEW_INFO_MIN_LEN) {
907 proto_tree_add_text(info_tree, tvb, offset, 0,
908 "Item length is %u, should be >= %u", length,
909 WC_VIEW_INFO_MIN_LEN);
913 proto_tree_add_text(info_tree, tvb, offset, 4,
914 "Change Number: %u", tvb_get_ntohl(tvb, offset));
917 n_routers = tvb_get_ntohl(tvb, offset);
918 proto_tree_add_text(info_tree, tvb, offset, 4,
919 "Number of Routers: %u", n_routers);
922 for (i = 0; i < n_routers; i++) {
923 te = proto_tree_add_text(info_tree, tvb, offset, 8,
924 "Router %d Identity Element: IP address %s", i,
925 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
926 element_tree = proto_item_add_subtree(te,
927 ett_router_identity_element);
928 dissect_wccp2_router_identity_element(tvb, offset, element_tree);
932 n_web_caches = tvb_get_ntohl(tvb, offset);
933 proto_tree_add_text(info_tree, tvb, offset, 4,
934 "Number of Web Caches: %u", n_web_caches);
937 for (i = 0; i < n_web_caches; i++) {
938 proto_tree_add_text(info_tree, tvb, offset, 4,
939 "Web-Cache %d: IP address %s", i,
940 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
947 #define ASSIGNMENT_INFO_MIN_LEN (8+4)
950 dissect_wccp2_router_assignment_element(tvbuff_t *tvb, int offset,
953 proto_tree_add_text(tree, tvb, offset, 4,
954 "IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
955 proto_tree_add_text(tree, tvb, offset + 4, 4,
956 "Receive ID: %u", tvb_get_ntohl(tvb, offset + 4));
957 proto_tree_add_text(tree, tvb, offset + 8, 4,
958 "Change Number: %u", tvb_get_ntohl(tvb, offset + 8));
962 assignment_bucket_name(guint8 bucket)
964 static gchar str[4][10+1];
967 if (cur == &str[0][0])
969 else if (cur == &str[1][0])
971 else if (cur == &str[2][0])
976 strcpy(cur, "Unassigned");
978 sprintf(cur, "%u%s", bucket >> 1,
979 (bucket & 0x01) ? " (Alt)" : "");
985 dissect_wccp2_assignment_info(tvbuff_t *tvb, int offset, int length,
986 proto_tree *info_tree)
989 guint32 n_web_caches;
992 proto_tree *element_tree;
994 if (length < ASSIGNMENT_INFO_MIN_LEN) {
995 proto_tree_add_text(info_tree, tvb, offset, 0,
996 "Item length is %u, should be >= %u", length,
997 ASSIGNMENT_INFO_MIN_LEN);
1001 dissect_wccp2_assignment_key(tvb, offset, info_tree);
1004 n_routers = tvb_get_ntohl(tvb, offset);
1005 proto_tree_add_text(info_tree, tvb, offset, 4,
1006 "Number of Routers: %u", n_routers);
1009 for (i = 0; i < n_routers; i++) {
1010 te = proto_tree_add_text(info_tree, tvb, offset, 4,
1011 "Router %d Assignment Element: IP address %s", i,
1012 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1013 element_tree = proto_item_add_subtree(te,
1014 ett_router_assignment_element);
1015 dissect_wccp2_router_assignment_element(tvb, offset,
1020 n_web_caches = tvb_get_ntohl(tvb, offset);
1021 proto_tree_add_text(info_tree, tvb, offset, 4,
1022 "Number of Web Caches: %u", n_web_caches);
1025 for (i = 0; i < n_web_caches; i++) {
1026 proto_tree_add_text(info_tree, tvb, offset, 4,
1027 "Web-Cache %d: IP address %s", i,
1028 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1032 for (i = 0; i < 256; i += 4) {
1033 proto_tree_add_text(info_tree, tvb, offset, 4,
1034 "Buckets %d - %d: %10s %10s %10s %10s",
1036 assignment_bucket_name(tvb_get_guint8(tvb, offset)),
1037 assignment_bucket_name(tvb_get_guint8(tvb, offset+1)),
1038 assignment_bucket_name(tvb_get_guint8(tvb, offset+2)),
1039 assignment_bucket_name(tvb_get_guint8(tvb, offset+3)));
1046 #define QUERY_INFO_LEN (4+4+4+4)
1049 dissect_wccp2_router_query_info(tvbuff_t *tvb, int offset, int length,
1050 proto_tree *info_tree)
1052 if (length != QUERY_INFO_LEN) {
1053 proto_tree_add_text(info_tree, tvb, offset, 0,
1054 "Item length is %u, should be %u", length, QUERY_INFO_LEN);
1058 proto_tree_add_text(info_tree, tvb, offset, 4,
1059 "Router IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1062 proto_tree_add_text(info_tree, tvb, offset, 4,
1063 "Receive ID: %u", tvb_get_ntohl(tvb, offset));
1066 proto_tree_add_text(info_tree, tvb, offset, 4,
1067 "Sent To IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1070 proto_tree_add_text(info_tree, tvb, offset, 4,
1071 "Target IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1077 #define WCCP2_FORWARDING_METHOD 0x01
1078 #define WCCP2_ASSIGNMENT_METHOD 0x02
1079 #define WCCP2_PACKET_RETURN_METHOD 0x03
1081 static const value_string capability_type_vals[] = {
1082 { WCCP2_FORWARDING_METHOD, "Forwarding Method" },
1083 { WCCP2_ASSIGNMENT_METHOD, "Assignment Method" },
1084 { WCCP2_PACKET_RETURN_METHOD, "Return Method" },
1088 #define WCCP2_FORWARDING_METHOD_GRE 0x00000001
1089 #define WCCP2_FORWARDING_METHOD_L2 0x00000002
1091 static const value_string forwarding_method_vals[] = {
1092 { WCCP2_FORWARDING_METHOD_GRE, "IP-GRE" },
1093 { WCCP2_FORWARDING_METHOD_L2, "L2" },
1097 #define WCCP2_ASSIGNMENT_METHOD_HASH 0x00000001
1098 #define WCCP2_ASSIGNMENT_METHOD_MASK 0x00000002
1100 static const value_string assignment_method_vals[] = {
1101 { WCCP2_ASSIGNMENT_METHOD_HASH, "Hash" },
1102 { WCCP2_ASSIGNMENT_METHOD_MASK, "Mask" },
1106 #define WCCP2_PACKET_RETURN_METHOD_GRE 0x00000001
1107 #define WCCP2_PACKET_RETURN_METHOD_L2 0x00000002
1109 static const value_string packet_return_method_vals[] = {
1110 { WCCP2_PACKET_RETURN_METHOD_GRE, "IP-GRE" },
1111 { WCCP2_PACKET_RETURN_METHOD_L2, "L2" },
1116 dissect_wccp2_capability_info(tvbuff_t *tvb, int offset, int length,
1117 proto_tree *info_tree)
1119 guint16 capability_type;
1120 guint16 capability_len;
1121 guint32 capability_val;
1124 proto_tree *element_tree;
1126 curr_offset = offset;
1127 while (curr_offset < (length + offset)) {
1128 capability_type = tvb_get_ntohs(tvb, curr_offset);
1129 capability_len = tvb_get_ntohs(tvb, curr_offset + 2);
1130 capability_val = tvb_get_ntohl(tvb, curr_offset + 4);
1131 te = proto_tree_add_text(info_tree, tvb, offset, 8,
1132 "Capability Element");
1133 element_tree = proto_item_add_subtree(te,
1134 ett_capability_element);
1136 proto_tree_add_text(element_tree, tvb, offset, 2,
1138 val_to_str(capability_type,
1139 capability_type_vals, "Unknown (0x%08X)"));
1140 proto_tree_add_text(element_tree, tvb, offset+2, 2,
1141 "Length: %u", capability_len);
1143 switch (capability_type) {
1145 case WCCP2_FORWARDING_METHOD:
1146 proto_tree_add_text(element_tree, tvb, offset+4, 4,
1148 val_to_str(capability_val,
1149 forwarding_method_vals, "Unknown (0x%08X)"));
1152 case WCCP2_ASSIGNMENT_METHOD:
1153 proto_tree_add_text(element_tree, tvb, offset+4, 4,
1155 val_to_str(capability_val,
1156 assignment_method_vals, "Unknown (0x%08X)"));
1159 case WCCP2_PACKET_RETURN_METHOD:
1160 proto_tree_add_text(element_tree, tvb, offset+4, 4,
1162 val_to_str(capability_val,
1163 packet_return_method_vals, "Unknown (0x%08X)"));
1167 proto_tree_add_text(element_tree, tvb, offset+4, 4,
1168 "Value: 0x%08X", capability_val);
1179 proto_register_wccp(void)
1181 static hf_register_info hf[] = {
1182 { &hf_wccp_message_type,
1183 { "WCCP Message Type", "wccp.message", FT_UINT32, BASE_DEC, VALS(wccp_type_vals), 0x0,
1184 "The WCCP message that was sent"}
1187 { "WCCP Version", "wccp.version", FT_UINT32, BASE_DEC, VALS(wccp_version_val), 0x0,
1190 { &hf_hash_revision,
1191 { "Hash Revision", "wccp.hash_revision", FT_UINT32, BASE_DEC, 0x0, 0x0,
1192 "The cache hash revision"}
1195 { "Change Number", "wccp.change_num", FT_UINT32, BASE_DEC, 0x0, 0x0,
1196 "The Web-Cache list entry change number"}
1199 { "Received ID", "wccp.recvd_id", FT_UINT32, BASE_DEC, 0x0, 0x0,
1200 "The number of I_SEE_YOU's that have been sent"}
1203 { "Web Cache IP address", "wccp.cache_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1204 "The IP address of a Web cache"}
1207 static gint *ett[] = {
1216 &ett_router_identity_element,
1217 &ett_router_identity_info,
1218 &ett_wc_identity_element,
1219 &ett_wc_identity_info,
1220 &ett_router_view_info,
1223 &ett_router_assignment_element,
1224 &ett_router_assignment_info,
1225 &ett_capabilities_info,
1226 &ett_capability_element,
1230 proto_wccp = proto_register_protocol("Web Cache Coordination Protocol",
1232 proto_register_field_array(proto_wccp, hf, array_length(hf));
1233 proto_register_subtree_array(ett, array_length(ett));
1237 proto_reg_handoff_wccp(void)
1239 dissector_add("udp.port", UDP_PORT_WCCP, dissect_wccp, proto_wccp);