Update Free Software Foundation address.
[metze/wireshark/wip.git] / epan / dissectors / packet-wccp.c
1 /* packet-wccp.c
2  * Routines for Web Cache Communication Protocol dissection
3  * Jerry Talkington <jtalkington@users.sourceforge.net>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/strutil.h>
33 #include <epan/emem.h>
34 #include <epan/expert.h>
35 #include "packet-wccp.h"
36
37 static int proto_wccp = -1;
38 static int hf_wccp_message_type = -1;   /* the message type */
39 static int hf_wccp_version = -1;        /* protocol version */
40 static int hf_wccp2_version = -1;
41 static int hf_hash_revision = -1;       /* the version of the hash */
42 static int hf_change_num = -1;          /* change number */
43 static int hf_hash_flag = -1;
44 static int hf_hash_flag_u = -1;
45 static int hf_recvd_id = -1;
46 static int hf_num_web_caches = -1;
47 static int hf_cache_ip = -1;
48 static int hf_item_header_length = -1;
49 static int hf_item_type = -1;
50 static int hf_item_length = -1;
51 static int hf_item_data = -1;
52 static int hf_security_option = -1;
53 static int hf_security_md5_checksum = -1;
54 static int hf_service_type = -1;
55 static int hf_service_id = -1;
56 static int hf_service_priority = -1;
57 static int hf_service_protocol = -1;
58 static int hf_service_flags = -1;
59 static int hf_service_flags_src_ip_hash = -1;
60 static int hf_service_flags_dest_ip_hash = -1;
61 static int hf_service_flags_src_port_hash = -1;
62 static int hf_service_flags_dest_port_hash = -1;
63 static int hf_service_flags_ports_defined = -1;
64 static int hf_service_flags_ports_source = -1;
65 static int hf_service_flags_src_ip_alt_hash = -1;
66 static int hf_service_flags_dest_ip_alt_hash = -1;
67 static int hf_service_flags_src_port_alt_hash = -1;
68 static int hf_service_flags_dest_port_alt_hash = -1;
69 static int hf_service_port = -1;
70 static int hf_router_identity_ip = -1;
71 static int hf_router_identity_receive_id = -1;
72 static int hf_router_send_to_ip = -1;
73 static int hf_router_num_recv_ip = -1;
74 static int hf_router_recv_ip = -1;
75 static int hf_web_cache_identity_ip = -1;
76 static int hf_web_cache_identity_hash_rev = -1;
77 static int hf_web_cache_identity_flags = -1;
78 static int hf_web_cache_identity_flag_hash_info = -1;
79 static int hf_web_cache_identity_flag_assign_type = -1;
80 static int hf_web_cache_identity_num_mask = -1;
81 static int hf_web_cache_identity_assign_mask = -1;
82 static int hf_web_cache_identity_assign_weight = -1;
83 static int hf_web_cache_identity_status = -1;
84 static int hf_assignment_key_ip = -1;
85 static int hf_assignment_key_change_num = -1;
86 static int hf_router_view_member_change_num = -1;
87 static int hf_router_router_num = -1;
88 static int hf_router_router_ip = -1;
89 static int hf_wc_view_info_change_num = -1;
90 static int hf_wc_view_router_num = -1;
91 static int hf_wc_view_ip = -1;
92 static int hf_router_assignment_element_ip = -1;
93 static int hf_router_assignment_element_receive_id = -1;
94 static int hf_router_assignment_element_change_num = -1;
95 static int hf_wccp2_assignment_info_router_num = -1;
96 static int hf_wccp2_assignment_info_ip = -1;
97 static int hf_router_query_info_ip = -1;
98 static int hf_router_query_info_receive_id = -1;
99 static int hf_router_query_info_send_to_ip = -1;
100 static int hf_router_query_info_target_ip = -1;
101 static int hf_capability_info_type = -1;
102 static int hf_capability_info_length = -1;
103 static int hf_capability_info_bytes = -1;
104 static int hf_capability_info_value = -1;
105 static int hf_capability_forwarding_method_flag_gre = -1;
106 static int hf_capability_forwarding_method_flag_l2 = -1;
107 static int hf_capability_assignment_method_flag_hash = -1;
108 static int hf_capability_assignment_method_flag_mask = -1;
109 static int hf_capability_return_method_flag_gre = -1;
110 static int hf_capability_return_method_flag_l2 = -1;
111 static int hf_wccp2_value_element_src_ip = -1;
112 static int hf_wccp2_value_element_dest_ip = -1;
113 static int hf_wccp2_value_element_src_port = -1;
114 static int hf_wccp2_value_element_dest_port = -1;
115 static int hf_wccp2_value_element_web_cache_ip = -1;
116 static int hf_wccp2_mask_value_set_element_src_ip = -1;
117 static int hf_wccp2_mask_value_set_element_dest_ip = -1;
118 static int hf_wccp2_mask_value_set_element_src_port = -1;
119 static int hf_wccp2_mask_value_set_element_dest_port = -1;
120 static int hf_wccp2_mask_value_set_element_num = -1;
121 static int hf_alt_assignment_info_assignment_type = -1;
122 static int hf_alt_assignment_info_assignment_length = -1;
123 static int hf_alt_assignment_info_num_routers = -1;
124 static int hf_alt_assignment_info_num_elements = -1;
125
126 static gint ett_wccp = -1;
127 static gint ett_cache_count = -1;
128 static gint ett_buckets = -1;
129 static gint ett_flags = -1;
130 static gint ett_cache_info = -1;
131 static gint ett_security_info = -1;
132 static gint ett_service_info = -1;
133 static gint ett_service_flags = -1;
134 static gint ett_router_identity_element = -1;
135 static gint ett_router_identity_info = -1;
136 static gint ett_wc_identity_element = -1;
137 static gint ett_wc_identity_info = -1;
138 static gint ett_router_view_info = -1;
139 static gint ett_wc_view_info = -1;
140 static gint ett_router_assignment_element = -1;
141 static gint ett_router_assignment_info = -1;
142 static gint ett_query_info = -1;
143 static gint ett_capabilities_info = -1;
144 static gint ett_capability_element = -1;
145 static gint ett_capability_forwarding_method = -1;
146 static gint ett_capability_assignment_method = -1;
147 static gint ett_capability_return_method = -1;
148 static gint ett_alt_assignment_info = -1;
149 static gint ett_mv_set_element = -1;
150 static gint ett_value_element = -1;
151 static gint ett_unknown_info = -1;
152
153 /*
154  * At
155  *
156  *      http://www.alternic.org/drafts/drafts-f-g/draft-forster-wrec-wccp-v1-00.html
157  *
158  * is a copy of the now-expired Internet-Draft for WCCP 1.0.
159  *
160  * At
161  *
162  *      http://tools.ietf.org/id/draft-wilson-wrec-wccp-v2-01.txt
163  *
164  * is an Internet-Draft for WCCP 2.0.
165  */
166
167 /* This is NOT IANA assigned */
168 #define UDP_PORT_WCCP   2048
169
170 #define WCCPv1                  4
171 #define WCCPv2                  0x0200
172 #define WCCP_HERE_I_AM          7
173 #define WCCP_I_SEE_YOU          8
174 #define WCCP_ASSIGN_BUCKET      9
175 #define WCCP2_HERE_I_AM         10
176 #define WCCP2_I_SEE_YOU         11
177 #define WCCP2_REDIRECT_ASSIGN   12
178 #define WCCP2_REMOVAL_QUERY     13
179
180 static const value_string wccp_type_vals[] = {
181     { WCCP_HERE_I_AM,        "1.0 Here I am" },
182     { WCCP_I_SEE_YOU,        "1.0 I see you" },
183     { WCCP_ASSIGN_BUCKET,    "1.0 Assign bucket" },
184     { WCCP2_HERE_I_AM,       "2.0 Here I am" },
185     { WCCP2_I_SEE_YOU,       "2.0 I see you" },
186     { WCCP2_REDIRECT_ASSIGN, "2.0 Redirect assign" },
187     { WCCP2_REMOVAL_QUERY,   "2.0 Removal query" },
188     { 0,                     NULL }
189 };
190
191 static const value_string wccp_version_val[] = {
192         { WCCPv1, "1"},
193         { WCCPv2, "2"},
194         { 0, NULL}
195 };
196
197 const true_false_string tfs_defined_not_defined = { "Defined", "Not defined" };
198 const true_false_string tfs_src_dest_port = { "Source port", "Destination port" };
199 const true_false_string tfs_historical_current = { "Historical", "Current" };
200 const true_false_string tfs_mask_hash = { "Mask", "Hash" };
201
202 #define HASH_INFO_SIZE  (4*(1+8+1))
203
204 #define WCCP_U_FLAG     0x80000000
205 #define WCCP_T_FLAG     0x4000
206
207 #define WCCP2_SECURITY_INFO             0
208 #define WCCP2_SERVICE_INFO              1
209 #define WCCP2_ROUTER_ID_INFO            2
210 #define WCCP2_WC_ID_INFO                3
211 #define WCCP2_RTR_VIEW_INFO             4
212 #define WCCP2_WC_VIEW_INFO              5
213 #define WCCP2_REDIRECT_ASSIGNMENT       6
214 #define WCCP2_QUERY_INFO                7
215 #define WCCP2_CAPABILITIES_INFO         8
216 #define WCCP2_ALT_ASSIGNMENT            13
217 #define WCCP2_ASSIGN_MAP                14
218 #define WCCP2_COMMAND_EXTENSION         15
219
220 static const value_string info_type_vals[] = {
221         { WCCP2_SECURITY_INFO,       "Security Info" },
222         { WCCP2_SERVICE_INFO,        "Service Info" },
223         { WCCP2_ROUTER_ID_INFO,      "Router Identity Info" },
224         { WCCP2_WC_ID_INFO,          "Web-Cache Identity Info" },
225         { WCCP2_RTR_VIEW_INFO,       "Router View Info" },
226         { WCCP2_WC_VIEW_INFO,        "Web-Cache View Info" },
227         { WCCP2_REDIRECT_ASSIGNMENT, "Assignment Info" },
228         { WCCP2_QUERY_INFO,          "Query Info" },
229         { WCCP2_CAPABILITIES_INFO,   "Capabilities Info" },
230         { WCCP2_ALT_ASSIGNMENT,      "Alternate Assignment" },
231         { WCCP2_ASSIGN_MAP,          "Assignment Map" },
232         { WCCP2_COMMAND_EXTENSION,   "Command Extension" },
233         { 0,                         NULL }
234 };
235
236 const value_string service_id_vals[] = {
237     { 0x00, "HTTP" },
238     { 0,    NULL }
239 };
240
241 typedef struct capability_flag {
242         guint32 value;
243         const char *short_name;
244         int* phf;
245 } capability_flag;
246
247 static void dissect_hash_data(tvbuff_t *tvb, int offset,
248     proto_tree *wccp_tree);
249 static void dissect_web_cache_list_entry(tvbuff_t *tvb, int offset,
250     int idx, proto_tree *wccp_tree);
251 static guint32 wccp_bucket_info(guint8 bucket_info, proto_tree *bucket_tree,
252     guint32 start, tvbuff_t *tvb, int offset);
253 static gchar *bucket_name(guint8 bucket);
254 static guint16 dissect_wccp2_header(tvbuff_t *tvb, int offset,
255     proto_tree *wccp_tree);
256 static void dissect_wccp2_info(tvbuff_t *tvb, int offset, guint16 length,
257     packet_info *pinfo, proto_tree *wccp_tree);
258 static gboolean dissect_wccp2_security_info(tvbuff_t *tvb, int offset,
259     int length, packet_info *pinfo, proto_tree *info_tree, proto_item *info_item);
260 static gboolean dissect_wccp2_service_info(tvbuff_t *tvb, int offset,
261     int length, packet_info *pinfo, proto_tree *info_tree, proto_item *info_item);
262 static gboolean dissect_wccp2_router_identity_info(tvbuff_t *tvb, int offset,
263     int length, packet_info *pinfo, proto_tree *info_tree, proto_item *info_item);
264 static gboolean dissect_wccp2_wc_identity_info(tvbuff_t *tvb, int offset,
265     int length, packet_info *pinfo, proto_tree *info_tree, proto_item *info_item);
266 static gboolean dissect_wccp2_router_view_info(tvbuff_t *tvb, int offset,
267     int length, packet_info *pinfo, proto_tree *info_tree, proto_item *info_item);
268 static gboolean dissect_wccp2_wc_view_info(tvbuff_t *tvb, int offset,
269     int length, packet_info *pinfo, proto_tree *info_tree, proto_item *info_item);
270 static gboolean dissect_wccp2_assignment_info(tvbuff_t *tvb, int offset,
271     int length, packet_info *pinfo, proto_tree *info_tree, proto_item *info_item);
272 static gboolean dissect_wccp2_router_query_info(tvbuff_t *tvb, int offset,
273     int length, packet_info *pinfo, proto_tree *info_tree, proto_item *info_item);
274 static gboolean dissect_wccp2_capability_info(tvbuff_t *tvb, int offset,
275     int length, packet_info *pinfo, proto_tree *info_tree, proto_item *info_item);
276 static void dissect_32_bit_capability_flags(tvbuff_t *tvb, int curr_offset,
277     guint16 capability_val_len, packet_info *pinfo, gint ett, const capability_flag *flags,
278     proto_tree *element_tree, proto_item *element_item);
279 static gboolean dissect_wccp2_alt_assignment_info(tvbuff_t *tvb, int offset,
280     int length, packet_info *pinfo, proto_tree *info_tree, proto_item *info_item);
281
282 static int
283 dissect_wccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
284 {
285         int offset = 0;
286         proto_tree *wccp_tree = NULL;
287         proto_item *wccp_tree_item;
288         guint32 wccp_message_type;
289         guint16 length;
290         guint32 cache_count;
291         guint32 ipaddr;
292         guint i;
293
294         wccp_message_type = tvb_get_ntohl(tvb, offset);
295
296         /* Check if this is really a WCCP message */
297         if (match_strval(wccp_message_type, wccp_type_vals) == NULL)
298                 return 0;
299
300         col_set_str(pinfo->cinfo, COL_PROTOCOL, "WCCP");
301         col_clear(pinfo->cinfo, COL_INFO);
302
303
304         if(check_col(pinfo->cinfo, COL_INFO)) {
305                 col_add_str(pinfo->cinfo, COL_INFO, val_to_str(wccp_message_type,
306                     wccp_type_vals, "Unknown WCCP message (%u)"));
307         }
308
309         if(tree != NULL) {
310                 wccp_tree_item = proto_tree_add_item(tree, proto_wccp, tvb, offset,
311                     -1, ENC_NA);
312                 wccp_tree = proto_item_add_subtree(wccp_tree_item, ett_wccp);
313
314                 proto_tree_add_uint(wccp_tree, hf_wccp_message_type, tvb, offset,
315                     4, wccp_message_type);
316                 offset += 4;
317
318                 switch (wccp_message_type) {
319
320                 case WCCP_HERE_I_AM:
321                         proto_tree_add_item(wccp_tree, hf_wccp_version, tvb, offset, 4, ENC_BIG_ENDIAN);
322                         offset += 4;
323                         dissect_hash_data(tvb, offset, wccp_tree);
324                         offset += HASH_INFO_SIZE;
325                         proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
326                             4, ENC_BIG_ENDIAN);
327                         offset += 4;
328                         break;
329
330                 case WCCP_I_SEE_YOU:
331                         proto_tree_add_item(wccp_tree, hf_wccp_version, tvb, offset, 4, ENC_BIG_ENDIAN);
332                         offset += 4;
333                         proto_tree_add_item(wccp_tree, hf_change_num, tvb, offset, 4, ENC_BIG_ENDIAN);
334                         offset += 4;
335                         proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset, 4, ENC_BIG_ENDIAN);
336                         offset += 4;
337                         cache_count = tvb_get_ntohl(tvb, offset);
338                         proto_tree_add_uint(wccp_tree, hf_num_web_caches, tvb, offset, 4, cache_count);
339                         offset += 4;
340                         for (i = 0; i < cache_count; i++) {
341                                 dissect_web_cache_list_entry(tvb, offset, i, wccp_tree);
342                                 offset += 4 + HASH_INFO_SIZE;
343                         }
344                         break;
345
346                 case WCCP_ASSIGN_BUCKET:
347                         /*
348                          * This hasn't been tested, since I don't have any
349                          * traces with this in it.
350                          *
351                          * The V1 spec claims that this does, indeed,
352                          * have a Received ID field after the type,
353                          * rather than a Version field.
354                          */
355                         proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset, 4, ENC_BIG_ENDIAN);
356                         offset += 4;
357                         cache_count = tvb_get_ntohl(tvb, offset);
358                         proto_tree_add_uint(wccp_tree, hf_num_web_caches, tvb, offset, 4, cache_count);
359                         offset += 4;
360                         for (i = 0; i < cache_count; i++) {
361                                 ipaddr = tvb_get_ipv4(tvb, offset);
362                                 proto_tree_add_ipv4_format(wccp_tree,
363                                     hf_cache_ip, tvb, offset, 4,
364                                     ipaddr,
365                                     "Web Cache %d IP Address: %s", i,
366                                     ip_to_str((guint8 *)&ipaddr));
367                                 offset += 4;
368                         }
369                         for (i = 0; i < 256; i += 4) {
370                                 proto_tree_add_text(wccp_tree, tvb, offset, 4,
371                                     "Buckets %d - %d: %10s %10s %10s %10s",
372                                     i, i + 3,
373                                     bucket_name(tvb_get_guint8(tvb, offset)),
374                                     bucket_name(tvb_get_guint8(tvb, offset+1)),
375                                     bucket_name(tvb_get_guint8(tvb, offset+2)),
376                                     bucket_name(tvb_get_guint8(tvb, offset+3)));
377                                 offset += 4;
378                         }
379                         break;
380
381                 case WCCP2_HERE_I_AM:
382                 case WCCP2_I_SEE_YOU:
383                 case WCCP2_REMOVAL_QUERY:
384                 case WCCP2_REDIRECT_ASSIGN:
385                 default:        /* assume unknown packets are v2 */
386                         length = dissect_wccp2_header(tvb, offset, wccp_tree);
387                         offset += 4;
388                         dissect_wccp2_info(tvb, offset, length, pinfo, wccp_tree);
389                         break;
390                 }
391         }
392
393         return(tvb_length(tvb));
394 }
395
396 static void
397 dissect_hash_data(tvbuff_t *tvb, int offset, proto_tree *wccp_tree)
398 {
399         proto_item *bucket_item;
400         proto_tree *bucket_tree;
401         proto_item *tf;
402         proto_tree *field_tree;
403         int i, n;
404         guint8 bucket_info;
405
406         proto_tree_add_item(wccp_tree, hf_hash_revision, tvb, offset, 4,
407             ENC_BIG_ENDIAN);
408         offset += 4;
409
410         bucket_item = proto_tree_add_text(wccp_tree, tvb, offset, 32,
411             "Hash information");
412         bucket_tree = proto_item_add_subtree(bucket_item, ett_buckets);
413
414         for (i = 0, n = 0; i < 32; i++) {
415                 bucket_info = tvb_get_guint8(tvb, offset);
416                 n = wccp_bucket_info(bucket_info, bucket_tree, n, tvb, offset);
417                 offset += 1;
418         }
419
420         tf = proto_tree_add_item(wccp_tree, hf_hash_flag, tvb, offset, 4, ENC_BIG_ENDIAN);
421         field_tree = proto_item_add_subtree(tf, ett_flags);
422         proto_tree_add_item(field_tree, hf_hash_flag_u, tvb, offset, 4, ENC_BIG_ENDIAN);
423 }
424
425 static void
426 dissect_web_cache_list_entry(tvbuff_t *tvb, int offset, int idx,
427     proto_tree *wccp_tree)
428 {
429         proto_item *tl;
430         proto_tree *list_entry_tree;
431
432         tl = proto_tree_add_text(wccp_tree, tvb, offset, 4 + HASH_INFO_SIZE,
433             "Web-Cache List Entry(%d)", idx);
434         list_entry_tree = proto_item_add_subtree(tl, ett_cache_info);
435         proto_tree_add_item(list_entry_tree, hf_cache_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
436         dissect_hash_data(tvb, offset + 4, list_entry_tree);
437 }
438
439 /*
440  * wccp_bucket_info()
441  * takes an integer representing a "Hash Information" bitmap, and spits out
442  * the corresponding proto_tree entries, returning the next bucket number.
443  */
444 static guint32
445 wccp_bucket_info(guint8 bucket_info, proto_tree *bucket_tree, guint32 start,
446     tvbuff_t *tvb, int offset)
447 {
448         guint32 i;
449
450         for(i = 0; i < 8; i++) {
451                 proto_tree_add_text(bucket_tree, tvb, offset, sizeof(bucket_info), "Bucket %3d: %s", start, (bucket_info & 1<<i ? "Assigned" : "Not Assigned") );
452                 start++;
453         }
454         return(start);
455 }
456
457 static gchar *
458 bucket_name(guint8 bucket)
459 {
460         gchar *cur;
461
462         if (bucket == 0xff) {
463                 cur="Unassigned";
464         } else {
465                 cur=ep_strdup_printf("%u", bucket);
466         }
467         return cur;
468 }
469
470 static guint16
471 dissect_wccp2_header(tvbuff_t *tvb, int offset, proto_tree *wccp_tree)
472 {
473         guint16 length;
474
475         proto_tree_add_item(wccp_tree, hf_wccp2_version, tvb, offset, 2, ENC_BIG_ENDIAN);
476         offset += 2;
477         length = tvb_get_ntohs(tvb, offset);
478         proto_tree_add_uint(wccp_tree, hf_item_header_length, tvb, offset, 2, length);
479         return length;
480 }
481
482 static void
483 dissect_wccp2_info(tvbuff_t *tvb, int offset, guint16 length,
484     packet_info *pinfo, proto_tree *wccp_tree)
485 {
486         guint16 type;
487         guint16 item_length;
488         proto_item *ti;
489         proto_tree *info_tree;
490         gint ett;
491         gboolean (*dissector)(tvbuff_t *, int, int, packet_info *, proto_tree *, proto_item *);
492
493         while (length != 0) {
494                 type = tvb_get_ntohs(tvb, offset);
495                 item_length = tvb_get_ntohs(tvb, offset+2);
496
497                 switch (type) {
498
499                 case WCCP2_SECURITY_INFO:
500                         ett = ett_security_info;
501                         dissector = dissect_wccp2_security_info;
502                         break;
503
504                 case WCCP2_SERVICE_INFO:
505                         ett = ett_service_info;
506                         dissector = dissect_wccp2_service_info;
507                         break;
508
509                 case WCCP2_ROUTER_ID_INFO:
510                         ett = ett_router_identity_info;
511                         dissector = dissect_wccp2_router_identity_info;
512                         break;
513
514                 case WCCP2_WC_ID_INFO:
515                         ett = ett_wc_identity_info;
516                         dissector = dissect_wccp2_wc_identity_info;
517                         break;
518
519                 case WCCP2_RTR_VIEW_INFO:
520                         ett = ett_router_view_info;
521                         dissector = dissect_wccp2_router_view_info;
522                         break;
523
524                 case WCCP2_WC_VIEW_INFO:
525                         ett = ett_wc_view_info;
526                         dissector = dissect_wccp2_wc_view_info;
527                         break;
528
529                 case WCCP2_REDIRECT_ASSIGNMENT:
530                         ett = ett_router_assignment_info;
531                         dissector = dissect_wccp2_assignment_info;
532                         break;
533
534                 case WCCP2_QUERY_INFO:
535                         ett = ett_query_info;
536                         dissector = dissect_wccp2_router_query_info;
537                         break;
538
539                 case WCCP2_CAPABILITIES_INFO:
540                         ett = ett_capabilities_info;
541                         dissector = dissect_wccp2_capability_info;
542                         break;
543
544                 case WCCP2_ALT_ASSIGNMENT:
545                         ett = ett_alt_assignment_info;
546                         dissector = dissect_wccp2_alt_assignment_info;
547                         break;
548
549                 case WCCP2_ASSIGN_MAP:
550                 case WCCP2_COMMAND_EXTENSION:
551                 default:
552                         ett = ett_unknown_info;
553                         dissector = NULL;
554                         break;
555                 }
556
557                 ti = proto_tree_add_text(wccp_tree, tvb, offset, item_length + 4, "Message Component (%s)",
558                     val_to_str(type, info_type_vals, "Unknown info type (%u)"));
559                 info_tree = proto_item_add_subtree(ti, ett);
560                 proto_tree_add_item(info_tree, hf_item_type, tvb, offset, 2, ENC_BIG_ENDIAN);
561                 proto_tree_add_item(info_tree, hf_item_length, tvb, offset+2, 2, ENC_BIG_ENDIAN);
562
563                 offset += 4;
564                 length -= 4;
565
566                 /*
567                  * XXX - pass in "length" and check for that as well.
568                  */
569                 if (dissector != NULL) {
570                         if (!(*dissector)(tvb, offset, item_length, pinfo, info_tree, ti))
571                                 return; /* ran out of data */
572                 } else {
573                         proto_tree_add_item(info_tree, hf_item_data, tvb, offset, item_length, ENC_NA);
574                 }
575                 offset += item_length;
576                 length -= item_length;
577         }
578 }
579
580 #define SECURITY_INFO_LEN               4
581
582 #define WCCP2_NO_SECURITY               0
583 #define WCCP2_MD5_SECURITY              1
584
585 const value_string security_option_vals[] = {
586         { WCCP2_NO_SECURITY, "None" },
587         { WCCP2_MD5_SECURITY, "MD5" },
588         { 0,    NULL }
589 };
590
591 static gboolean
592 dissect_wccp2_security_info(tvbuff_t *tvb, int offset, int length,
593     packet_info *pinfo, proto_tree *info_tree, proto_item *info_item)
594 {
595         guint32 security_option;
596
597         if (length < SECURITY_INFO_LEN) {
598                 expert_add_info_format(pinfo, info_item, PI_PROTOCOL, PI_WARN,
599                             "Item length is %u, should be >= %u", length, SECURITY_INFO_LEN);
600                 return TRUE;
601         }
602
603         security_option = tvb_get_ntohl(tvb, offset);
604         proto_tree_add_item(info_tree, hf_security_option, tvb, offset, 4, ENC_BIG_ENDIAN);
605         if (security_option == WCCP2_MD5_SECURITY) {
606                 proto_tree_add_item(info_tree, hf_security_md5_checksum, tvb, offset+4, length-4, ENC_NA);
607         }
608
609         return TRUE;
610 }
611
612 #define SERVICE_INFO_LEN                (4+4+8*2)
613
614 #define WCCP2_SERVICE_STANDARD          0
615 #define WCCP2_SERVICE_DYNAMIC           1
616
617 const value_string service_type_vals[] = {
618         { WCCP2_SERVICE_STANDARD, "Well-known service" },
619         { WCCP2_SERVICE_DYNAMIC, "Dynamic service" },
620         { 0,    NULL }
621 };
622
623 /*
624  * Service flags.
625  */
626 #define WCCP2_SI_SRC_IP_HASH            0x0001
627 #define WCCP2_SI_DST_IP_HASH            0x0002
628 #define WCCP2_SI_SRC_PORT_HASH          0x0004
629 #define WCCP2_SI_DST_PORT_HASH          0x0008
630 #define WCCP2_SI_PORTS_DEFINED          0x0010
631 #define WCCP2_SI_PORTS_SOURCE           0x0020
632 #define WCCP2_SI_SRC_IP_ALT_HASH        0x0100
633 #define WCCP2_SI_DST_IP_ALT_HASH        0x0200
634 #define WCCP2_SI_SRC_PORT_ALT_HASH      0x0400
635 #define WCCP2_SI_DST_PORT_ALT_HASH      0x0800
636
637 static gboolean
638 dissect_wccp2_service_info(tvbuff_t *tvb, int offset, int length,
639     packet_info *pinfo, proto_tree *info_tree, proto_item *info_item)
640 {
641         guint8 service_type;
642         guint8 priority;
643         guint8 protocol;
644         guint32 flags;
645         proto_item *tf;
646         proto_tree *field_tree;
647         int i;
648
649         if (length != SERVICE_INFO_LEN) {
650                 expert_add_info_format(pinfo, info_item, PI_PROTOCOL, PI_WARN,
651                                 "Item length is %u, should be %u", length, SERVICE_INFO_LEN);
652                 return TRUE;
653         }
654
655         service_type = tvb_get_guint8(tvb, offset);
656     proto_tree_add_item(info_tree, hf_service_type, tvb, offset, 1, ENC_BIG_ENDIAN);
657         switch (service_type) {
658
659         case WCCP2_SERVICE_STANDARD:
660                 proto_tree_add_item(info_tree, hf_service_id, tvb, offset+1, 1, ENC_BIG_ENDIAN);
661                 tf = proto_tree_add_item(info_tree, hf_service_priority, tvb, offset+2, 1, ENC_BIG_ENDIAN);
662                 priority = tvb_get_guint8(tvb, offset+2);
663                 if (priority != 0)
664                         expert_add_info_format(pinfo, tf, PI_PROTOCOL, PI_WARN,
665                                 "The priority must be zero for well-known services.");
666                 tf = proto_tree_add_item(info_tree, hf_service_protocol, tvb, offset+3, 1, ENC_BIG_ENDIAN);
667                 protocol = tvb_get_guint8(tvb, offset+3);
668                 if (protocol != 0)
669                         expert_add_info_format(pinfo, tf, PI_PROTOCOL, PI_WARN,
670                                 "The protocol must be zero for well-known services.");
671                 break;
672
673         case WCCP2_SERVICE_DYNAMIC:
674                 proto_tree_add_item(info_tree, hf_service_id, tvb, offset+1, 1, ENC_BIG_ENDIAN);
675                 proto_tree_add_item(info_tree, hf_service_priority, tvb, offset+2, 1, ENC_BIG_ENDIAN);
676                 /*
677                  * XXX - does "IP protocol identifier" mean this is a
678                  * protocol type of the sort you get in IP headers?
679                  * If so, we should get a table of those from the
680                  * IP dissector, and use that.
681                  */
682                 proto_tree_add_item(info_tree, hf_service_protocol, tvb, offset+3, 1, ENC_BIG_ENDIAN);
683                 break;
684         }
685         offset += 4;
686
687         flags = tvb_get_ntohl(tvb, offset);
688         tf = proto_tree_add_item(info_tree, hf_service_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
689         field_tree = proto_item_add_subtree(tf, ett_service_flags);
690
691         proto_tree_add_item(field_tree, hf_service_flags_src_ip_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
692         proto_tree_add_item(field_tree, hf_service_flags_dest_ip_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
693         proto_tree_add_item(field_tree, hf_service_flags_src_port_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
694         proto_tree_add_item(field_tree, hf_service_flags_dest_port_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
695         proto_tree_add_item(field_tree, hf_service_flags_ports_defined, tvb, offset, 4, ENC_BIG_ENDIAN);
696         if (flags & WCCP2_SI_PORTS_DEFINED)
697                 proto_tree_add_item(field_tree, hf_service_flags_ports_source, tvb, offset, 4, ENC_BIG_ENDIAN);
698         proto_tree_add_item(field_tree, hf_service_flags_src_ip_alt_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
699         proto_tree_add_item(field_tree, hf_service_flags_dest_ip_alt_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
700         proto_tree_add_item(field_tree, hf_service_flags_src_port_alt_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
701         proto_tree_add_item(field_tree, hf_service_flags_dest_port_alt_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
702         offset += 4;
703
704         if (flags & WCCP2_SI_PORTS_DEFINED) {
705                 for (i = 0; i < 8; i++) {
706                         proto_tree_add_item(info_tree, hf_service_port, tvb, offset, 2, ENC_BIG_ENDIAN);
707                         offset += 2;
708                 }
709         }
710
711         return TRUE;
712 }
713
714 #define ROUTER_ID_INFO_MIN_LEN          (8+4+4)
715
716 static void
717 dissect_wccp2_router_identity_element(tvbuff_t *tvb, int offset,
718     proto_tree *tree)
719 {
720         proto_tree_add_item(tree, hf_router_identity_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
721         proto_tree_add_item(tree, hf_router_identity_receive_id, tvb, offset+4, 4, ENC_BIG_ENDIAN);
722 }
723
724 static gboolean
725 dissect_wccp2_router_identity_info(tvbuff_t *tvb, int offset, int length,
726     packet_info *pinfo, proto_tree *info_tree, proto_item *info_item)
727 {
728         guint32 n_received_from;
729         guint i;
730         proto_item *te;
731         proto_tree *element_tree;
732
733         if (length < ROUTER_ID_INFO_MIN_LEN) {
734                 expert_add_info_format(pinfo, info_item, PI_PROTOCOL, PI_WARN,
735                                 "Item length is %u, should be >= %u", length, ROUTER_ID_INFO_MIN_LEN);
736                 return TRUE;
737         }
738
739         te = proto_tree_add_text(info_tree, tvb, offset, 8,
740             "Router Identity Element: IP address %s",
741             tvb_ip_to_str(tvb, offset));
742         element_tree = proto_item_add_subtree(te, ett_router_identity_element);
743         dissect_wccp2_router_identity_element(tvb, offset, element_tree);
744         offset += 8;
745
746         proto_tree_add_item(info_tree, hf_router_send_to_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
747         offset += 4;
748
749         n_received_from = tvb_get_ntohl(tvb, offset);
750         proto_tree_add_item(info_tree, hf_router_num_recv_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
751         offset += 4;
752         for (i = 0; i < n_received_from; i++) {
753                 proto_tree_add_ipv4_format_value(info_tree, hf_router_recv_ip, tvb, offset, 4,
754                         tvb_get_ipv4(tvb, offset), "Received From IP Address %d: %s", i,
755                         tvb_ip_to_str(tvb, offset));
756                 offset += 4;
757         }
758
759         return TRUE;
760 }
761
762 #define WC_ID_INFO_LEN                  (4+4+8*4+4)
763
764 static gboolean
765 dissect_wccp2_web_cache_identity_element(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int length)
766 {
767         proto_item *bucket_item;
768         proto_tree *bucket_tree;
769         proto_item *tf;
770         proto_tree *field_tree;
771     guint16 flags;
772         guint32 i, n, num_masks;
773         guint8 bucket_info;
774
775         proto_tree_add_item(tree, hf_web_cache_identity_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
776         offset += 4;
777         proto_tree_add_item(tree, hf_web_cache_identity_hash_rev, tvb, offset, 2, ENC_BIG_ENDIAN);
778         offset += 2;
779
780     flags = tvb_get_ntohs(tvb, offset);
781         tf = proto_tree_add_uint(tree, hf_web_cache_identity_flags, tvb, offset, 2, flags);
782         field_tree = proto_item_add_subtree(tf, ett_flags);
783         proto_tree_add_item(field_tree, hf_web_cache_identity_flag_hash_info, tvb, offset, 2, ENC_BIG_ENDIAN);
784         proto_tree_add_item(field_tree, hf_web_cache_identity_flag_assign_type, tvb, offset, 2, ENC_BIG_ENDIAN);
785         offset += 2;
786
787     if (flags & WCCP_T_FLAG) {
788             bucket_item = proto_tree_add_text(tree, tvb, offset, 8*4, "Mask Assignment information");
789             bucket_tree = proto_item_add_subtree(bucket_item, ett_buckets);
790
791         num_masks = tvb_get_ntohl(tvb, offset);
792             proto_tree_add_uint(bucket_tree, hf_web_cache_identity_num_mask, tvb, offset, 4, num_masks);
793         offset += 4;
794             for (i = 0; i < num_masks; i++) {
795                 proto_tree_add_item(bucket_tree, hf_web_cache_identity_assign_mask, tvb, offset, 4, ENC_BIG_ENDIAN);
796                     offset += 4;
797         }
798     }
799     else {
800             if (length != WC_ID_INFO_LEN) {
801                     expert_add_info_format(pinfo, tf, PI_PROTOCOL, PI_WARN,
802                                     "Item length is %u, should be %u", length, WC_ID_INFO_LEN);
803                     return TRUE;
804             }
805
806             bucket_item = proto_tree_add_text(tree, tvb, offset, 8*4, "Hash information");
807             bucket_tree = proto_item_add_subtree(bucket_item, ett_buckets);
808             for (i = 0, n = 0; i < 32; i++) {
809                     bucket_info = tvb_get_guint8(tvb, offset);
810                     n = wccp_bucket_info(bucket_info, bucket_tree, n, tvb, offset);
811                     offset += 1;
812         }
813     }
814
815         proto_tree_add_item(tree, hf_web_cache_identity_assign_weight, tvb, offset, 2, ENC_BIG_ENDIAN);
816         offset += 2;
817         proto_tree_add_item(tree, hf_web_cache_identity_status, tvb, offset, 2, ENC_BIG_ENDIAN);
818         return TRUE;
819 }
820
821 static gboolean
822 dissect_wccp2_wc_identity_info(tvbuff_t *tvb, int offset, int length,
823     packet_info *pinfo, proto_tree *info_tree, proto_item *info_item _U_)
824 {
825         proto_item *te;
826         proto_tree *element_tree;
827
828         te = proto_tree_add_text(info_tree, tvb, offset, length,
829             "Web-Cache Identity Element: IP address %s",
830             tvb_ip_to_str(tvb, offset));
831         element_tree = proto_item_add_subtree(te, ett_wc_identity_element);
832         if (!dissect_wccp2_web_cache_identity_element(tvb, offset, pinfo, element_tree, length))
833                 return FALSE;   /* ran out of data */
834
835         return TRUE;
836 }
837
838 #define ROUTER_VIEW_INFO_MIN_LEN        (4+8+4)
839
840 static void
841 dissect_wccp2_assignment_key(tvbuff_t *tvb, int offset,
842     proto_tree *info_tree)
843 {
844         proto_tree_add_item(info_tree, hf_assignment_key_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
845         proto_tree_add_item(info_tree, hf_assignment_key_change_num, tvb, offset+4, 4, ENC_BIG_ENDIAN);
846 }
847
848 static gboolean
849 dissect_wccp2_router_view_info(tvbuff_t *tvb, int offset, int length,
850     packet_info *pinfo, proto_tree *info_tree, proto_item *info_item)
851 {
852         guint32 n_routers;
853         guint32 n_web_caches;
854         guint i;
855         proto_item *te;
856         proto_tree *element_tree;
857
858         if (length < ROUTER_VIEW_INFO_MIN_LEN) {
859                 expert_add_info_format(pinfo, info_item, PI_PROTOCOL, PI_WARN,
860                                 "Item length is %u, should be >= %u", length, ROUTER_VIEW_INFO_MIN_LEN);
861                 return TRUE;
862         }
863
864         proto_tree_add_item(info_tree, hf_router_view_member_change_num, tvb, offset, 4, ENC_BIG_ENDIAN);
865         offset += 4;
866
867         dissect_wccp2_assignment_key(tvb, offset, info_tree);
868         offset += 8;
869
870         n_routers = tvb_get_ntohl(tvb, offset);
871         proto_tree_add_uint(info_tree, hf_router_router_num, tvb, offset, 4, n_routers);
872         offset += 4;
873
874         for (i = 0; i < n_routers; i++) {
875                 proto_tree_add_ipv4_format_value(info_tree, hf_router_router_ip, tvb, offset, 4,
876                         tvb_get_ipv4(tvb, offset), "Router %d IP Address: %s", i,
877                         tvb_ip_to_str(tvb, offset));
878                 offset += 4;
879         }
880
881         n_web_caches = tvb_get_ntohl(tvb, offset);
882         proto_tree_add_uint(info_tree, hf_num_web_caches, tvb, offset, 4, n_web_caches);
883         offset += 4;
884
885         for (i = 0; i < n_web_caches; i++) {
886                 te = proto_tree_add_text(info_tree, tvb, offset, WC_ID_INFO_LEN,
887                     "Web-Cache Identity Element %d: IP address %s", i,
888                     tvb_ip_to_str(tvb, offset));
889                 element_tree = proto_item_add_subtree(te, ett_wc_identity_element);
890                 if (!dissect_wccp2_web_cache_identity_element(tvb, offset, pinfo, element_tree, WC_ID_INFO_LEN))
891                         return FALSE;   /* ran out of data */
892                 offset += WC_ID_INFO_LEN;
893         }
894
895         return TRUE;
896 }
897
898 #define WC_VIEW_INFO_MIN_LEN            (4+4)
899
900 static gboolean
901 dissect_wccp2_wc_view_info(tvbuff_t *tvb, int offset, int length,
902     packet_info *pinfo, proto_tree *info_tree, proto_item *info_item)
903 {
904         guint32 n_routers;
905         guint32 n_web_caches;
906         guint i;
907         proto_item *te;
908         proto_tree *element_tree;
909
910         if (length < WC_VIEW_INFO_MIN_LEN) {
911                 expert_add_info_format(pinfo, info_item, PI_PROTOCOL, PI_WARN,
912                             "Item length is %u, should be >= %u", length, WC_VIEW_INFO_MIN_LEN);
913                 return TRUE;
914         }
915
916         proto_tree_add_item(info_tree, hf_wc_view_info_change_num, tvb, offset, 4, ENC_BIG_ENDIAN);
917         offset += 4;
918
919         n_routers = tvb_get_ntohl(tvb, offset);
920         proto_tree_add_uint(info_tree, hf_wc_view_router_num, tvb, offset, 4, n_routers);
921         offset += 4;
922
923         for (i = 0; i < n_routers; i++) {
924                 te = proto_tree_add_text(info_tree, tvb, offset, 8,
925                     "Router %d Identity Element: IP address %s", i,
926                     tvb_ip_to_str(tvb, offset));
927                 element_tree = proto_item_add_subtree(te, ett_router_identity_element);
928                 dissect_wccp2_router_identity_element(tvb, offset, element_tree);
929                 offset += 8;
930         }
931
932         n_web_caches = tvb_get_ntohl(tvb, offset);
933         proto_tree_add_uint(info_tree, hf_num_web_caches, tvb, offset, 4, n_web_caches);
934         offset += 4;
935
936         for (i = 0; i < n_web_caches; i++) {
937                 proto_tree_add_ipv4_format_value(info_tree, hf_wc_view_ip, tvb, offset, 4,
938                         tvb_get_ipv4(tvb, offset), "Web-Cache %d IP Address: %s", i,
939                         tvb_ip_to_str(tvb, offset));
940                 offset += 4;
941         }
942
943         return TRUE;
944 }
945
946 #define ASSIGNMENT_INFO_MIN_LEN         (8+4)
947
948 static void
949 dissect_wccp2_router_assignment_element(tvbuff_t *tvb, int offset,
950     proto_tree *tree)
951 {
952         proto_tree_add_item(tree, hf_router_assignment_element_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
953         proto_tree_add_item(tree, hf_router_assignment_element_receive_id, tvb, offset+4, 4, ENC_BIG_ENDIAN);
954         proto_tree_add_item(tree, hf_router_assignment_element_change_num, tvb, offset+8, 4, ENC_BIG_ENDIAN);
955 }
956
957 static gchar *
958 assignment_bucket_name(guint8 bucket)
959 {
960         gchar *cur;
961
962         if (bucket == 0xff) {
963                 cur="Unassigned";
964         } else {
965                 cur=ep_strdup_printf("%u%s", bucket >> 1,
966                     (bucket & 0x01) ? " (Alt)" : "");
967         }
968         return cur;
969 }
970
971 static gboolean
972 dissect_wccp2_assignment_info(tvbuff_t *tvb, int offset, int length,
973     packet_info *pinfo, proto_tree *info_tree, proto_item *info_item)
974 {
975         guint32 n_routers;
976         guint32 n_web_caches;
977         guint i;
978         proto_item *te;
979         proto_tree *element_tree;
980
981         if (length < ASSIGNMENT_INFO_MIN_LEN) {
982                 expert_add_info_format(pinfo, info_item, PI_PROTOCOL, PI_WARN,
983                             "Item length is %u, should be >= %u", length, ASSIGNMENT_INFO_MIN_LEN);
984                 return TRUE;
985         }
986
987         dissect_wccp2_assignment_key(tvb, offset, info_tree);
988         offset += 8;
989
990         n_routers = tvb_get_ntohl(tvb, offset);
991         proto_tree_add_uint(info_tree, hf_wccp2_assignment_info_router_num, tvb, offset, 4, n_routers);
992         offset += 4;
993
994         for (i = 0; i < n_routers; i++) {
995                 te = proto_tree_add_text(info_tree, tvb, offset, 4,
996                     "Router %d Assignment Element: IP address %s", i,
997                     tvb_ip_to_str(tvb, offset));
998                 element_tree = proto_item_add_subtree(te, ett_router_assignment_element);
999                 dissect_wccp2_router_assignment_element(tvb, offset, element_tree);
1000                 offset += 12;
1001         }
1002
1003         n_web_caches = tvb_get_ntohl(tvb, offset);
1004         proto_tree_add_uint(info_tree, hf_num_web_caches, tvb, offset, 4, n_web_caches);
1005         offset += 4;
1006
1007         for (i = 0; i < n_web_caches; i++) {
1008                 proto_tree_add_ipv4_format_value(info_tree, hf_wccp2_assignment_info_ip, tvb, offset, 4,
1009                         tvb_get_ipv4(tvb, offset), "Web-Cache %d IP Address: %s", i,
1010                     tvb_ip_to_str(tvb, offset));
1011                 offset += 4;
1012         }
1013
1014         for (i = 0; i < 256; i += 4) {
1015                 proto_tree_add_text(info_tree, tvb, offset, 4,
1016                     "Buckets %d - %d: %10s %10s %10s %10s",
1017                     i, i + 3,
1018                     assignment_bucket_name(tvb_get_guint8(tvb, offset)),
1019                     assignment_bucket_name(tvb_get_guint8(tvb, offset+1)),
1020                     assignment_bucket_name(tvb_get_guint8(tvb, offset+2)),
1021                     assignment_bucket_name(tvb_get_guint8(tvb, offset+3)));
1022                 offset += 4;
1023         }
1024
1025         return TRUE;
1026 }
1027
1028 #define QUERY_INFO_LEN                  (4+4+4+4)
1029
1030 static gboolean
1031 dissect_wccp2_router_query_info(tvbuff_t *tvb, int offset, int length,
1032     packet_info *pinfo, proto_tree *info_tree, proto_item *info_item)
1033 {
1034         if (length != QUERY_INFO_LEN) {
1035                 expert_add_info_format(pinfo, info_item, PI_PROTOCOL, PI_WARN,
1036                                 "Item length is %u, should be %u", length, QUERY_INFO_LEN);
1037                 return TRUE;
1038         }
1039
1040         proto_tree_add_item(info_tree, hf_router_query_info_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1041         proto_tree_add_item(info_tree, hf_router_query_info_receive_id, tvb, offset+4, 4, ENC_BIG_ENDIAN);
1042         proto_tree_add_item(info_tree, hf_router_query_info_send_to_ip, tvb, offset+8, 4, ENC_BIG_ENDIAN);
1043         proto_tree_add_item(info_tree, hf_router_query_info_target_ip, tvb, offset+12, 4, ENC_BIG_ENDIAN);
1044
1045         return TRUE;
1046 }
1047
1048 #define WCCP2_FORWARDING_METHOD         0x01
1049 #define WCCP2_ASSIGNMENT_METHOD         0x02
1050 #define WCCP2_PACKET_RETURN_METHOD      0x03
1051
1052 static const value_string capability_type_vals[] = {
1053         { WCCP2_FORWARDING_METHOD,    "Forwarding Method" },
1054         { WCCP2_ASSIGNMENT_METHOD,    "Assignment Method" },
1055         { WCCP2_PACKET_RETURN_METHOD, "Return Method" },
1056         { 0,                          NULL }
1057 };
1058
1059 #define WCCP2_FORWARDING_METHOD_GRE     0x00000001
1060 #define WCCP2_FORWARDING_METHOD_L2      0x00000002
1061
1062 static const capability_flag forwarding_method_flags[] = {
1063         { WCCP2_FORWARDING_METHOD_GRE, "IP-GRE", &hf_capability_forwarding_method_flag_gre },
1064         { WCCP2_FORWARDING_METHOD_L2, "L2", &hf_capability_forwarding_method_flag_l2 },
1065         { 0, NULL, NULL }
1066 };
1067
1068 #define WCCP2_ASSIGNMENT_METHOD_HASH    0x00000001
1069 #define WCCP2_ASSIGNMENT_METHOD_MASK    0x00000002
1070
1071 static const capability_flag assignment_method_flags[] = {
1072         { WCCP2_ASSIGNMENT_METHOD_HASH, "Hash", &hf_capability_assignment_method_flag_hash },
1073         { WCCP2_ASSIGNMENT_METHOD_MASK, "Mask", &hf_capability_assignment_method_flag_mask },
1074         { 0,                            NULL,   NULL }
1075 };
1076
1077 #define WCCP2_PACKET_RETURN_METHOD_GRE  0x00000001
1078 #define WCCP2_PACKET_RETURN_METHOD_L2   0x00000002
1079
1080 static const capability_flag packet_return_method_flags[] = {
1081         { WCCP2_PACKET_RETURN_METHOD_GRE, "IP-GRE", &hf_capability_return_method_flag_gre },
1082         { WCCP2_PACKET_RETURN_METHOD_L2, "L2", &hf_capability_return_method_flag_l2 },
1083         { 0, NULL, NULL }
1084 };
1085
1086 static gboolean
1087 dissect_wccp2_capability_info(tvbuff_t *tvb, int offset, int length,
1088     packet_info *pinfo, proto_tree *info_tree, proto_item *info_item _U_)
1089 {
1090         guint16 capability_type;
1091         guint16 capability_val_len;
1092         int curr_offset;
1093         proto_item *te;
1094         proto_tree *element_tree;
1095
1096         for (curr_offset = offset; curr_offset < (length + offset);
1097                 curr_offset += (capability_val_len + 4)) {
1098                 capability_type = tvb_get_ntohs(tvb, curr_offset);
1099                 capability_val_len = tvb_get_ntohs(tvb, curr_offset + 2);
1100
1101                 te = proto_tree_add_item(info_tree, hf_capability_info_type, tvb, curr_offset, 2, ENC_BIG_ENDIAN);
1102                 proto_item_set_len(te, capability_val_len + 4);
1103                 element_tree = proto_item_add_subtree(te, ett_capability_element);
1104                 if (capability_val_len < 4) {
1105                         expert_add_info_format(pinfo, te, PI_PROTOCOL, PI_WARN,
1106                                         "Value Length: %u (illegal, must be >= 4)", capability_val_len);
1107                         break;
1108                 }
1109
1110                 proto_tree_add_uint(element_tree, hf_capability_info_length, tvb, curr_offset+2, 2, capability_val_len);
1111                 switch (capability_type) {
1112
1113                 case WCCP2_FORWARDING_METHOD:
1114                         dissect_32_bit_capability_flags(tvb, curr_offset,
1115                             capability_val_len, pinfo,
1116                             ett_capability_forwarding_method,
1117                             forwarding_method_flags, element_tree, te);
1118                         break;
1119
1120                 case WCCP2_ASSIGNMENT_METHOD:
1121                         dissect_32_bit_capability_flags(tvb, curr_offset,
1122                             capability_val_len, pinfo,
1123                             ett_capability_assignment_method,
1124                             assignment_method_flags, element_tree, te);
1125                         break;
1126
1127                 case WCCP2_PACKET_RETURN_METHOD:
1128                         dissect_32_bit_capability_flags(tvb, curr_offset,
1129                             capability_val_len, pinfo,
1130                             ett_capability_return_method,
1131                             packet_return_method_flags, element_tree, te);
1132                         break;
1133
1134                 default:
1135                         proto_tree_add_item(element_tree, hf_capability_info_bytes, tvb, curr_offset+4, capability_val_len, ENC_NA);
1136                         break;
1137                 }
1138
1139         }
1140         return TRUE;
1141 }
1142
1143 static void
1144 dissect_32_bit_capability_flags(tvbuff_t *tvb, int curr_offset,
1145     guint16 capability_val_len, packet_info *pinfo, gint ett, const capability_flag *flags,
1146     proto_tree *element_tree, proto_item *element_item)
1147 {
1148         guint32 capability_val;
1149         proto_item *tm;
1150         proto_tree *method_tree;
1151         int i;
1152         gboolean first = TRUE;
1153
1154         if (capability_val_len != 4) {
1155                 expert_add_info_format(pinfo, element_item, PI_PROTOCOL, PI_WARN,
1156                                 "Value Length: %u (illegal, must be >= 4)", capability_val_len);
1157                 return;
1158         }
1159
1160         capability_val = tvb_get_ntohl(tvb, curr_offset + 4);
1161         tm = proto_tree_add_uint(element_tree, hf_capability_info_value, tvb, curr_offset + 4, 4, capability_val);
1162
1163         for (i = 0; flags[i].short_name != NULL; i++) {
1164                 if (capability_val & flags[i].value) {
1165                         if (first) {
1166                                 proto_item_append_text( tm, " (%s", flags[i].short_name);
1167                                 first = FALSE;
1168                         } else {
1169                                 proto_item_append_text( tm, ", %s", flags[i].short_name);
1170                         }
1171                 }
1172         }
1173
1174         if (first == FALSE)
1175                 proto_item_append_text( tm, ")");
1176
1177         method_tree = proto_item_add_subtree(tm, ett);
1178         for (i = 0; flags[i].phf != NULL; i++)
1179                 proto_tree_add_item(method_tree, *(flags[i].phf), tvb, curr_offset+4, 4, ENC_BIG_ENDIAN);
1180
1181 }
1182
1183 #define ALT_ASSIGNMENT_INFO_MIN_LEN    (4+4)
1184
1185 #define WCCP2_HASH_ASSIGNMENT_TYPE     0x0000
1186 #define WCCP2_MASK_ASSIGNMENT_TYPE     0x0001
1187
1188 static const value_string assignment_type_vals[] = {
1189         { WCCP2_HASH_ASSIGNMENT_TYPE, "Hash" },
1190         { WCCP2_MASK_ASSIGNMENT_TYPE, "Mask" },
1191         { 0,                          NULL }
1192 };
1193
1194 static void
1195 dissect_wccp2_value_element(tvbuff_t *tvb, int offset, int idx, proto_tree *info_tree)
1196 {
1197         proto_item *tl;
1198         proto_tree *element_tree;
1199
1200         tl = proto_tree_add_text(info_tree, tvb, offset, 16, "Value Element(%u)", idx);
1201         element_tree = proto_item_add_subtree(tl, ett_value_element);
1202
1203         proto_tree_add_item(element_tree, hf_wccp2_value_element_src_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1204         proto_tree_add_item(element_tree, hf_wccp2_value_element_dest_ip, tvb, offset+4, 4, ENC_BIG_ENDIAN);
1205         proto_tree_add_item(element_tree, hf_wccp2_value_element_src_port, tvb, offset+8, 2, ENC_BIG_ENDIAN);
1206         proto_tree_add_item(element_tree, hf_wccp2_value_element_dest_port, tvb, offset+10, 2, ENC_BIG_ENDIAN);
1207         proto_tree_add_item(element_tree, hf_wccp2_value_element_web_cache_ip, tvb, offset+12, 4, ENC_BIG_ENDIAN);
1208 }
1209
1210 static guint
1211 dissect_wccp2_mask_value_set_element(tvbuff_t *tvb, int offset, int idx, proto_tree *info_tree)
1212 {
1213         proto_item *tl;
1214         proto_tree *element_tree;
1215         guint num_of_val_elements;
1216         guint i;
1217
1218         tl = proto_tree_add_text(info_tree, tvb, offset, 0, "Mask/Value Set Element(%d)", idx);
1219         element_tree = proto_item_add_subtree(tl, ett_mv_set_element);
1220
1221         proto_tree_add_item(element_tree, hf_wccp2_mask_value_set_element_src_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1222         proto_tree_add_item(element_tree, hf_wccp2_mask_value_set_element_dest_ip, tvb, offset+4, 4, ENC_BIG_ENDIAN);
1223         proto_tree_add_item(element_tree, hf_wccp2_mask_value_set_element_src_port, tvb, offset+8, 2, ENC_BIG_ENDIAN);
1224         proto_tree_add_item(element_tree, hf_wccp2_mask_value_set_element_dest_port, tvb, offset+10, 2, ENC_BIG_ENDIAN);
1225         proto_tree_add_item(element_tree, hf_wccp2_mask_value_set_element_num, tvb, offset+12, 4, ENC_BIG_ENDIAN);
1226         num_of_val_elements = tvb_get_ntohl(tvb, offset+12);
1227         offset += 16;
1228
1229         for (i = 0; i < num_of_val_elements; i++)
1230         {
1231                 dissect_wccp2_value_element(tvb, offset, i, element_tree);
1232                 offset += 16;
1233         }
1234
1235         proto_item_set_len(tl, 16+i*16);
1236
1237         return 16+idx*16;
1238 }
1239
1240 static gboolean
1241 dissect_wccp2_alt_assignment_info(tvbuff_t *tvb, int offset, int length,
1242     packet_info *pinfo, proto_tree *info_tree, proto_item *info_item)
1243 {
1244         guint16 assignment_type;
1245         guint16 assignment_length;
1246
1247         if (length < ALT_ASSIGNMENT_INFO_MIN_LEN) {
1248                 expert_add_info_format(pinfo, info_item, PI_PROTOCOL, PI_WARN,
1249                                 "Item length is %u, should be >= %u", length, ALT_ASSIGNMENT_INFO_MIN_LEN);
1250                 return TRUE;
1251         }
1252
1253         assignment_type = tvb_get_ntohs(tvb, offset);
1254         proto_tree_add_item(info_tree, hf_alt_assignment_info_assignment_type, tvb, offset, 2, ENC_BIG_ENDIAN);
1255         offset += 2;
1256
1257         assignment_length = tvb_get_ntohs(tvb, offset);
1258         proto_tree_add_item(info_tree, hf_alt_assignment_info_assignment_length, tvb, offset, 2, ENC_BIG_ENDIAN);
1259         offset += 2;
1260
1261         switch (assignment_type) {
1262         case WCCP2_HASH_ASSIGNMENT_TYPE:
1263                 dissect_wccp2_assignment_info(tvb, offset, assignment_length, pinfo, info_tree, info_item);
1264                 break;
1265
1266         case WCCP2_MASK_ASSIGNMENT_TYPE:
1267         {
1268                 guint num_of_rtr;
1269                 guint num_of_elem;
1270                 guint i;
1271
1272                 dissect_wccp2_assignment_key(tvb, offset, info_tree);
1273                 offset += 8;
1274
1275                 num_of_rtr = tvb_get_ntohl(tvb, offset);
1276                 proto_tree_add_uint(info_tree, hf_alt_assignment_info_num_routers, tvb, offset, 4, num_of_rtr);
1277                 offset += 4;
1278                 for (i = 0; i < num_of_rtr; i++)
1279                 {
1280                         dissect_wccp2_router_assignment_element(tvb, offset, info_tree);
1281                         offset += 12;
1282                 }
1283
1284                 num_of_elem = tvb_get_ntohl(tvb, offset);
1285                 proto_tree_add_uint(info_tree, hf_alt_assignment_info_num_elements, tvb, offset, 4, num_of_elem);
1286                 offset += 4;
1287                 for (i = 0; i < num_of_elem; i++)
1288                 {
1289                         offset += dissect_wccp2_mask_value_set_element(tvb, offset, i, info_tree);
1290                 }
1291                 break;
1292         }
1293
1294         default:
1295                 break;
1296         }
1297
1298         return TRUE;
1299 }
1300
1301 void
1302 proto_register_wccp(void)
1303 {
1304         static hf_register_info hf[] = {
1305                 { &hf_wccp_message_type,
1306                         { "WCCP Message Type", "wccp.message", FT_UINT32, BASE_DEC, VALS(wccp_type_vals), 0x0,
1307                                 "The WCCP message that was sent", HFILL }
1308                 },
1309                 { &hf_wccp_version,
1310                         { "WCCP Version", "wccp.version", FT_UINT32, BASE_HEX, VALS(wccp_version_val), 0x0,
1311                                 "The WCCP version", HFILL }
1312                 },
1313                 { &hf_wccp2_version,
1314                         { "WCCP Version", "wccp.version", FT_UINT16, BASE_HEX, NULL, 0x0,
1315                                 "The WCCP version", HFILL }
1316                 },
1317                 { &hf_hash_revision,
1318                         { "Hash Revision", "wccp.hash_revision", FT_UINT32, BASE_DEC, 0x0, 0x0,
1319                                 "The cache hash revision", HFILL }
1320                 },
1321                 { &hf_change_num,
1322                         { "Change Number", "wccp.change_num", FT_UINT32, BASE_DEC, 0x0, 0x0,
1323                                 "The Web-Cache list entry change number", HFILL }
1324                 },
1325                 { &hf_hash_flag,
1326                         { "Flags", "wccp.hash_flag", FT_UINT32, BASE_HEX, 0x0, 0x0,
1327                                 NULL, HFILL }
1328                 },
1329                 { &hf_hash_flag_u,
1330                         { "Hash information", "wccp.hash_flag.u", FT_BOOLEAN, 32, TFS(&tfs_historical_current), WCCP_U_FLAG,
1331                                 NULL, HFILL }
1332                 },
1333                 { &hf_recvd_id,
1334                         { "Received ID", "wccp.recvd_id", FT_UINT32, BASE_DEC, 0x0, 0x0,
1335                                 "The number of I_SEE_YOU's that have been sent", HFILL }
1336                 },
1337                 { &hf_num_web_caches,
1338                         { "Number of Web Caches", "wccp.num_web_caches", FT_UINT32, BASE_DEC, 0x0, 0x0,
1339                                 NULL, HFILL }
1340                 },
1341                 { &hf_cache_ip,
1342                         { "Web Cache IP address", "wccp.cache_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1343                                 "The IP address of a Web cache", HFILL }
1344                 },
1345                 { &hf_item_header_length,
1346                         { "Length", "wccp.item_header_length", FT_UINT16, BASE_DEC, 0x0, 0x0,
1347                                 NULL, HFILL }
1348                 },
1349                 { &hf_item_length,
1350                         { "Length", "wccp.item_length", FT_UINT16, BASE_DEC, 0x0, 0x0,
1351                                 NULL, HFILL }
1352                 },
1353                 { &hf_item_type,
1354                         { "Type", "wccp.item_type", FT_UINT16, BASE_DEC, VALS(info_type_vals), 0x0,
1355                                 NULL, HFILL }
1356                 },
1357                 { &hf_item_data,
1358                         { "Data", "wccp.item_data", FT_BYTES, BASE_NONE, 0x0, 0x0,
1359                                 NULL, HFILL }
1360                 },
1361                 { &hf_security_option,
1362                         { "Security Option", "wccp.security_option", FT_UINT16, BASE_DEC, VALS(security_option_vals), 0x0,
1363                                 NULL, HFILL }
1364                 },
1365                 { &hf_security_md5_checksum,
1366                         { "MD5 checksum", "wccp.security_md5_checksum", FT_BYTES, BASE_NONE, 0x0, 0x0,
1367                                 NULL, HFILL }
1368                 },
1369                 { &hf_service_type,
1370                         { "Service Type", "wccp.service_type", FT_UINT8, BASE_DEC, VALS(service_type_vals), 0x0,
1371                                 NULL, HFILL }
1372                 },
1373                 { &hf_service_id,
1374                         { "Service ID", "wccp.service_id", FT_UINT8, BASE_DEC, VALS(service_id_vals), 0x0,
1375                                 NULL, HFILL }
1376                 },
1377                 { &hf_service_priority,
1378                         { "Priority", "wccp.service_priority", FT_UINT8, BASE_DEC, NULL, 0x0,
1379                                 NULL, HFILL }
1380                 },
1381                 { &hf_service_protocol,
1382                         { "Protocol", "wccp.service_protocol", FT_UINT8, BASE_DEC, NULL, 0x0,
1383                                 NULL, HFILL }
1384                 },
1385                 { &hf_service_flags,
1386                         { "Flags", "wccp.service_flags", FT_UINT32, BASE_HEX, 0x0, 0x0,
1387                                 NULL, HFILL }
1388                 },
1389                 { &hf_service_flags_src_ip_hash,
1390                         { "Source IP address in primary hash", "wccp.service_flag.src_ip_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_SRC_IP_HASH,
1391                                 NULL, HFILL }
1392                 },
1393                 { &hf_service_flags_dest_ip_hash,
1394                         { "Destination IP address in primary hash", "wccp.service_flag.dest_ip_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_DST_IP_HASH,
1395                                 NULL, HFILL }
1396                 },
1397                 { &hf_service_flags_src_port_hash,
1398                         { "Source port in primary hash", "wccp.service_flag.src_port_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_SRC_PORT_HASH,
1399                                 NULL, HFILL }
1400                 },
1401                 { &hf_service_flags_dest_port_hash,
1402                         { "Destination port in primary hash", "wccp.service_flag.dest_port_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_DST_PORT_HASH,
1403                                 NULL, HFILL }
1404                 },
1405                 { &hf_service_flags_ports_defined,
1406                         { "Ports", "wccp.service_flag.ports_defined", FT_BOOLEAN, 32, TFS(&tfs_defined_not_defined), WCCP2_SI_PORTS_DEFINED,
1407                                 NULL, HFILL }
1408                 },
1409                 { &hf_service_flags_ports_source,
1410                         { "Ports refer to", "wccp.service_flag.ports_source", FT_BOOLEAN, 32, TFS(&tfs_src_dest_port), WCCP2_SI_PORTS_SOURCE,
1411                                 NULL, HFILL }
1412                 },
1413                 { &hf_service_flags_src_ip_alt_hash,
1414                         { "Source IP address in secondary hash", "wccp.service_flag.src_ip_alt_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_SRC_IP_ALT_HASH,
1415                                 NULL, HFILL }
1416                 },
1417                 { &hf_service_flags_dest_ip_alt_hash,
1418                         { "Destination IP address in secondary hash", "wccp.service_flag.dest_ip_alt_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_DST_IP_ALT_HASH,
1419                                 NULL, HFILL }
1420                 },
1421                 { &hf_service_flags_src_port_alt_hash,
1422                         { "Source port in secondary hash", "wccp.service_flag.src_port_alt_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_SRC_PORT_ALT_HASH,
1423                                 NULL, HFILL }
1424                 },
1425                 { &hf_service_flags_dest_port_alt_hash,
1426                         { "Destination port in secondary hash", "wccp.service_flag.dest_port_alt_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_DST_PORT_ALT_HASH,
1427                                 NULL, HFILL }
1428                 },
1429                 { &hf_service_port,
1430                         { "Port", "wccp.service_port", FT_UINT16, BASE_DEC, NULL, 0x0,
1431                                 NULL, HFILL }
1432                 },
1433                 { &hf_router_identity_ip,
1434                         { "IP Address", "wccp.router_identity.ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1435                                 NULL, HFILL }
1436                 },
1437                 { &hf_router_identity_receive_id,
1438                         { "Received ID", "wccp.router_identity.receive_id", FT_UINT32, BASE_DEC, 0x0, 0x0,
1439                                 NULL, HFILL }
1440                 },
1441                 { &hf_router_send_to_ip,
1442                         { "Sent To IP Address", "wccp.router.send_to_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1443                                 NULL, HFILL }
1444                 },
1445                 { &hf_router_num_recv_ip,
1446                         { "Number of Received From IP addresses", "wccp.router.num_recv_ip", FT_UINT32, BASE_DEC, 0x0, 0x0,
1447                                 NULL, HFILL }
1448                 },
1449                 { &hf_router_recv_ip,
1450                         { "Received From IP Address", "wccp.router.recv_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1451                                 NULL, HFILL }
1452                 },
1453                 { &hf_web_cache_identity_ip,
1454                         { "Web-Cache IP Address", "wccp.web_cache_identity.ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1455                                 NULL, HFILL }
1456                 },
1457                 { &hf_web_cache_identity_hash_rev,
1458                         { "Hash Revision", "wccp.web_cache_identity.hash_rev", FT_UINT16, BASE_DEC, NULL, 0x0,
1459                                 NULL, HFILL }
1460                 },
1461                 { &hf_web_cache_identity_flags,
1462                         { "Flags", "wccp.web_cache_identity.flags", FT_UINT16, BASE_HEX, NULL, 0x0,
1463                                 NULL, HFILL }
1464                 },
1465                 { &hf_web_cache_identity_flag_hash_info,
1466                         { "Hash information", "wccp.web_cache_identity.flags.hash_info", FT_BOOLEAN, 16, TFS(&tfs_historical_current), 0x8000,
1467                                 NULL, HFILL }
1468                 },
1469                 { &hf_web_cache_identity_flag_assign_type,
1470                         { "Assignment Type", "wccp.web_cache_identity.flags.assign_type", FT_BOOLEAN, 16, TFS(&tfs_mask_hash), 0x4000,
1471                                 NULL, HFILL }
1472                 },
1473                 { &hf_web_cache_identity_num_mask,
1474                         { "Number of Masks", "wccp.web_cache_identity.num_mask", FT_UINT32, BASE_DEC, 0x0, 0x0,
1475                                 NULL, HFILL }
1476                 },
1477                 { &hf_web_cache_identity_assign_mask,
1478                         { "Mask Element", "wccp.web_cache_identity.assign_mask", FT_UINT32, BASE_HEX, 0x0, 0x0,
1479                                 NULL, HFILL }
1480                 },
1481                 { &hf_web_cache_identity_assign_weight,
1482                         { "Assignment Weight", "wccp.web_cache_identity.assignment_weight", FT_UINT16, BASE_DEC, NULL, 0x0,
1483                                 NULL, HFILL }
1484                 },
1485                 { &hf_web_cache_identity_status,
1486                         { "Status", "wccp.web_cache_identity.status", FT_UINT16, BASE_HEX, NULL, 0x0,
1487                                 NULL, HFILL }
1488                 },
1489                 { &hf_assignment_key_ip,
1490                         { "Assignment Key IP Address", "wccp.assignment_key.ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1491                                 NULL, HFILL }
1492                 },
1493                 { &hf_assignment_key_change_num,
1494                         { "Assignment Key Change Number", "wccp.assignment_key.change_num", FT_UINT32, BASE_DEC, NULL, 0x0,
1495                                 NULL, HFILL }
1496                 },
1497                 { &hf_router_view_member_change_num,
1498                         { "Member Change Number", "wccp.router_view.member_change_num", FT_UINT32, BASE_DEC, NULL, 0x0,
1499                                 NULL, HFILL }
1500                 },
1501                 { &hf_router_router_num,
1502                         { "Number of Routers", "wccp.router_view.router_num", FT_UINT32, BASE_DEC, NULL, 0x0,
1503                                 NULL, HFILL }
1504                 },
1505                 { &hf_router_router_ip,
1506                         { "Router IP Address", "wccp.router_view.router_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1507                                 NULL, HFILL }
1508                 },
1509                 { &hf_wc_view_info_change_num,
1510                         { "Change Number", "wccp.wc_view.change_num", FT_UINT32, BASE_DEC, NULL, 0x0,
1511                                 NULL, HFILL }
1512                 },
1513                 { &hf_wc_view_router_num,
1514                         { "Number of Routers", "wccp.wc_view.router_num", FT_UINT32, BASE_DEC, NULL, 0x0,
1515                                 NULL, HFILL }
1516                 },
1517                 { &hf_wc_view_ip,
1518                         { "Router IP Address", "wccp.wc_view.ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1519                                 NULL, HFILL }
1520                 },
1521                 { &hf_router_assignment_element_ip,
1522                         { "IP Address", "wccp.router_assignment_element.ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1523                                 NULL, HFILL }
1524                 },
1525                 { &hf_router_assignment_element_receive_id,
1526                         { "Receive ID", "wccp.router_assignment_element.receive_id", FT_UINT32, BASE_DEC, NULL, 0x0,
1527                                 NULL, HFILL }
1528                 },
1529                 { &hf_router_assignment_element_change_num,
1530                         { "Change Number", "wccp.router_assignment_element.change_num", FT_UINT32, BASE_DEC, NULL, 0x0,
1531                                 NULL, HFILL }
1532                 },
1533                 { &hf_wccp2_assignment_info_router_num,
1534                         { "Number of Routers", "wccp.assignment_info.router_num", FT_UINT32, BASE_DEC, NULL, 0x0,
1535                                 NULL, HFILL }
1536                 },
1537                 { &hf_wccp2_assignment_info_ip,
1538                         { "Router IP Address", "wccp.assignment_info.ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1539                                 NULL, HFILL }
1540                 },
1541                 { &hf_router_query_info_ip,
1542                         { "Router IP Address", "wccp.router_query_info.ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1543                                 NULL, HFILL }
1544                 },
1545                 { &hf_router_query_info_receive_id,
1546                         { "Receive ID", "wccp.router_query_info.receive_id", FT_UINT32, BASE_DEC, NULL, 0x0,
1547                                 NULL, HFILL }
1548                 },
1549                 { &hf_router_query_info_send_to_ip,
1550                         { "Sent To IP Address", "wccp.router_query_info.send_to_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1551                                 NULL, HFILL }
1552                 },
1553                 { &hf_router_query_info_target_ip,
1554                         { "Target IP Address", "wccp.router_query_info.target_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1555                                 NULL, HFILL }
1556                 },
1557                 { &hf_capability_info_type,
1558                         { "Type", "wccp.capability_info.type", FT_UINT16, BASE_DEC, VALS(capability_type_vals), 0x0,
1559                                 NULL, HFILL }
1560                 },
1561                 { &hf_capability_info_length,
1562                         { "Value Length", "wccp.capability_info.length", FT_UINT16, BASE_DEC, NULL, 0x0,
1563                                 NULL, HFILL }
1564                 },
1565                 { &hf_capability_info_bytes,
1566                         { "Value", "wccp.capability_info.bytes", FT_BYTES, BASE_NONE, 0x0, 0x0,
1567                                 NULL, HFILL }
1568                 },
1569                 { &hf_capability_info_value,
1570                         { "Value", "wccp.capability_info.value", FT_UINT32, BASE_HEX, NULL, 0x0,
1571                                 NULL, HFILL }
1572                 },
1573                 { &hf_capability_forwarding_method_flag_gre,
1574                         { "GRE-encapsulated", "wccp.capability_info.forwarding_method_flag.gre", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_FORWARDING_METHOD_GRE,
1575                                 NULL, HFILL }
1576                 },
1577                 { &hf_capability_forwarding_method_flag_l2,
1578                         { "L2 rewrite", "wccp.capability_info.forwarding_method_flag.l2", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_FORWARDING_METHOD_L2,
1579                                 NULL, HFILL }
1580                 },
1581                 { &hf_capability_assignment_method_flag_hash,
1582                         { "Hash", "wccp.capability_info.assignment_method_flag.hash", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_ASSIGNMENT_METHOD_HASH,
1583                                 NULL, HFILL }
1584                 },
1585                 { &hf_capability_assignment_method_flag_mask,
1586                         { "Mask", "wccp.capability_info.assignment_method_flag.mask", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_ASSIGNMENT_METHOD_MASK,
1587                                 NULL, HFILL }
1588                 },
1589                 { &hf_capability_return_method_flag_gre,
1590                         { "GRE-encapsulated", "wccp.capability_info.return_method_flag.gre", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_PACKET_RETURN_METHOD_GRE,
1591                                 NULL, HFILL }
1592                 },
1593                 { &hf_capability_return_method_flag_l2,
1594                         { "L2 rewrite", "wccp.capability_info.return_method_flag.l2", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_PACKET_RETURN_METHOD_L2,
1595                                 NULL, HFILL }
1596                 },
1597                 { &hf_wccp2_value_element_src_ip,
1598                         { "Source Address", "wccp.value_element.src_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1599                                 NULL, HFILL }
1600                 },
1601                 { &hf_wccp2_value_element_dest_ip,
1602                         { "Destination Address", "wccp.value_element.dest_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1603                                 NULL, HFILL }
1604                 },
1605                 { &hf_wccp2_value_element_src_port,
1606                         { "Source Port", "wccp.value_element.src_port", FT_UINT16, BASE_DEC, NULL, 0x0,
1607                                 NULL, HFILL }
1608                 },
1609                 { &hf_wccp2_value_element_dest_port,
1610                         { "Destination Port", "wccp.value_element.dest_port", FT_UINT16, BASE_DEC, NULL, 0x0,
1611                                 NULL, HFILL }
1612                 },
1613                 { &hf_wccp2_value_element_web_cache_ip,
1614                         { "Web Cache Address", "wccp.value_element.web_cache_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1615                                 NULL, HFILL }
1616                 },
1617                 { &hf_wccp2_mask_value_set_element_src_ip,
1618                         { "Source Address Mask", "wccp.mask_value_set_element.src_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1619                                 NULL, HFILL }
1620                 },
1621                 { &hf_wccp2_mask_value_set_element_dest_ip,
1622                         { "Destination Address Mask", "wccp.mask_value_set_element.dest_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1623                                 NULL, HFILL }
1624                 },
1625                 { &hf_wccp2_mask_value_set_element_src_port,
1626                         { "Source Port Mask", "wccp.mask_value_set_element.src_port", FT_UINT16, BASE_DEC, NULL, 0x0,
1627                                 NULL, HFILL }
1628                 },
1629                 { &hf_wccp2_mask_value_set_element_dest_port,
1630                         { "Destination Port Mask", "wccp.mask_value_set_element.dest_port", FT_UINT16, BASE_DEC, NULL, 0x0,
1631                                 NULL, HFILL }
1632                 },
1633                 { &hf_wccp2_mask_value_set_element_num,
1634                         { "Number of Value Elements", "wccp.mask_value_set_element.num", FT_UINT32, BASE_DEC, NULL, 0x0,
1635                                 NULL, HFILL }
1636                 },
1637                 { &hf_alt_assignment_info_assignment_type,
1638                         { "Assignment type", "wccp.alt_assignment_info.assignment_type", FT_UINT16, BASE_DEC, VALS(assignment_type_vals), 0x0,
1639                                 NULL, HFILL }
1640                 },
1641                 { &hf_alt_assignment_info_assignment_length,
1642                         { "Assignment length", "wccp.alt_assignment_info.assignment_length", FT_UINT16, BASE_DEC, NULL, 0x0,
1643                                 NULL, HFILL }
1644                 },
1645                 { &hf_alt_assignment_info_num_routers,
1646                         { "Number of routers", "wccp.alt_assignment_info.num_routers", FT_UINT32, BASE_DEC, NULL, 0x0,
1647                                 NULL, HFILL }
1648                 },
1649                 { &hf_alt_assignment_info_num_elements,
1650                         { "Number of elements", "wccp.alt_assignment_info.num_elements", FT_UINT32, BASE_DEC, NULL, 0x0,
1651                                 NULL, HFILL }
1652                 },
1653         };
1654
1655         static gint *ett[] = {
1656                 &ett_wccp,
1657                 &ett_cache_count,
1658                 &ett_buckets,
1659                 &ett_flags,
1660                 &ett_cache_info,
1661                 &ett_security_info,
1662                 &ett_service_info,
1663                 &ett_service_flags,
1664                 &ett_router_identity_element,
1665                 &ett_router_identity_info,
1666                 &ett_wc_identity_element,
1667                 &ett_wc_identity_info,
1668                 &ett_router_view_info,
1669                 &ett_wc_view_info,
1670                 &ett_query_info,
1671                 &ett_router_assignment_element,
1672                 &ett_router_assignment_info,
1673                 &ett_capabilities_info,
1674                 &ett_capability_element,
1675                 &ett_capability_forwarding_method,
1676                 &ett_capability_assignment_method,
1677                 &ett_capability_return_method,
1678                 &ett_mv_set_element,
1679                 &ett_value_element,
1680                 &ett_alt_assignment_info,
1681                 &ett_unknown_info,
1682         };
1683
1684         proto_wccp = proto_register_protocol("Web Cache Communication Protocol",
1685             "WCCP", "wccp");
1686         proto_register_field_array(proto_wccp, hf, array_length(hf));
1687         proto_register_subtree_array(ett, array_length(ett));
1688 }
1689
1690 void
1691 proto_reg_handoff_wccp(void)
1692 {
1693         dissector_handle_t wccp_handle;
1694
1695         wccp_handle = new_create_dissector_handle(dissect_wccp, proto_wccp);
1696         dissector_add_uint("udp.port", UDP_PORT_WCCP, wccp_handle);
1697 }