Remove all $Id$ from top of file
[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  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #include <glib.h>
27 #include <epan/packet.h>
28 #include <epan/to_str.h>
29 #include <epan/wmem/wmem.h>
30 #include <epan/ipproto.h>
31 #include <epan/expert.h>
32 #include <epan/ipv6-utils.h>
33 #include <epan/ipv4.h>
34 #include "packet-wccp.h"
35
36 void proto_register_wccp(void);
37 void proto_reg_handoff_wccp(void);
38
39 static int proto_wccp = -1;
40 static int hf_wccp_message_type = -1;   /* the message type */
41 static int hf_wccp_version = -1;        /* protocol version */
42 static int hf_message_header_version = -1;
43 static int hf_hash_revision = -1;       /* the version of the hash */
44 static int hf_change_num = -1;          /* change number */
45 static int hf_hash_flag = -1;
46 static int hf_hash_flag_u = -1;
47 static int hf_recvd_id = -1;
48 static int hf_wc_num = -1;
49 static int hf_wc_view_wc_num = -1;
50 static int hf_cache_ip = -1;
51 static int hf_message_header_length = -1;
52 static int hf_item_type = -1;
53 static int hf_item_length = -1;
54 static int hf_item_data = -1;
55 static int hf_security_info_option = -1;
56 static int hf_security_info_md5_checksum = -1;
57 static int hf_command_element_type = -1;
58 static int hf_command_element_length = -1;
59 static int hf_command_element_shutdown_ip = -1;
60 static int hf_service_info_type = -1;
61 static int hf_service_info_id_standard = -1;
62 static int hf_service_info_id_dynamic = -1;
63 static int hf_service_info_priority = -1;
64 static int hf_service_info_protocol = -1;
65 static int hf_service_info_flags = -1;
66 static int hf_service_info_flags_src_ip_hash = -1;
67 static int hf_service_info_flags_dest_ip_hash = -1;
68 static int hf_service_info_flags_src_port_hash = -1;
69 static int hf_service_info_flags_dest_port_hash = -1;
70 static int hf_service_info_flags_ports_defined = -1;
71 static int hf_service_info_flags_ports_source = -1;
72 static int hf_service_info_flags_redirect_only_protocol_0 = -1;
73 static int hf_service_info_flags_src_ip_alt_hash = -1;
74 static int hf_service_info_flags_dest_ip_alt_hash = -1;
75 static int hf_service_info_flags_src_port_alt_hash = -1;
76 static int hf_service_info_flags_dest_port_alt_hash = -1;
77 static int hf_service_info_source_port = -1;
78 static int hf_service_info_destination_port = -1;
79 static int hf_router_identity_ip = -1;
80 static int hf_router_identity_receive_id = -1;
81 static int hf_router_identity_send_to_ip = -1;
82 static int hf_router_identity_received_from_num = -1;
83 static int hf_web_cache_identity_ip = -1;
84 static int hf_web_cache_identity_hash_rev = -1;
85 static int hf_web_cache_identity_flags = -1;
86 static int hf_web_cache_identity_flag_hash_info = -1;
87 static int hf_web_cache_identity_flag_assign_type = -1;
88 static int hf_web_cache_identity_flag_version_request = -1;
89 static int hf_mask_value_set_element_value_element_num = -1;
90 static int hf_assignment_weight = -1;
91 static int hf_assignment_status = -1;
92 static int hf_assignment_key_ip = -1;
93 static int hf_assignment_key_change_num = -1;
94 static int hf_router_view_member_change_num = -1;
95 static int hf_router_router_num = -1;
96 static int hf_router_identity_router_ip = -1;
97 static int hf_wc_view_info_change_num = -1;
98 static int hf_wc_view_info_router_ip = -1;
99 static int hf_wc_view_info_wc_ip = -1;
100 static int hf_wc_view_router_num = -1;
101 static int hf_wc_identity_ip_address = -1;
102 static int hf_router_identity_received_from_ip = -1;
103 static int hf_router_assignment_element_change_num = -1;
104 static int hf_assignment_info_router_num = -1;
105 static int hf_hash_buckets_assignment_wc_num = -1;
106 static int hf_hash_buckets_assignment_wc_ip = -1;
107 static int hf_assignment_info_router_ip = -1;
108 static int hf_router_view_ip = -1;
109 static int hf_router_query_info_ip = -1;
110 static int hf_router_query_info_send_to_ip = -1;
111 static int hf_router_query_info_target_ip = -1;
112 static int hf_capability_element_type = -1;
113 static int hf_capability_element_length = -1;
114 static int hf_capability_info_value = -1;
115 static int hf_capability_forwarding_method_flag_gre = -1;
116 static int hf_capability_forwarding_method_flag_l2 = -1;
117 static int hf_capability_assignment_method_flag_hash = -1;
118 static int hf_capability_assignment_method_flag_mask = -1;
119 static int hf_capability_return_method_flag_gre = -1;
120 static int hf_capability_return_method_flag_l2 = -1;
121 static int hf_capability_transmit_t = -1;
122 static int hf_capability_transmit_t_upper_limit = -1;
123 static int hf_capability_transmit_t_lower_limit = -1;
124 static int hf_capability_timer_scale_timeout_scale = -1;
125 static int hf_capability_timer_scale_ra_timer_scale = -1;
126 static int hf_capability_timer_scale_timeout_scale_upper_limit = -1;
127 static int hf_capability_timer_scale_timeout_scale_lower_limit = -1;
128 static int hf_capability_timer_scale_ra_scale_upper_limit = -1;
129 static int hf_capability_timer_scale_ra_scale_lower_limit = -1;
130 static int hf_value_element_src_ip = -1;
131 static int hf_value_element_dest_ip = -1;
132 static int hf_value_element_src_port = -1;
133 static int hf_value_element_dest_port = -1;
134 static int hf_value_element_web_cache_ip = -1;
135 static int hf_mask_value_set_list_num_elements = -1;
136 static int hf_mask_element_src_ip = -1;
137 static int hf_mask_element_dest_ip = -1;
138 static int hf_mask_element_src_port = -1;
139 static int hf_mask_element_dest_port = -1;
140 static int hf_alt_assignment_info_assignment_type = -1;
141 static int hf_extended_assignment_data_type = -1;
142 static int hf_alt_assignment_info_assignment_length = -1;
143 static int hf_alt_assignment_map_assignment_type = -1;
144 static int hf_alt_assignment_map_assignment_length = -1;
145 static int hf_extended_assignment_data_length = -1;
146 static int hf_alt_assignment_info_num_routers = -1;
147 static int hf_alt_assignment_mask_value_set_element_num_wc_value_elements = -1;
148 static int hf_web_cache_value_element_wc_address = -1;
149 static int hf_web_cache_value_element_num_values = -1;
150 static int hf_alt_assignment_mask_value_set_list_num_elements = -1;
151 static int hf_address_table_family = -1;
152 static int hf_address_table_address_length = -1;
153 static int hf_address_table_length = -1;
154 static int hf_address_table_element = -1;
155
156 static gint ett_wccp = -1;
157 static gint ett_buckets = -1;
158 static gint ett_hash_assignment_buckets = -1;
159 static gint ett_mask_assignment_data_element = -1;
160 static gint ett_alternate_mask_assignment_data_element = -1;
161 static gint ett_extended_assigment_data_element = -1;
162 static gint ett_table_element = -1;
163 static gint ett_hash_flags = -1;
164 static gint ett_wc_identity_flags = -1;
165 static gint ett_cache_info = -1;
166 static gint ett_security_info = -1;
167 static gint ett_service_info = -1;
168 static gint ett_service_flags = -1;
169 static gint ett_service_info_ports = -1;
170 static gint ett_wc_view_info_router_element = -1;
171 static gint ett_router_identity_info = -1;
172 static gint ett_wc_identity_element = -1;
173 static gint ett_wc_identity_info = -1;
174 static gint ett_router_view_info = -1;
175 static gint ett_wc_view_info = -1;
176 static gint ett_router_assignment_element = -1;
177 static gint ett_hash_buckets_assignment_wc_element=-1;
178 static gint ett_hash_buckets_assignment_buckets=-1;
179 static gint ett_router_alt_assignment_element = -1;
180 static gint ett_router_assignment_info = -1;
181 static gint ett_query_info = -1;
182 static gint ett_capabilities_info = -1;
183 static gint ett_capability_element = -1;
184 static gint ett_capability_forwarding_method = -1;
185 static gint ett_capability_assignment_method = -1;
186 static gint ett_capability_return_method = -1;
187 static gint ett_capability_transmit_t = -1;
188 static gint ett_capability_timer_scale = -1;
189 static gint ett_alt_assignment_info = -1;
190 static gint ett_alt_assignment_map = -1;
191 static gint ett_address_table = -1;
192 static gint ett_assignment_map = -1;
193 static gint ett_command_extension = -1;
194 static gint ett_alternate_mask_value_set=-1;
195 static gint ett_alternate_mask_value_set_element=-1;
196 static gint ett_mv_set_list = -1;
197 static gint ett_mv_set_element = -1;
198 static gint ett_mv_set_value_list = -1;
199 static gint ett_alternate_mv_set_element_list = -1;
200 static gint ett_web_cache_value_element_list = -1;
201 static gint ett_alternate_mv_set_element = -1;
202 static gint ett_value_element = -1;
203 static gint ett_unknown_info = -1;
204
205 static expert_field ei_wccp_missing_security_info = EI_INIT;
206 static expert_field ei_wccp_missing_service_info = EI_INIT;
207 static expert_field ei_wccp_missing_wc_id_info = EI_INIT;
208 static expert_field ei_wccp_missing_router_id_info = EI_INIT;
209 static expert_field ei_wccp_missing_query_info = EI_INIT;
210 static expert_field ei_wccp_missing_wc_view_info = EI_INIT;
211 static expert_field ei_wccp_missing_rtr_view_info = EI_INIT;
212 static expert_field ei_wccp_contains_redirect_assignment = EI_INIT;
213 static expert_field ei_wccp_contains_router_id_info = EI_INIT;
214 static expert_field ei_wccp_contains_rtr_view_info = EI_INIT;
215 static expert_field ei_wccp_contains_query_info = EI_INIT;
216 static expert_field ei_wccp_contains_alt_assignment = EI_INIT;
217 static expert_field ei_wccp_contains_assign_map = EI_INIT;
218 static expert_field ei_wccp_contains_alt_assignment_map = EI_INIT;
219 static expert_field ei_wccp_contains_wc_id_info = EI_INIT;
220 static expert_field ei_wccp_contains_wc_view_info = EI_INIT;
221 static expert_field ei_wccp_contains_capabilities_info = EI_INIT;
222 static expert_field ei_wccp_contains_command_extension = EI_INIT;
223 static expert_field ei_wccp_missing_assignment = EI_INIT;
224 static expert_field ei_wccp_assignment_length_bad = EI_INIT;
225 static expert_field ei_wccp_length_bad = EI_INIT;
226 static expert_field ei_wccp_service_info_priority_nonzero = EI_INIT;
227 static expert_field ei_wccp_service_info_protocol_nonzero = EI_INIT;
228 static expert_field ei_wccp_router_identity_receive_id_zero = EI_INIT;
229 static expert_field ei_wccp_web_cache_identity_hash_rev_zero = EI_INIT;
230 static expert_field ei_wccp_address_table_family_unknown = EI_INIT;
231 static expert_field ei_wccp_capability_element_length = EI_INIT;
232
233 /*
234  * At
235  *
236  *      http://tools.ietf.org/html/draft-forster-wrec-wccp-v1-00
237  *
238  * is a copy of the now-expired Internet-Draft for WCCP 1.0.
239  *
240  * At
241  *
242  *      http://tools.ietf.org/id/draft-wilson-wrec-wccp-v2-01.txt
243  *
244  * is an Internet-Draft for WCCP 2.0.
245  *
246  * http://tools.ietf.org/html/draft-mclaggan-wccp-v2rev1
247  *
248  * is the current draft for WCCP 2.01
249  *
250  */
251
252 /* This is NOT IANA assigned */
253 #define UDP_PORT_WCCP           2048
254
255 #define WCCPv1                  4
256 #define WCCPv2                  0x0200
257 #define WCCPv2r1                0x0201
258 #define WCCP_HERE_I_AM          7
259 #define WCCP_I_SEE_YOU          8
260 #define WCCP_ASSIGN_BUCKET      9
261 #define WCCP2_HERE_I_AM         10
262 #define WCCP2_I_SEE_YOU         11
263 #define WCCP2_REDIRECT_ASSIGN   12
264 #define WCCP2_REMOVAL_QUERY     13
265
266 static const value_string wccp_type_vals[] = {
267   { WCCP_HERE_I_AM,        "1.0 Here I am" },
268   { WCCP_I_SEE_YOU,        "1.0 I see you" },
269   { WCCP_ASSIGN_BUCKET,    "1.0 Assign bucket" },
270   { WCCP2_HERE_I_AM,       "2.0 Here I am" },
271   { WCCP2_I_SEE_YOU,       "2.0 I see you" },
272   { WCCP2_REDIRECT_ASSIGN, "2.0 Redirect assign" },
273   { WCCP2_REMOVAL_QUERY,   "2.0 Removal query" },
274   { 0,                     NULL }
275 };
276
277 static const value_string wccp_version_val[] = {
278   { WCCPv1, "1"},
279   { WCCPv2, "2"},
280   { WCCPv2r1, "2.01"},
281   { 0, NULL}
282 };
283
284 const true_false_string tfs_defined_not_defined = { "Defined", "Not defined" };
285 const true_false_string tfs_src_dest_port = { "Source port", "Destination port" };
286 const true_false_string tfs_redirect_protocol0 = { "Redirect only protocol 0 (IP)", "Redirect all traffic" };
287 const true_false_string tfs_historical_current = { "Historical", "Current" };
288 const true_false_string tfs_version_min_max = {"WCCP version set is maximum supported by CE", "WCCP version set is minimum supported by CE"};
289
290 static const value_string wccp_address_family_val[] = {
291   { 0, "Reserved" },
292   { 1, "IPv4" },
293   { 2, "IPv6" },
294   { 0, NULL }
295 };
296
297
298 #define WCCP2_HASH_ASSIGNMENT_TYPE         0
299 #define WCCP2_MASK_ASSIGNMENT_TYPE         1
300 #define WCCP2r1_ALT_MASK_ASSIGNMENT_TYPE   2
301 #define WCCP2r1_ASSIGNMENT_WEIGHT_STATUS   3
302
303 static const value_string assignment_type_vals[] = {
304   { WCCP2_HASH_ASSIGNMENT_TYPE, "Hash" },
305   { WCCP2_MASK_ASSIGNMENT_TYPE, "Mask" },
306   { WCCP2r1_ALT_MASK_ASSIGNMENT_TYPE, "WCCP2r1 Alternate Mask"},
307   { WCCP2r1_ASSIGNMENT_WEIGHT_STATUS, "WCCP2r1 Assignment Weight Status"},
308   { 0,                          NULL }
309 };
310
311 #define HASH_INFO_SIZE          (4*(1+8+1))
312
313 #define WCCP2_SECURITY_INFO             0
314 #define WCCP2_SERVICE_INFO              1
315 #define WCCP2_ROUTER_ID_INFO            2
316 #define WCCP2_WC_ID_INFO                3
317 #define WCCP2_RTR_VIEW_INFO             4
318 #define WCCP2_WC_VIEW_INFO              5
319 #define WCCP2_REDIRECT_ASSIGNMENT       6
320 #define WCCP2_QUERY_INFO                7
321 #define WCCP2_CAPABILITIES_INFO         8
322 #define WCCP2_ALT_ASSIGNMENT            13
323 #define WCCP2_ASSIGN_MAP                14
324 #define WCCP2_COMMAND_EXTENSION         15
325 /* WCCP 2 r1 additions: */
326 #define WCCP2r1_ALT_ASSIGNMENT_MAP      16
327 #define WCCP2r1_ADDRESS_TABLE           17
328
329   static const value_string info_type_vals[] = {
330     { WCCP2_SECURITY_INFO,       "Security Info" },
331     { WCCP2_SERVICE_INFO,        "Service Info" },
332     { WCCP2_ROUTER_ID_INFO,      "Router Identity Info" },
333     { WCCP2_WC_ID_INFO,          "Web-Cache Identity Info" },
334     { WCCP2_RTR_VIEW_INFO,       "Router View Info" },
335     { WCCP2_WC_VIEW_INFO,        "Web-Cache View Info" },
336     { WCCP2_REDIRECT_ASSIGNMENT, "Assignment Info" },
337     { WCCP2_QUERY_INFO,          "Router Query Info" },
338     { WCCP2_CAPABILITIES_INFO,   "Capabilities Info" },
339     { WCCP2_ALT_ASSIGNMENT,      "Alternate Assignment" },
340     { WCCP2_ASSIGN_MAP,          "Assignment Map" },
341     { WCCP2_COMMAND_EXTENSION,   "Command Extension" },
342     { WCCP2r1_ALT_ASSIGNMENT_MAP, "Alternative Assignment Map" },
343     { WCCP2r1_ADDRESS_TABLE,      "Address Table" },
344     { 0,                         NULL }
345   };
346
347 const value_string service_id_vals[] = {
348   { 0x00, "HTTP" },
349   { 0,    NULL }
350 };
351
352 typedef struct capability_flag {
353   guint32 value;
354   const char *short_name;
355   int* phf;
356 } capability_flag;
357
358
359
360
361 #define WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_HASH        0
362 #define WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_MASK        1
363 #define WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_NOT_PRESENT 2
364 #define WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_EXTENDED    3
365
366 static const value_string wccp_web_cache_assignment_data_type_val[] = {
367   { WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_HASH        , "Hash Assignment Data Element"},
368   { WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_MASK        , "Mask Assignment Data Element"},
369   { WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_NOT_PRESENT , "Assignment Data Element Not Present"},
370   { WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_EXTENDED    , "Extended Assignment Data Element"},
371   { 0,                          NULL }
372 };
373
374 #define WCCP2_FORWARDING_METHOD         0x01
375 #define WCCP2_ASSIGNMENT_METHOD         0x02
376 #define WCCP2_PACKET_RETURN_METHOD      0x03
377 #define WCCP2_TRANSMIT_T                0x04
378 #define WCCP2_TIMER_SCALE               0x05
379
380 static const value_string capability_type_vals[] = {
381   { WCCP2_FORWARDING_METHOD,    "Forwarding Method" },
382   { WCCP2_ASSIGNMENT_METHOD,    "Assignment Method" },
383   { WCCP2_PACKET_RETURN_METHOD, "Packet Return Method" },
384   { WCCP2_TRANSMIT_T,           "Transmit_t Message interval values"},
385   { WCCP2_TIMER_SCALE,          "Timer_scale Timeout scale values"},
386   { 0, NULL }
387 };
388
389
390 /* with version 2.01 we now have a address table which is possibly present */
391
392 typedef struct wccp_address_table {
393   gboolean in_use;
394   gint16 family;
395   gint16 version;
396   guint16 table_length;
397   guint32 *table_ipv4;
398   struct e_in6_addr *table_ipv6;
399 } wccp_address_table;
400
401
402 wccp_address_table wccp_wccp_address_table;
403
404 static guint dissect_hash_data(tvbuff_t *tvb, int offset,
405                                proto_tree *wccp_tree);
406 static guint dissect_web_cache_list_entry(tvbuff_t *tvb, int offset,
407                                           int idx, proto_tree *wccp_tree);
408 static int wccp_bucket_info(guint8 bucket_info, proto_tree *bucket_tree,
409                             guint32 start, tvbuff_t *tvb, int offset);
410 static const gchar *bucket_name(guint8 bucket);
411 static guint16 dissect_wccp2_header(tvbuff_t *tvb, int offset,
412                                     proto_tree *wccp_tree);
413 static void dissect_wccp2_info(tvbuff_t *tvb, int offset, guint16 length,
414                                packet_info *pinfo, proto_tree *wccp_tree, guint32 wccp_message_type);
415
416 /* WCCP 2r1 IPv6 utlility functions */
417 static void find_wccp_address_table(tvbuff_t *tvb, int offset, guint16 length,
418                                     packet_info *pinfo _U_, proto_tree *wccp_tree _U_);
419 /* The V2 dissectors will return the remaining length of the packet
420    and a negative number if there are missing bytes to finish the
421    dissection */
422 static gint dissect_wccp2_security_info(tvbuff_t *tvb, int offset, gint lengreth,
423                                         packet_info *pinfo _U_, proto_tree *info_tree);
424 static gint dissect_wccp2_service_info(tvbuff_t *tvb, int offset, gint length,
425                                        packet_info *pinfo, proto_tree *info_tree);
426 static gint  dissect_wccp2r1_address_table_info(tvbuff_t *tvb, int offset,
427                                                 int length, packet_info *pinfo, proto_tree *info_tree);
428 static gint dissect_wccp2_router_identity_info(tvbuff_t *tvb, int offset, gint length,
429                                                packet_info *pinfo _U_, proto_tree *info_tree);
430 static gint dissect_wccp2_wc_identity_info(tvbuff_t *tvb, int offset, gint length,
431                                            packet_info *pinfo _U_, proto_tree *info_tree);
432 static gint dissect_wccp2_router_view_info(tvbuff_t *tvb, int offset, gint length,
433                                            packet_info *pinfo _U_, proto_tree *info_tree);
434 static gint dissect_wccp2_web_cache_view_info(tvbuff_t *tvb, int offset, gint length,
435                                               packet_info *pinfo _U_, proto_tree *info_tree);
436 static gint dissect_wccp2_assignment_info(tvbuff_t *tvb, int offset, gint length,
437                                           packet_info *pinfo _U_, proto_tree *info_tree);
438 static gint dissect_wccp2_hash_buckets_assignment_element(tvbuff_t *tvb, int offset, gint length,
439                                                           packet_info *pinfo, proto_tree *info_tree);
440 static gboolean dissect_wccp2_router_query_info(tvbuff_t *tvb, int offset, gint length,
441                                                 packet_info *pinfo _U_, proto_tree *info_tree);
442 static gint dissect_wccp2_capability_info(tvbuff_t *tvb, int offset, gint length,
443                                           packet_info *pinfo _U_, proto_tree *info_tree);
444 static gint dissect_wccp2_alternate_assignment_info(tvbuff_t *tvb, int offset, gint length,
445                                                     packet_info *pinfo, proto_tree *info_tree);
446 static gint dissect_wccp2_hash_assignment_info(tvbuff_t *tvb, int offset, gint length,
447                                                packet_info *pinfo _U_, proto_tree *info_tree);
448 static gint dissect_wccp2_assignment_map(tvbuff_t *tvb, int offset,
449                                          int length, packet_info *pinfo _U_, proto_tree *info_tree);
450 static gint  dissect_wccp2r1_alt_assignment_map_info(tvbuff_t *tvb, int offset,
451                                                      int length, packet_info *pinfo, proto_tree *info_tree);
452 static gint  dissect_wccp2_command_extension(tvbuff_t *tvb, int offset,
453                                              int length, packet_info *pinfo _U_, proto_tree *info_tree);
454 static void dissect_wccp2_router_identity_element(tvbuff_t *tvb, int offset, packet_info *pinfo,
455                                                   proto_tree *tree);
456 static gint dissect_wccp2_web_cache_identity_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
457                                                      proto_tree *info_tree);
458 static gint dissect_wccp2_hash_assignment_data_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
459                                                        proto_tree *info_tree);
460 static gint dissect_wccp2_mask_assignment_data_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
461                                                        proto_tree *info_tree) ;
462 static gint dissect_wccp2_alternate_mask_assignment_data_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
463                                                                  proto_tree *info_tree);
464 static gint dissect_wccp2_assignment_weight_and_status_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
465                                                                proto_tree *info_tree);
466 static gint dissect_wccp2_extended_assignment_data_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
467                                                            proto_tree *info_tree);
468 static gint dissect_wccp2_assignment_key_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
469                                                  proto_tree *info_tree);
470 static void dissect_wccp2_router_assignment_element(tvbuff_t *tvb, int offset, gint length,
471                                                     packet_info *pinfo, proto_tree *info_tree) ;
472 static gint dissect_wccp2_capability_element(tvbuff_t *tvb, int offset, gint length,
473                                              packet_info *pinfo _U_, proto_tree *info_tree);
474 static gint  dissect_wccp2_mask_value_set_list(tvbuff_t *tvb, int offset,
475                                                int length, packet_info *pinfo, proto_tree *info_tree);
476
477 /* Utility functions */
478 static gint dissect_wccp2_mask_value_set_element(tvbuff_t *tvb, int offset,
479                                                  gint length, int idx, packet_info *pinfo, proto_tree *info_tree);
480 static gint dissect_wccp2_mask_element(tvbuff_t *tvb, int offset,
481                                        gint length, packet_info *pinfo, proto_tree *info_tree);
482 static gint dissect_wccp2_value_element(tvbuff_t *tvb, int offset,
483                                         gint length, int idx, packet_info *pinfo, proto_tree *info_tree);
484 static gint dissect_wccp2_alternate_mask_value_set_list(tvbuff_t *tvb, int offset,
485                                                         gint length, packet_info *pinfo _U_, proto_tree *info_tree);
486 static gint dissect_wccp2_alternate_mask_value_set_element(tvbuff_t *tvb, int offset, gint length, guint el_index, packet_info *pinfo, proto_tree *info_tree);
487 static gint dissect_wccp2_web_cache_value_element(tvbuff_t *tvb, int offset,
488                                                   gint length,  packet_info *pinfo, proto_tree *info_tree);
489 static const gchar *assignment_bucket_name(guint8 bucket);
490 static void dissect_32_bit_capability_flags(tvbuff_t *tvb, int curr_offset,
491                                             guint16 capability_val_len, gint ett, const capability_flag *flags,
492                                             proto_tree *element_tree, proto_item *header);
493 static void dissect_transmit_t_capability(tvbuff_t *tvb, proto_item *te, int curr_offset,
494                                           guint16 capability_val_len, gint ett, proto_tree *element_tree);
495 static void dissect_timer_scale_capability(tvbuff_t *tvb, int curr_offset,
496                                            guint16 capability_val_len, gint ett, proto_tree *element_tree);
497
498
499
500
501 /*
502  * In WCCP 2.01 addresses are encoded to support IPv6 with 32 bit fields
503  *
504  * handle the decoding
505  */
506
507 static void
508 find_wccp_address_table(tvbuff_t *tvb, int offset, guint16 length,
509                         packet_info *pinfo _U_, proto_tree *wccp_tree _U_)
510 {
511   guint16 type;
512   guint16 item_length;
513
514   /* first clean up: */
515   wccp_wccp_address_table.in_use = FALSE;
516   wccp_wccp_address_table.family = -1;
517   wccp_wccp_address_table.version = -1;
518   wccp_wccp_address_table.table_length = 0;
519   wccp_wccp_address_table.table_ipv4 = (guint32 *) NULL;
520   wccp_wccp_address_table.table_ipv6 = (struct e_in6_addr *)NULL;
521
522   while (length >= 4) {
523     type = tvb_get_ntohs(tvb, offset);
524     item_length = tvb_get_ntohs(tvb, offset+2);
525
526     if (item_length > tvb_length_remaining(tvb, offset))
527       return;
528
529     if (type == WCCP2r1_ADDRESS_TABLE)
530       {
531         dissect_wccp2r1_address_table_info(tvb, offset+4, item_length, NULL, NULL);
532         /* no need to decode the rest */
533         return;
534       }
535
536     /* check if we _can_ advance */
537     if (length < (item_length+4))
538       return;
539
540     offset = offset + item_length + 4;
541     length = length - item_length - 4;
542   }
543 }
544
545
546 /* This function prints the IP or the encoded IP if the table exists */
547
548 /* at most an IPv6 IP: see
549    http://stackoverflow.com/questions/166132/maximum-length-of-the-textual-representation-of-an-ipv6-address
550
551    39 = 8 groups of 4 digits with 7 : characters
552
553    or
554
555    45 = IPv4 tunnel features: 0000:0000:0000:0000:0000:0000:192.168.0.1
556 */
557
558 /* problem here is that the IP is in network byte order for IPv4
559    we need to fix that
560 */
561
562 static void wccp_fmt_ipadddress(gchar *buffer, guint32 host_addr)
563 {
564   /* are we using an address table? */
565   if (! wccp_wccp_address_table.in_use)
566     {
567       /* no return the IPv4 IP */
568       /* first fix the byte order */
569       guint addr= GUINT32_SWAP_LE_BE(host_addr);
570
571       ip_to_str_buf( (guint8 *) &addr, buffer, ITEM_LABEL_LENGTH);
572       return;
573     }
574   else
575     {
576       /* we need to decode the encoded address: */
577       guint16 reserv = (host_addr & 0xFF00) >> 16;
578       guint16 addr_index  = (host_addr & 0x00FF);
579
580       if (reserv != 0) {
581         g_snprintf(buffer, ITEM_LABEL_LENGTH, "INVALID: reserved part non zero");
582         return;
583       }
584
585       /* now check if it's IPv4 or IPv6 we need to print */
586       switch (wccp_wccp_address_table.family) {
587       case 1:
588         /* IPv4 */
589
590         /* special case: index 0 -> undefined IP */
591         if (addr_index == 0) {
592           g_snprintf(buffer, ITEM_LABEL_LENGTH, "0.0.0.0");
593           return;
594         }
595         /* are we be beyond the end of the table? */
596         if (addr_index > wccp_wccp_address_table.table_length) {
597           g_snprintf(buffer, ITEM_LABEL_LENGTH, "INVALID IPv4 index: %d > %d",
598                      addr_index, wccp_wccp_address_table.table_length);
599           return;
600         }
601
602         /* ok get the IP */
603         if (wccp_wccp_address_table.table_ipv4 != NULL) {
604           ip_to_str_buf( (guint8 *) &(wccp_wccp_address_table.table_ipv4[addr_index-1]), buffer, ITEM_LABEL_LENGTH);
605           return;
606         }
607         else {
608           g_snprintf(buffer, ITEM_LABEL_LENGTH, "INVALID IPv4 table empty!");
609           return;
610         }
611         break;
612       case 2:
613         /* IPv6 */
614         /* special case: index 0 -> undefined IP */
615         if (addr_index == 0) {
616           g_snprintf(buffer, ITEM_LABEL_LENGTH, "::");
617           return;
618         }
619
620         /* are we be beyond the end of the table? */
621         if (addr_index > wccp_wccp_address_table.table_length) {
622           g_snprintf(buffer, ITEM_LABEL_LENGTH, "INVALID IPv6 index: %d > %d",
623                      addr_index, wccp_wccp_address_table.table_length);
624           return;
625         }
626
627         /* ok get the IP */
628         if (wccp_wccp_address_table.table_ipv6 != NULL) {
629           ip6_to_str_buf(&(wccp_wccp_address_table.table_ipv6[addr_index-1]), buffer);
630           return;
631         }
632         else {
633           g_snprintf(buffer, ITEM_LABEL_LENGTH, "INVALID IPv6 table empty!");
634           return;
635         }
636         break;
637       default:
638         g_snprintf(buffer, ITEM_LABEL_LENGTH, "INVALID IP family");
639         return;
640       }
641     }
642 }
643
644
645 #define WCCP_IP_MAX_LENGTH (MAX_IP_STR_LEN > 46 ? MAX_IP_STR_LEN : 46)
646
647
648 static const gchar * decode_wccp_encoded_address(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *info_tree _U_)
649 {
650   gchar *buffer;
651   guint32 host_addr;
652
653   buffer= (char *) wmem_alloc(wmem_packet_scope(), WCCP_IP_MAX_LENGTH+1);
654   host_addr = tvb_get_ntohl(tvb,offset);
655
656   wccp_fmt_ipadddress(buffer, host_addr);
657   return buffer;
658 }
659
660 static int
661 dissect_wccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
662 {
663   int offset = 0;
664   proto_tree *wccp_tree = NULL;
665   proto_item *wccp_tree_item;
666   guint32 wccp_message_type;
667   guint16 length;
668   guint32 cache_count;
669   guint32 ipaddr;
670   guint i;
671
672   wccp_message_type = tvb_get_ntohl(tvb, offset);
673
674   /* Check if this is really a WCCP message */
675   if (try_val_to_str(wccp_message_type, wccp_type_vals) == NULL)
676     return 0;
677
678   col_set_str(pinfo->cinfo, COL_PROTOCOL, "WCCP");
679
680   col_add_str(pinfo->cinfo, COL_INFO, val_to_str(wccp_message_type,
681                                                    wccp_type_vals, "Unknown WCCP message (%u)"));
682
683   wccp_tree_item = proto_tree_add_item(tree, proto_wccp, tvb, offset, -1, ENC_NA);
684   wccp_tree = proto_item_add_subtree(wccp_tree_item, ett_wccp);
685
686   proto_tree_add_uint(wccp_tree, hf_wccp_message_type, tvb, offset, 4, wccp_message_type);
687   offset += 4;
688
689   switch (wccp_message_type) {
690
691     case WCCP_HERE_I_AM:
692       proto_tree_add_item(wccp_tree, hf_wccp_version, tvb,
693                           offset, 4, ENC_BIG_ENDIAN);
694       offset += 4;
695       offset = dissect_hash_data(tvb, offset, wccp_tree);
696       proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
697                           4, ENC_BIG_ENDIAN);
698       /*offset += 4;*/
699       break;
700
701     case WCCP_I_SEE_YOU:
702       proto_tree_add_item(wccp_tree, hf_wccp_version, tvb,
703                           offset, 4, ENC_BIG_ENDIAN);
704       offset += 4;
705       proto_tree_add_item(wccp_tree, hf_change_num, tvb, offset,
706                           4, ENC_BIG_ENDIAN);
707       offset += 4;
708       proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
709                           4, ENC_BIG_ENDIAN);
710       offset += 4;
711       cache_count = tvb_get_ntohl(tvb, offset);
712       proto_tree_add_uint(wccp_tree, hf_wc_num, tvb, offset, 4, cache_count);
713       offset += 4;
714       for (i = 0; i < cache_count; i++) {
715         offset = dissect_web_cache_list_entry(tvb, offset, i,
716                                               wccp_tree);
717       }
718       break;
719
720     case WCCP_ASSIGN_BUCKET:
721       /*
722        * This hasn't been tested, since I don't have any
723        * traces with this in it.
724        *
725        * The V1 spec claims that this does, indeed,
726        * have a Received ID field after the type,
727        * rather than a Version field.
728        */
729       proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
730                           4, ENC_BIG_ENDIAN);
731       offset += 4;
732       cache_count = tvb_get_ntohl(tvb, offset);
733       proto_tree_add_uint(wccp_tree, hf_wc_num, tvb, offset, 4, cache_count);
734       offset += 4;
735       for (i = 0; i < cache_count; i++) {
736         ipaddr = tvb_get_ipv4(tvb, offset);
737         proto_tree_add_ipv4_format(wccp_tree,
738                                    hf_cache_ip, tvb, offset, 4,
739                                    ipaddr,
740                                    "Web Cache %d IP Address: %s", i,
741                                    ip_to_str((guint8 *)&ipaddr));
742         offset += 4;
743       }
744       for (i = 0; i < 256; i += 4) {
745         proto_tree_add_text(wccp_tree, tvb, offset, 4,
746                             "Buckets %d - %d: %10s %10s %10s %10s",
747                             i, i + 3,
748                             bucket_name(tvb_get_guint8(tvb, offset)),
749                             bucket_name(tvb_get_guint8(tvb, offset+1)),
750                             bucket_name(tvb_get_guint8(tvb, offset+2)),
751                             bucket_name(tvb_get_guint8(tvb, offset+3)));
752         offset += 4;
753       }
754       break;
755
756     case WCCP2_HERE_I_AM:
757     case WCCP2_I_SEE_YOU:
758     case WCCP2_REMOVAL_QUERY:
759     case WCCP2_REDIRECT_ASSIGN:
760     default:    /* assume unknown packets are v2 */
761       length = dissect_wccp2_header(tvb, offset, wccp_tree);
762       offset += 4;
763       dissect_wccp2_info(tvb, offset, length, pinfo, wccp_tree, wccp_message_type);
764       break;
765   }
766
767   return tvb_length(tvb);
768 }
769
770 static guint
771 dissect_hash_data(tvbuff_t *tvb, int offset, proto_tree *wccp_tree)
772 {
773   proto_item *bucket_item;
774   proto_tree *bucket_tree;
775   proto_item *tf;
776   proto_tree *field_tree;
777   int i;
778   guint8 bucket_info;
779   int n;
780
781   proto_tree_add_item(wccp_tree, hf_hash_revision, tvb, offset, 4,
782                       ENC_BIG_ENDIAN);
783   offset += 4;
784
785   bucket_item = proto_tree_add_text(wccp_tree, tvb, offset, 32,
786                                     "Hash information");
787   bucket_tree = proto_item_add_subtree(bucket_item, ett_buckets);
788
789   for (i = 0, n = 0; i < 32; i++) {
790     bucket_info = tvb_get_guint8(tvb, offset);
791     n = wccp_bucket_info(bucket_info, bucket_tree, n, tvb, offset);
792     offset += 1;
793   }
794   tf = proto_tree_add_item(wccp_tree, hf_hash_flag, tvb, offset, 4, ENC_BIG_ENDIAN);
795   field_tree = proto_item_add_subtree(tf, ett_hash_flags);
796   proto_tree_add_item(field_tree, hf_hash_flag_u, tvb, offset, 4, ENC_BIG_ENDIAN);
797   offset += 4;
798   return offset;
799 }
800
801 static guint
802 dissect_web_cache_list_entry(tvbuff_t *tvb, int offset, int idx,
803                              proto_tree *wccp_tree)
804 {
805   proto_item *tl;
806   proto_tree *list_entry_tree;
807
808   tl = proto_tree_add_text(wccp_tree, tvb, offset, 4 + HASH_INFO_SIZE,
809                            "Web-Cache List Entry(%d)", idx);
810   list_entry_tree = proto_item_add_subtree(tl, ett_cache_info);
811   proto_tree_add_item(list_entry_tree, hf_cache_ip, tvb, offset, 4,
812                       ENC_BIG_ENDIAN);
813   offset += 4;
814   offset = dissect_hash_data(tvb, offset, list_entry_tree);
815   return offset;
816 }
817
818 /*
819  * wccp_bucket_info()
820  * takes an integer representing a "Hash Information" bitmap, and spits out
821  * the corresponding proto_tree entries, returning the next bucket number.
822  */
823 static int
824 wccp_bucket_info(guint8 bucket_info, proto_tree *bucket_tree, guint32 start,
825                  tvbuff_t *tvb, int offset)
826 {
827   guint32 i;
828
829   for(i = 0; i < 8; i++) {
830     proto_tree_add_text(bucket_tree, tvb, offset, sizeof(bucket_info), "Bucket %3d: %s", start, (bucket_info & 1<<i ? "Assigned" : "Not Assigned") );
831     start++;
832   }
833   return(start);
834 }
835
836 static const gchar *
837 bucket_name(guint8 bucket)
838 {
839   if (bucket == 0xff) {
840     return "Unassigned";
841   } else {
842     return wmem_strdup_printf(wmem_packet_scope(), "%u", bucket);
843   }
844 }
845
846
847 /* 5.5 WCCP Message Header */
848 static guint16
849 dissect_wccp2_header(tvbuff_t *tvb, int offset, proto_tree *wccp_tree)
850 {
851   guint16 length;
852
853   proto_tree_add_item(wccp_tree, hf_message_header_version, tvb, offset, 2,
854                       ENC_BIG_ENDIAN);
855   offset += 2;
856   length = tvb_get_ntohs(tvb, offset);
857   proto_tree_add_uint(wccp_tree, hf_message_header_length, tvb, offset, 2, length);
858   return length;
859 }
860
861
862 static void
863 dissect_wccp2_info(tvbuff_t *tvb, int offset, guint16 length,
864                    packet_info *pinfo, proto_tree *wccp_tree,
865                    guint32 message_type)
866 {
867   guint16 type;
868   guint16 item_length;
869   proto_item *tf;
870   proto_tree *info_tree;
871   gint ett;
872   gint (*dissector)(tvbuff_t *, int, int, packet_info *, proto_tree *);
873
874   /* check if all required fields are there */
875   gboolean wccp2_security_info;
876   gboolean wccp2_service_info;
877   gboolean wccp2_router_id_info;
878   gboolean wccp2_wc_id_info;
879   gboolean wccp2_rtr_view_info;
880   gboolean wccp2_wc_view_info;
881   gboolean wccp2_redirect_assignment;
882   gboolean wccp2_query_info;
883   gboolean wccp2_capabilities_info;
884   gboolean wccp2_alt_assignment;
885   gboolean wccp2_assign_map;
886   gboolean wccp2_command_extension;
887   gboolean wccp2r1_alt_assignment_map;
888
889   wccp2_security_info=FALSE;
890   wccp2_service_info=FALSE;
891   wccp2_router_id_info=FALSE;
892   wccp2_wc_id_info=FALSE;
893   wccp2_rtr_view_info=FALSE;
894   wccp2_wc_view_info=FALSE;
895   wccp2_redirect_assignment=FALSE;
896   wccp2_query_info=FALSE;
897   wccp2_capabilities_info=FALSE;
898   wccp2_alt_assignment=FALSE;
899   wccp2_assign_map=FALSE;
900   wccp2_command_extension=FALSE;
901   wccp2r1_alt_assignment_map=FALSE;
902
903   /* ugly hack: we first need to check for the address table
904      compnent, otherwise we cannot print the IP's.
905   */
906   find_wccp_address_table(tvb,offset,length,pinfo,wccp_tree);
907
908   while (length != 0) {
909
910     if (length < 4) {
911       tf = proto_tree_add_text(wccp_tree, tvb, offset, length,
912                                "Invalid WCCP Type/Length values");
913
914       expert_add_info_format(pinfo, tf, &ei_wccp_length_bad,
915                              "The packet only has %d bytes left. That is not enough for a WCCP item type and length.",
916                              length);
917       break;
918     }
919
920     type = tvb_get_ntohs(tvb, offset);
921     item_length = tvb_get_ntohs(tvb, offset+2);
922
923
924     if (item_length > tvb_length_remaining(tvb, offset)) {
925       tf = proto_tree_add_text(wccp_tree, tvb, offset, length,
926                                "Excessive WCCP Length values");
927       expert_add_info_format(pinfo, tf, &ei_wccp_length_bad,
928                              "The length of the item is %d but there are only %d bytes remaining in the packet, I counted %d remaining",
929                              item_length, tvb_length_remaining(tvb, offset), length);
930       break;
931     }
932     switch (type) {
933
934     case WCCP2_SECURITY_INFO:
935       wccp2_security_info=TRUE;
936       ett = ett_security_info;
937       dissector = dissect_wccp2_security_info;
938       break;
939
940     case WCCP2_SERVICE_INFO:
941       wccp2_service_info=TRUE;
942       ett = ett_service_info;
943       dissector = dissect_wccp2_service_info;
944       break;
945
946     case WCCP2_ROUTER_ID_INFO:
947       wccp2_router_id_info=TRUE;
948       ett = ett_router_identity_info;
949       dissector = dissect_wccp2_router_identity_info;
950       break;
951
952     case WCCP2_WC_ID_INFO:
953       wccp2_wc_id_info=TRUE;
954       ett = ett_wc_identity_info;
955       dissector = dissect_wccp2_wc_identity_info;
956       break;
957
958     case WCCP2_RTR_VIEW_INFO:
959       wccp2_rtr_view_info=TRUE;
960       ett = ett_router_view_info;
961       dissector = dissect_wccp2_router_view_info;
962       break;
963
964     case WCCP2_WC_VIEW_INFO:
965       wccp2_wc_view_info=TRUE;
966       ett = ett_wc_view_info;
967       dissector = dissect_wccp2_web_cache_view_info;
968       break;
969
970     case WCCP2_REDIRECT_ASSIGNMENT:
971       wccp2_redirect_assignment=TRUE;
972       ett = ett_router_assignment_info;
973       dissector = dissect_wccp2_assignment_info;
974       break;
975
976     case WCCP2_QUERY_INFO:
977       wccp2_query_info=TRUE;
978       ett = ett_query_info;
979       dissector = dissect_wccp2_router_query_info;
980       break;
981
982     case WCCP2_CAPABILITIES_INFO:
983       wccp2_capabilities_info=TRUE;
984       ett = ett_capabilities_info;
985       dissector = dissect_wccp2_capability_info;
986       break;
987
988     case WCCP2_ALT_ASSIGNMENT:
989       wccp2_alt_assignment=TRUE;
990       ett = ett_alt_assignment_info;
991       dissector = dissect_wccp2_alternate_assignment_info;
992       break;
993
994     case WCCP2r1_ALT_ASSIGNMENT_MAP:
995       wccp2r1_alt_assignment_map=TRUE;
996       ett = ett_alt_assignment_map;
997       dissector = dissect_wccp2r1_alt_assignment_map_info;
998       break;
999
1000     case WCCP2r1_ADDRESS_TABLE:
1001       ett = ett_address_table;
1002       dissector = dissect_wccp2r1_address_table_info;
1003       break;
1004
1005     case WCCP2_ASSIGN_MAP:
1006       wccp2_assign_map=TRUE;
1007       ett = ett_assignment_map;
1008       dissector = dissect_wccp2_assignment_map;
1009       break;
1010     case WCCP2_COMMAND_EXTENSION:
1011       wccp2_command_extension=TRUE;
1012       ett = ett_command_extension;
1013       dissector = dissect_wccp2_command_extension;
1014       break;
1015
1016     default:
1017       ett = ett_unknown_info;
1018       dissector = NULL;
1019       break;
1020     }
1021
1022     tf = proto_tree_add_text(wccp_tree, tvb, offset, item_length + 4, "%s",
1023                              val_to_str(type, info_type_vals, "Unknown info type (%u)"));
1024     info_tree = proto_item_add_subtree(tf, ett);
1025     proto_tree_add_item(info_tree, hf_item_type, tvb, offset, 2, ENC_BIG_ENDIAN);
1026     proto_tree_add_item(info_tree, hf_item_length, tvb, offset+2, 2, ENC_BIG_ENDIAN);
1027
1028     offset += 4;
1029     length -= 4;
1030
1031     if (length < item_length) {
1032       expert_add_info_format(pinfo, tf, &ei_wccp_length_bad,
1033                              "The item has length %d but the remaining WCCP data is only %d long",
1034                              item_length,
1035                              length);
1036     }
1037
1038     if (dissector != NULL) {
1039       gint remaining_item_length = (*dissector)(tvb, offset, item_length, pinfo, info_tree);
1040
1041       /* warn if we left bytes */
1042       if (remaining_item_length > 0)
1043         expert_add_info_format(pinfo, tf, &ei_wccp_length_bad,
1044                                "The dissector left %d bytes undecoded",
1045                                remaining_item_length);
1046
1047       /* error if we needed more bytes */
1048       if (remaining_item_length < 0)
1049         expert_add_info_format(pinfo, tf, &ei_wccp_length_bad,
1050                                "The dissector needed %d more bytes to decode the packet, but the item is not that long",
1051                                remaining_item_length);
1052
1053       /* we assume that the item length is correct and jump forward */
1054     } else {
1055       proto_tree_add_item(info_tree, hf_item_data, tvb, offset, item_length, ENC_NA);
1056     }
1057     /* avoid looping forever */
1058     if (length < item_length)
1059       return;
1060
1061     offset += item_length;
1062
1063     /* should no happen....*/
1064     DISSECTOR_ASSERT( ( (signed int) length - item_length) >= 0);
1065     length -= item_length;
1066   }
1067
1068
1069   /* we're done. Check if we got all the required components */
1070
1071   switch (message_type) {
1072   case WCCP2_HERE_I_AM:
1073     if (!wccp2_security_info)
1074       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_security_info);
1075     if (!wccp2_service_info)
1076       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_service_info);
1077     if (wccp2_router_id_info)
1078       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_router_id_info);
1079     if (!wccp2_wc_id_info)
1080       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_wc_id_info);
1081     if (wccp2_rtr_view_info)
1082       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_rtr_view_info);
1083     if (!wccp2_wc_view_info)
1084       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_wc_view_info);
1085     if (wccp2_redirect_assignment)
1086       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_redirect_assignment);
1087     if (wccp2_query_info)
1088       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_query_info);
1089     if (wccp2_alt_assignment)
1090       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_alt_assignment);
1091     if (wccp2_assign_map)
1092       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_assign_map);
1093     if (wccp2r1_alt_assignment_map)
1094       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_alt_assignment_map);
1095     break;
1096   case WCCP2_I_SEE_YOU:
1097     if (!wccp2_security_info)
1098       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_security_info);
1099     if (!wccp2_service_info)
1100       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_service_info);
1101     if (!wccp2_router_id_info)
1102       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_router_id_info);
1103     if (wccp2_wc_id_info)
1104       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_wc_id_info);
1105     if (!wccp2_rtr_view_info)
1106       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_rtr_view_info);
1107     if (wccp2_wc_view_info)
1108       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_wc_view_info);
1109     if (wccp2_redirect_assignment)
1110       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_redirect_assignment);
1111     if (wccp2_query_info)
1112       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_query_info);
1113     if (wccp2r1_alt_assignment_map)
1114       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_alt_assignment_map);
1115     break;
1116
1117   case WCCP2_REMOVAL_QUERY:
1118     if (!wccp2_security_info)
1119       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_security_info);
1120     if (!wccp2_service_info)
1121       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_service_info);
1122     if (wccp2_router_id_info)
1123       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_router_id_info);
1124     if (wccp2_wc_id_info)
1125       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_wc_id_info);
1126     if (wccp2_rtr_view_info)
1127       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_rtr_view_info);
1128     if (wccp2_wc_view_info)
1129       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_wc_view_info);
1130     if (wccp2_redirect_assignment)
1131       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_redirect_assignment);
1132     if (!wccp2_query_info)
1133       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_query_info);
1134     if (wccp2_capabilities_info)
1135       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_capabilities_info);
1136     if (wccp2_alt_assignment)
1137       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_alt_assignment);
1138     if (wccp2_assign_map)
1139       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_assign_map);
1140     if (wccp2_command_extension)
1141       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_command_extension);
1142     if (wccp2r1_alt_assignment_map)
1143       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_alt_assignment_map);
1144     break;
1145
1146   case WCCP2_REDIRECT_ASSIGN:
1147     if (!wccp2_security_info)
1148       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_security_info);
1149     if (!wccp2_service_info)
1150       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_service_info);
1151     if (wccp2_router_id_info)
1152       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_router_id_info);
1153     if (wccp2_wc_id_info)
1154       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_wc_id_info);
1155     if (wccp2_rtr_view_info)
1156       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_rtr_view_info);
1157     if (wccp2_wc_view_info)
1158       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_wc_view_info);
1159     if (wccp2_query_info)
1160       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_query_info);
1161     if (wccp2_capabilities_info)
1162       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_capabilities_info);
1163     if (! (wccp2_assign_map || wccp2r1_alt_assignment_map || wccp2_alt_assignment || wccp2_redirect_assignment))
1164       expert_add_info(pinfo, wccp_tree, &ei_wccp_missing_assignment);
1165     if (wccp2_command_extension)
1166       expert_add_info(pinfo, wccp_tree, &ei_wccp_contains_command_extension);
1167     break;
1168   }
1169 }
1170
1171 /* the following functions all need to check the length and the offset
1172    so we have a few macros to use
1173 */
1174
1175 #define EAT(x) {length -= x; offset += x;}
1176
1177 #define EAT_AND_CHECK(x,next) {length -= x; offset += x; if (length < next) return length - next;}
1178
1179 #define NOTE_EATEN_LENGTH(new_length) {if (new_length<0) return new_length;  offset += length-new_length; length = new_length; }
1180
1181
1182 /* 5.1.1 Security Info Component */
1183
1184 /* Security options */
1185
1186 #define WCCP2_NO_SECURITY               0
1187 #define WCCP2_MD5_SECURITY              1
1188
1189 #define SECURITY_INFO_LEN               4
1190
1191 const value_string security_option_vals[] = {
1192   { WCCP2_NO_SECURITY, "None" },
1193   { WCCP2_MD5_SECURITY, "MD5" },
1194   { 0,    NULL }
1195 };
1196
1197
1198 static gint
1199 dissect_wccp2_security_info(tvbuff_t *tvb, int offset, gint length,
1200                             packet_info *pinfo _U_, proto_tree *info_tree)
1201 {
1202   guint32 security_option;
1203
1204   if (length < SECURITY_INFO_LEN)
1205     return (length-SECURITY_INFO_LEN);
1206
1207   security_option = tvb_get_ntohl(tvb, offset);
1208   proto_tree_add_item(info_tree, hf_security_info_option, tvb, offset, 4, ENC_BIG_ENDIAN);
1209
1210   if (security_option == WCCP2_MD5_SECURITY) {
1211     offset += 4;
1212
1213     proto_tree_add_item(info_tree, hf_security_info_md5_checksum, tvb, offset, length-4, ENC_NA);
1214
1215     return length-4-16;
1216   }
1217   return length-4;
1218 }
1219
1220
1221 /* 5.1.2 Service Info Component */
1222
1223 #define SERVICE_INFO_LEN                (4+4+8*2)
1224
1225 #define WCCP2_SERVICE_STANDARD          0
1226 #define WCCP2_SERVICE_DYNAMIC           1
1227
1228 const value_string service_type_vals[] = {
1229   { WCCP2_SERVICE_STANDARD, "Standard predefined service"},
1230   { WCCP2_SERVICE_DYNAMIC, "Dynamic CE defined service" },
1231   { 0,    NULL }
1232 };
1233
1234 /*
1235  * Service flags.
1236  */
1237 #define WCCP2_SI_SRC_IP_HASH                    0x0001
1238 #define WCCP2_SI_DST_IP_HASH                    0x0002
1239 #define WCCP2_SI_SRC_PORT_HASH                  0x0004
1240 #define WCCP2_SI_DST_PORT_HASH                  0x0008
1241 #define WCCP2_SI_PORTS_DEFINED                  0x0010
1242 #define WCCP2_SI_PORTS_SOURCE                   0x0020
1243 #define WCCP2r1_SI_REDIRECT_ONLY_PROTOCOL_0     0x0040
1244 #define WCCP2_SI_SRC_IP_ALT_HASH                0x0100
1245 #define WCCP2_SI_DST_IP_ALT_HASH                0x0200
1246 #define WCCP2_SI_SRC_PORT_ALT_HASH              0x0400
1247 #define WCCP2_SI_DST_PORT_ALT_HASH              0x0800
1248
1249
1250 static gint
1251 dissect_wccp2_service_info(tvbuff_t *tvb, int offset, gint length,
1252                            packet_info *pinfo, proto_tree *info_tree)
1253 {
1254   guint8 service_type;
1255   guint32 flags;
1256   proto_item *tf;
1257   proto_tree *field_tree, *ports_tree;
1258   int i;
1259   gchar *buf;
1260   int max_offset = offset+length;
1261
1262   if (length != SERVICE_INFO_LEN)
1263     return length - SERVICE_INFO_LEN;
1264
1265   service_type = tvb_get_guint8(tvb, offset);
1266   proto_tree_add_item(info_tree, hf_service_info_type, tvb,
1267                       offset, 1, ENC_BIG_ENDIAN);
1268
1269   switch (service_type) {
1270
1271   case WCCP2_SERVICE_STANDARD:
1272     proto_tree_add_item(info_tree, hf_service_info_id_standard, tvb,
1273                         offset +1 , 1, ENC_BIG_ENDIAN);
1274
1275     tf = proto_tree_add_item(info_tree, hf_service_info_priority, tvb, offset+2, 1, ENC_BIG_ENDIAN);
1276     if (tvb_get_guint8(tvb, offset+2) != 0)
1277       expert_add_info(pinfo, tf, &ei_wccp_service_info_priority_nonzero);
1278
1279     tf = proto_tree_add_item(info_tree, hf_service_info_protocol, tvb,
1280                         offset+3, 1, ENC_BIG_ENDIAN);
1281
1282     if (tvb_get_guint8(tvb, offset+3) != 0)
1283       expert_add_info(pinfo, tf, &ei_wccp_service_info_protocol_nonzero);
1284     break;
1285
1286   case WCCP2_SERVICE_DYNAMIC:
1287     proto_tree_add_item(info_tree, hf_service_info_id_dynamic, tvb,
1288                         offset +1 , 1, ENC_BIG_ENDIAN);
1289     proto_tree_add_item(info_tree, hf_service_info_priority, tvb,
1290                         offset+2, 1, ENC_BIG_ENDIAN);
1291     proto_tree_add_item(info_tree, hf_service_info_protocol, tvb,
1292                         offset+3, 1, ENC_BIG_ENDIAN);
1293     break;
1294   }
1295   offset += 4;
1296
1297   flags = tvb_get_ntohl(tvb, offset);
1298   tf = proto_tree_add_item(info_tree, hf_service_info_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
1299
1300   field_tree = proto_item_add_subtree(tf, ett_service_flags);
1301   proto_tree_add_item(field_tree, hf_service_info_flags_src_ip_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
1302   proto_tree_add_item(field_tree, hf_service_info_flags_dest_ip_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
1303   proto_tree_add_item(field_tree, hf_service_info_flags_src_port_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
1304   proto_tree_add_item(field_tree, hf_service_info_flags_dest_port_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
1305   proto_tree_add_item(field_tree, hf_service_info_flags_ports_defined, tvb, offset, 4, ENC_BIG_ENDIAN);
1306   /* if they are defined which ? */
1307   if (flags & WCCP2_SI_PORTS_DEFINED)
1308     proto_tree_add_item(field_tree, hf_service_info_flags_ports_source, tvb, offset, 4, ENC_BIG_ENDIAN);
1309
1310   proto_tree_add_item(field_tree, hf_service_info_flags_redirect_only_protocol_0, tvb, offset, 4, ENC_BIG_ENDIAN);
1311   proto_tree_add_item(field_tree, hf_service_info_flags_src_ip_alt_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
1312   proto_tree_add_item(field_tree, hf_service_info_flags_dest_ip_alt_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
1313   proto_tree_add_item(field_tree, hf_service_info_flags_src_port_alt_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
1314   proto_tree_add_item(field_tree, hf_service_info_flags_dest_port_alt_hash, tvb, offset, 4, ENC_BIG_ENDIAN);
1315
1316   buf= (char *) wmem_alloc(wmem_packet_scope(), 128);
1317   decode_bitfield_value(buf, flags,
1318                         0xFFFFFFFF ^ (WCCP2_SI_SRC_IP_HASH
1319                                       | WCCP2_SI_DST_IP_HASH
1320                                       | WCCP2_SI_SRC_PORT_HASH
1321                                       | WCCP2_SI_DST_PORT_HASH
1322                                       | WCCP2_SI_PORTS_DEFINED
1323                                       | WCCP2_SI_PORTS_SOURCE
1324                                       | WCCP2r1_SI_REDIRECT_ONLY_PROTOCOL_0
1325                                       | WCCP2_SI_SRC_IP_ALT_HASH
1326                                       | WCCP2_SI_DST_IP_ALT_HASH
1327                                       | WCCP2_SI_SRC_PORT_ALT_HASH
1328                                       | WCCP2_SI_DST_PORT_ALT_HASH),
1329                         32);
1330   proto_tree_add_text(field_tree, tvb, offset, 2,
1331                       "%s : %s",
1332                       buf, "reserved, should be 0");
1333
1334   offset += 4;
1335
1336   if (flags & WCCP2_SI_PORTS_DEFINED) {
1337     tf = proto_tree_add_text(info_tree, tvb, offset, 2*8,
1338                              "Ports list: ");
1339     ports_tree = proto_item_add_subtree(tf, ett_service_info_ports);
1340
1341     for (i = 0; i < 8; i++) {
1342       guint16 port = tvb_get_ntohs(tvb, offset);
1343
1344       if (port) {
1345         if (flags & WCCP2_SI_SRC_PORT_HASH)
1346           proto_tree_add_item(ports_tree, hf_service_info_source_port, tvb, offset, 2, ENC_BIG_ENDIAN);
1347         else
1348           proto_tree_add_item(ports_tree, hf_service_info_destination_port, tvb, offset, 2, ENC_BIG_ENDIAN);
1349         proto_item_append_text(tf, " %d", port);
1350       }
1351       offset += 2;
1352       DISSECTOR_ASSERT(offset <= max_offset);
1353     }
1354   }
1355   else {
1356     /* just use up the space if there is */
1357     if (offset + 8 * 2 <= max_offset)  {
1358       proto_tree_add_text(info_tree, tvb, offset, 8*2,
1359                           "Ports fields not used");
1360       /*offset += 8*2;*/
1361     }
1362   }
1363
1364   return length - SERVICE_INFO_LEN;
1365 }
1366
1367 /* 6.1 Router Identity Element */
1368 static void
1369 dissect_wccp2_router_identity_element(tvbuff_t *tvb, int offset, packet_info *pinfo,
1370                                       proto_tree *tree)
1371 {
1372   proto_item *tf;
1373
1374
1375   proto_tree_add_item(tree, hf_router_identity_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1376   tf = proto_tree_add_item(tree, hf_router_identity_receive_id, tvb, offset+4, 4, ENC_BIG_ENDIAN);
1377
1378   if (tvb_get_ntohl(tvb, offset + 4) == 0)
1379     expert_add_info(pinfo, tf, &ei_wccp_router_identity_receive_id_zero);
1380 }
1381
1382 #define ROUTER_ID_INFO_MIN_LEN          (8+4+4)
1383
1384 /* 5.3.1 Router Identity Info Component */
1385 static gint
1386 dissect_wccp2_router_identity_info(tvbuff_t *tvb, int offset, gint length,
1387                                    packet_info *pinfo, proto_tree *info_tree)
1388 {
1389   guint32 n_received_from;
1390   guint i;
1391   proto_item *te;
1392   proto_tree *element_tree;
1393
1394   if (length < 8)
1395     return length -  ROUTER_ID_INFO_MIN_LEN;
1396
1397
1398   te = proto_tree_add_item(info_tree, hf_router_identity_router_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1399
1400   element_tree = proto_item_add_subtree(te,ett_wc_view_info_router_element);
1401
1402   dissect_wccp2_router_identity_element(tvb,offset,pinfo,element_tree);
1403   EAT_AND_CHECK(8,4);
1404
1405
1406   proto_tree_add_item(info_tree, hf_router_identity_send_to_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1407   EAT_AND_CHECK(4,4);
1408
1409   n_received_from = tvb_get_ntohl(tvb, offset);
1410   proto_tree_add_item(info_tree, hf_router_identity_received_from_num, tvb, offset, 4, ENC_BIG_ENDIAN);
1411   EAT(4);
1412
1413   for (i = 0; i < n_received_from; i++) {
1414     if (length < 4)
1415       return length-4*(i-n_received_from);
1416
1417
1418     proto_tree_add_item(info_tree, hf_router_identity_received_from_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1419     EAT(4);
1420   }
1421
1422   return length;
1423 }
1424
1425 #define ROUTER_WC_ID_ELEMENT_MIN_LEN (4+2+2)
1426
1427 /* 6.4 Web-Cache Identity Element */
1428 static gint
1429 dissect_wccp2_web_cache_identity_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
1430                                          proto_tree *info_tree)
1431 {
1432   proto_item *tf;
1433   proto_tree *field_tree;
1434   guint16 flags;
1435   guint data_element_type;
1436   char *buf;
1437
1438   if (length < ROUTER_WC_ID_ELEMENT_MIN_LEN)
1439     return length - ROUTER_WC_ID_ELEMENT_MIN_LEN;
1440
1441   proto_tree_add_item(info_tree, hf_web_cache_identity_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1442   EAT_AND_CHECK(4,2);
1443
1444   tf = proto_tree_add_item(info_tree, hf_web_cache_identity_hash_rev, tvb, offset, 2, ENC_BIG_ENDIAN);
1445   if (tvb_get_ntohs(tvb, offset) != 0)
1446     expert_add_info(pinfo, tf, &ei_wccp_web_cache_identity_hash_rev_zero);
1447
1448   EAT_AND_CHECK(2,2);
1449
1450   flags = tvb_get_ntohs(tvb, offset);
1451   tf = proto_tree_add_uint(info_tree, hf_web_cache_identity_flags, tvb, offset, 2, flags);
1452   data_element_type = (flags & 0x6) >> 1;
1453
1454   field_tree = proto_item_add_subtree(tf, ett_wc_identity_flags);
1455   proto_tree_add_item(field_tree, hf_web_cache_identity_flag_hash_info, tvb, offset, 2, ENC_BIG_ENDIAN);
1456   proto_tree_add_item(field_tree, hf_web_cache_identity_flag_assign_type, tvb, offset, 2, ENC_BIG_ENDIAN);
1457   proto_tree_add_item(field_tree, hf_web_cache_identity_flag_version_request, tvb, offset, 2, ENC_BIG_ENDIAN);
1458   buf=(char *) wmem_alloc(wmem_packet_scope(), 128);
1459   decode_bitfield_value(buf, flags, 0xFFF0, 16);
1460   proto_tree_add_text(field_tree, tvb, offset, 2,
1461                       "%s : %s",
1462                       buf, "reserved, should be 0");
1463   EAT(2);
1464
1465   switch (data_element_type) {
1466   case WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_HASH:
1467     return dissect_wccp2_hash_assignment_data_element(tvb,offset,length,pinfo,info_tree);
1468   case WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_MASK:
1469     return dissect_wccp2_mask_assignment_data_element(tvb,offset,length,pinfo,info_tree);
1470
1471   case WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_NOT_PRESENT:
1472     proto_tree_add_text(info_tree, tvb, offset, 2,
1473                         "No Assignment Data Present");
1474     return length;
1475     break;
1476   case WCCP2_WEB_CACHE_ASSIGNMENT_DATA_TYPE_EXTENDED:
1477     return dissect_wccp2_extended_assignment_data_element(tvb,offset,length,pinfo,info_tree);
1478   }
1479   return length;
1480 }
1481
1482 /* 5.2.1  Web-Cache Identity Info Component */
1483 static gint
1484 dissect_wccp2_wc_identity_info(tvbuff_t *tvb, int offset, gint length,
1485                                packet_info *pinfo _U_, proto_tree *info_tree)
1486 {
1487   proto_item *te;
1488   proto_tree *element_tree;
1489
1490
1491   te = proto_tree_add_item(info_tree, hf_wc_identity_ip_address, tvb, offset, 4, ENC_BIG_ENDIAN);
1492
1493   element_tree = proto_item_add_subtree(te, ett_wc_identity_element);
1494   return dissect_wccp2_web_cache_identity_element(tvb, offset,length, pinfo,
1495                                                   element_tree);
1496 }
1497
1498 /* 6.3 Assignment Key Element */
1499 static gint
1500 dissect_wccp2_assignment_key_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo _U_,
1501                                      proto_tree *info_tree)
1502 {
1503   if (length < 8)
1504     return length -8;
1505
1506
1507   proto_tree_add_item(info_tree, hf_assignment_key_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1508
1509   EAT_AND_CHECK(4,4);
1510   proto_tree_add_item(info_tree, hf_assignment_key_change_num, tvb, offset, 4, ENC_BIG_ENDIAN);
1511   EAT(4);
1512
1513   return length;
1514 }
1515
1516
1517 #define ROUTER_VIEW_INFO_MIN_LEN        (4+8+4+4)
1518
1519 /* 5.3.2 Router View Info Component */
1520 static gint
1521 dissect_wccp2_router_view_info(tvbuff_t *tvb, int offset, gint length,
1522                                packet_info *pinfo, proto_tree *info_tree)
1523 {
1524   guint32 n_routers;
1525   guint32 n_web_caches;
1526   guint i;
1527   proto_item *te;
1528   proto_tree *element_tree;
1529   gint new_length;
1530
1531   if (length < ROUTER_VIEW_INFO_MIN_LEN)
1532     return length - ROUTER_VIEW_INFO_MIN_LEN;
1533
1534   proto_tree_add_item(info_tree, hf_router_view_member_change_num, tvb, offset, 4, ENC_BIG_ENDIAN);
1535   EAT(4);
1536
1537   new_length=dissect_wccp2_assignment_key_element(tvb, offset, length, pinfo, info_tree);
1538   NOTE_EATEN_LENGTH(new_length);
1539
1540   n_routers = tvb_get_ntohl(tvb, offset);
1541   proto_tree_add_uint(info_tree, hf_router_router_num, tvb, offset, 4, n_routers);
1542   EAT(4);
1543
1544   for (i = 0; i < n_routers; i++) {
1545     if (length < 4)
1546       return length - (n_routers-i)*4 - 4;
1547
1548     proto_tree_add_item(info_tree, hf_router_view_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1549     EAT(4);
1550   }
1551
1552   if (length < 4)
1553     return length - 4;
1554
1555   n_web_caches = tvb_get_ntohl(tvb, offset);
1556   proto_tree_add_uint(info_tree, hf_wc_view_wc_num, tvb, offset, 4, n_web_caches);
1557   EAT(4);
1558
1559   for (i = 0; i < n_web_caches; i++) {
1560     gint old_length;
1561     old_length = length;
1562
1563     if (length < 4)
1564       return length - 4*(n_web_caches-i);
1565
1566     te = proto_tree_add_item(info_tree, hf_router_query_info_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1567
1568     element_tree = proto_item_add_subtree(te, ett_wc_identity_element);
1569     length = dissect_wccp2_web_cache_identity_element(tvb,
1570                                                       offset, length, pinfo,
1571                                                       element_tree);
1572     if (length < 0)
1573       return length;
1574
1575     offset += old_length - length;
1576   }
1577   return length;
1578 }
1579
1580 #define WC_VIEW_INFO_MIN_LEN            (4+4+4)
1581
1582 /* 5.2.2 Web Cache View Info Component */
1583
1584 static gint
1585 dissect_wccp2_web_cache_view_info(tvbuff_t *tvb, int offset, gint length,
1586                                   packet_info *pinfo, proto_tree *info_tree)
1587 {
1588   guint32 n_routers;
1589   guint32 n_web_caches;
1590   guint i;
1591   proto_item *te;
1592   proto_tree *element_tree;
1593
1594
1595   if (length < WC_VIEW_INFO_MIN_LEN)
1596     return length - WC_VIEW_INFO_MIN_LEN;
1597
1598
1599   proto_tree_add_item(info_tree, hf_wc_view_info_change_num, tvb, offset, 4, ENC_BIG_ENDIAN);
1600   EAT_AND_CHECK(4,4);
1601
1602   n_routers = tvb_get_ntohl(tvb, offset);
1603   proto_tree_add_uint(info_tree, hf_wc_view_router_num, tvb, offset, 4, n_routers);
1604   EAT(4);
1605
1606   for (i = 0; i < n_routers; i++) {
1607     if (length < 8)
1608       return length -8 * (n_routers-i) - 4;
1609
1610     te = proto_tree_add_item(info_tree, hf_wc_view_info_router_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1611     /* also include the receive id in the object */
1612     proto_item_set_len(te, 8);
1613
1614     element_tree = proto_item_add_subtree(te,ett_wc_view_info_router_element);
1615     dissect_wccp2_router_identity_element(tvb, offset, pinfo, element_tree);
1616     EAT(8);
1617   }
1618
1619   if (length < 4)
1620     return length - 4;
1621
1622   n_web_caches = tvb_get_ntohl(tvb, offset);
1623   proto_tree_add_uint(info_tree, hf_wc_view_wc_num, tvb, offset, 4, n_web_caches);
1624   EAT(4);
1625
1626   for (i = 0; i < n_web_caches; i++) {
1627     if (length < 4)
1628       return length - 4*(n_web_caches-i);
1629
1630     proto_tree_add_item(info_tree, hf_wc_view_info_wc_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1631     EAT(4);
1632   }
1633   return length;
1634 }
1635
1636 /* 6.2 Router Assignment Element */
1637 static void
1638 dissect_wccp2_router_assignment_element(tvbuff_t *tvb, int offset,
1639                                         gint length, packet_info *pinfo, proto_tree *info_tree)
1640 {
1641   dissect_wccp2_router_identity_element(tvb,offset,pinfo,info_tree);
1642   EAT(8);
1643   proto_tree_add_item(info_tree, hf_router_assignment_element_change_num, tvb, offset, 4, ENC_BIG_ENDIAN);
1644   EAT(4);
1645 }
1646
1647 static const gchar *
1648 assignment_bucket_name(guint8 bucket)
1649 {
1650   const gchar *cur;
1651
1652   if (bucket == 0xff) {
1653     cur= "Unassigned";
1654   } else {
1655     cur=wmem_strdup_printf(wmem_packet_scope(), "%u%s", bucket & 0x7F,
1656                          (bucket & 0x80) ? " (Alt)" : "");
1657   }
1658   return cur;
1659 }
1660
1661 #define ASSIGNMENT_INFO_MIN_LEN         (8+4+4)
1662
1663 /* 5.4.1 Assignment Info Component  */
1664 static gint
1665 dissect_wccp2_assignment_info(tvbuff_t *tvb, int offset, gint length,
1666                               packet_info *pinfo, proto_tree *info_tree)
1667 {
1668   guint32 n_routers;
1669   guint i;
1670   proto_item *te;
1671   proto_tree *element_tree;
1672   gint new_length;
1673
1674   if (length < ASSIGNMENT_INFO_MIN_LEN)
1675     return length - ASSIGNMENT_INFO_MIN_LEN;
1676
1677
1678   new_length=dissect_wccp2_assignment_key_element(tvb, offset, length, pinfo,  info_tree);
1679   NOTE_EATEN_LENGTH(new_length);
1680
1681   n_routers = tvb_get_ntohl(tvb, offset);
1682   proto_tree_add_uint(info_tree, hf_assignment_info_router_num, tvb, offset, 4, n_routers);
1683   EAT(4);
1684
1685   for (i = 0; i < n_routers; i++) {
1686     if (length < 12)
1687       return length - 12*(n_routers-i)-4-256;
1688
1689     te = proto_tree_add_item(info_tree, hf_assignment_info_router_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1690
1691     element_tree = proto_item_add_subtree(te, ett_router_assignment_element);
1692     dissect_wccp2_router_assignment_element(tvb, offset, length , pinfo,
1693                                             element_tree);
1694     EAT(12);
1695   }
1696
1697   new_length = dissect_wccp2_hash_buckets_assignment_element(tvb, offset, length, pinfo, info_tree);
1698   NOTE_EATEN_LENGTH(new_length);
1699   return length;
1700 }
1701
1702
1703 #define QUERY_INFO_LEN                  (4+4+4+4)
1704
1705 /* 5.5.1 Router Query Info Component */
1706 static gboolean
1707 dissect_wccp2_router_query_info(tvbuff_t *tvb, int offset, gint length,
1708                                 packet_info *pinfo, proto_tree *info_tree)
1709 {
1710   if (length < QUERY_INFO_LEN)
1711     return length - QUERY_INFO_LEN;
1712
1713   dissect_wccp2_router_identity_element(tvb,offset,pinfo,info_tree);
1714   EAT_AND_CHECK(8,4);
1715
1716   proto_tree_add_item(info_tree, hf_router_query_info_send_to_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1717   EAT_AND_CHECK(4,4);
1718   proto_tree_add_item(info_tree, hf_router_query_info_target_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1719   EAT(4);
1720
1721   return length;
1722 }
1723
1724 /* 6.5 Hash Buckets Assignment Element */
1725 static gint dissect_wccp2_hash_buckets_assignment_element(tvbuff_t *tvb, int offset, gint length,
1726                                                           packet_info *pinfo _U_, proto_tree *info_tree)
1727 {
1728   guint32 i,n_web_caches;
1729   proto_item *te;
1730   proto_tree *element_tree;
1731
1732   if (length < 4)
1733     return length - 4;
1734
1735   n_web_caches = tvb_get_ntohl(tvb, offset);
1736   te = proto_tree_add_uint(info_tree, hf_hash_buckets_assignment_wc_num, tvb, offset, 4, n_web_caches);
1737   EAT(4);
1738
1739   element_tree = proto_item_add_subtree(te,ett_hash_buckets_assignment_wc_element);
1740   for (i = 0; i < n_web_caches; i++) {
1741     proto_item *l_te;
1742
1743     if (length < 4)
1744       return length - 4*(n_web_caches-i)-256;
1745
1746     l_te = proto_tree_add_item(element_tree, hf_hash_buckets_assignment_wc_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1747
1748     proto_item_append_text(l_te, " id: %d", i);
1749     EAT(4);
1750   }
1751
1752   te = proto_tree_add_text(info_tree,tvb, offset,256, "Buckets");
1753   element_tree = proto_item_add_subtree(te,ett_hash_buckets_assignment_buckets);
1754
1755   for (i = 0; i < 256; i += 4) {
1756     if (length < 4)
1757       return length - (256-i);
1758
1759     proto_tree_add_text(element_tree, tvb, offset, 4,
1760                         "Buckets %3d - %3d: %10s %10s %10s %10s",
1761                         i, i + 3,
1762                         assignment_bucket_name(tvb_get_guint8(tvb, offset)),
1763                         assignment_bucket_name(tvb_get_guint8(tvb, offset+1)),
1764                         assignment_bucket_name(tvb_get_guint8(tvb, offset+2)),
1765                         assignment_bucket_name(tvb_get_guint8(tvb, offset+3)));
1766     EAT(4);
1767   }
1768   return length;
1769 }
1770
1771 #define WCCP2_FORWARDING_METHOD_GRE     0x00000001
1772 #define WCCP2_FORWARDING_METHOD_L2      0x00000002
1773
1774 static const capability_flag forwarding_method_flags[] = {
1775   { WCCP2_FORWARDING_METHOD_GRE, "IP-GRE", &hf_capability_forwarding_method_flag_gre },
1776   { WCCP2_FORWARDING_METHOD_L2, "L2", &hf_capability_forwarding_method_flag_l2 },
1777   { 0, NULL, NULL }
1778 };
1779
1780 #define WCCP2_ASSIGNMENT_METHOD_HASH    0x00000001
1781 #define WCCP2_ASSIGNMENT_METHOD_MASK    0x00000002
1782
1783 static const capability_flag assignment_method_flags[] = {
1784   { WCCP2_ASSIGNMENT_METHOD_HASH, "Hash", &hf_capability_assignment_method_flag_hash },
1785   { WCCP2_ASSIGNMENT_METHOD_MASK, "Mask", &hf_capability_assignment_method_flag_mask },
1786   { 0,                            NULL,   NULL }
1787 };
1788
1789
1790 #define WCCP2_PACKET_RETURN_METHOD_GRE  0x00000001
1791 #define WCCP2_PACKET_RETURN_METHOD_L2   0x00000002
1792
1793 static const capability_flag packet_return_method_flags[] = {
1794   { WCCP2_PACKET_RETURN_METHOD_GRE, "IP-GRE", &hf_capability_return_method_flag_gre },
1795   { WCCP2_PACKET_RETURN_METHOD_L2, "L2", &hf_capability_return_method_flag_l2 },
1796   { 0, NULL, NULL }
1797 };
1798
1799 #define WCCP2_COMMAND_TYPE_SHUTDOWN           1
1800 #define WCCP2_COMMAND_TYPE_SHUTDOWN_RESPONSE  2
1801
1802 static const value_string wccp_command_type_vals[] = {
1803   { WCCP2_COMMAND_TYPE_SHUTDOWN,          "CE shutting down" },
1804   { WCCP2_COMMAND_TYPE_SHUTDOWN_RESPONSE, "Router Acknowledge CE shutdown"},
1805   { 0, NULL }
1806 };
1807
1808
1809
1810 /* 5.1.3 Capabilities Info Component */
1811
1812 static gint
1813 dissect_wccp2_capability_info(tvbuff_t *tvb, int offset, gint length,
1814                               packet_info *pinfo, proto_tree *info_tree)
1815 {
1816   gint capability_length;
1817
1818   while (length >= 8) {
1819     capability_length = dissect_wccp2_capability_element(tvb,offset,length,pinfo,info_tree);
1820
1821     NOTE_EATEN_LENGTH(capability_length);
1822   }
1823   return length;
1824 }
1825
1826
1827 #define ALT_COMMAND_EXTENSION_MIN_LEN  (4)
1828
1829 /* 5.1.4 && 6.12 Command Extension Component */
1830
1831 static gint
1832 dissect_wccp2_command_extension(tvbuff_t *tvb, int offset,
1833                                 int length, packet_info *pinfo _U_, proto_tree *info_tree)
1834 {
1835   guint16 command_type;
1836   guint16 command_length;
1837
1838   for (;;) {
1839     if (length == 0)
1840       return length;
1841
1842     if (length < ALT_COMMAND_EXTENSION_MIN_LEN )
1843       return length - ALT_COMMAND_EXTENSION_MIN_LEN ;
1844
1845     command_type = tvb_get_ntohs(tvb, offset);
1846     proto_tree_add_item(info_tree, hf_command_element_type, tvb, offset, 2, ENC_BIG_ENDIAN);
1847     EAT_AND_CHECK(2,2);
1848
1849
1850     command_length = tvb_get_ntohs(tvb, offset);
1851     proto_tree_add_item(info_tree, hf_command_element_length, tvb, offset, 2, ENC_BIG_ENDIAN);
1852     proto_tree_add_text(info_tree, tvb, offset, 2,
1853                         "Command length: %u", command_length);
1854     EAT(2);
1855
1856     if (((command_type == WCCP2_COMMAND_TYPE_SHUTDOWN) ||
1857          (command_type == WCCP2_COMMAND_TYPE_SHUTDOWN_RESPONSE)) &&
1858         (command_length == 4)) {
1859       if (length < 4)
1860         return length - 4;
1861       proto_tree_add_item(info_tree, hf_command_element_shutdown_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
1862     } else {
1863       if (length < command_length)
1864         return length - command_length;
1865
1866       proto_tree_add_text(info_tree, tvb, offset, command_length,
1867                           "Unknown command");
1868     }
1869     EAT(command_length);
1870   }
1871 }
1872
1873
1874 /* 5.1.5 Address Table Component */
1875 /* this function is special as it can be invoked twice during a packet decode:
1876    once to get the tables, once to display them
1877 */
1878 static gint
1879 dissect_wccp2r1_address_table_info(tvbuff_t *tvb, int offset,
1880                                    int length, packet_info *pinfo, proto_tree *info_tree)
1881 {
1882   guint16 address_length;
1883   guint32 i;
1884   proto_tree *element_tree=NULL;
1885   proto_item *tf=NULL;
1886
1887   wccp_wccp_address_table.in_use = TRUE;
1888
1889   if (info_tree)
1890     tf = proto_tree_get_parent(info_tree);
1891
1892   if (length < 2*4)
1893     return length - 2*4;
1894
1895
1896   wccp_wccp_address_table.family = tvb_get_ntohs(tvb,offset);
1897   if (pinfo && info_tree)
1898     proto_tree_add_item(info_tree, hf_address_table_family, tvb,
1899                         offset, 2, ENC_BIG_ENDIAN);
1900   EAT_AND_CHECK(2,2);
1901
1902   address_length = tvb_get_ntohs(tvb,offset);
1903   if (info_tree)
1904     proto_tree_add_item(info_tree, hf_address_table_address_length, tvb, offset, 2, ENC_BIG_ENDIAN);
1905   EAT_AND_CHECK(2,2);
1906
1907   wccp_wccp_address_table.table_length =  tvb_get_ntohl(tvb,offset);
1908   if (pinfo && info_tree) {
1909     tf = proto_tree_add_item(info_tree, hf_address_table_length, tvb, offset, 4, ENC_BIG_ENDIAN);
1910     element_tree = proto_item_add_subtree(tf, ett_table_element);
1911   }
1912   EAT(4);
1913
1914   /* check if the length is valid and allocate the tables if needed*/
1915   switch (wccp_wccp_address_table.family) {
1916   case 1:
1917     if (wccp_wccp_address_table.table_ipv4 == NULL)
1918       wccp_wccp_address_table.table_ipv4 = (guint32 *)
1919         wmem_alloc(wmem_packet_scope(), wccp_wccp_address_table.table_length * 4);
1920     if ((address_length != 4) && (pinfo && info_tree)) {
1921       expert_add_info_format(pinfo, tf, &ei_wccp_length_bad,
1922                              "The Address length must be 4, but I found  %d for IPv4 addresses. Correcting this.",
1923                              address_length);
1924       address_length = 4;
1925     }
1926     break;
1927   case 2:
1928     if (wccp_wccp_address_table.table_ipv6 == NULL)
1929       wccp_wccp_address_table.table_ipv6 = (struct e_in6_addr *)
1930         wmem_alloc(wmem_packet_scope(), wccp_wccp_address_table.table_length * sizeof(struct e_in6_addr));
1931     if ((address_length != 16) && (pinfo && info_tree)) {
1932       expert_add_info_format(pinfo, tf, &ei_wccp_length_bad,
1933                              "The Address length must be 16, but I found %d for IPv6 addresses.  Correcting this",
1934                              address_length);
1935       address_length=16;
1936     }
1937     break;
1938   default:
1939     if (pinfo && info_tree) {
1940       expert_add_info_format(pinfo, tf, &ei_wccp_address_table_family_unknown,
1941                     "Unknown address family: %d", wccp_wccp_address_table.family);
1942     }
1943   };
1944
1945   /* now read the addresses and print/store them */
1946
1947   for(i=0; i<wccp_wccp_address_table.table_length; i++) {
1948     const gchar* addr;
1949
1950     /* do we have space? */
1951     if (length < address_length) {
1952       if (pinfo && tf)
1953         expert_add_info_format(pinfo, tf, &ei_wccp_length_bad, "Ran out of space to decode");
1954
1955       /* first clean up: */
1956       wccp_wccp_address_table.in_use = FALSE;
1957       wccp_wccp_address_table.family = -1;
1958       wccp_wccp_address_table.version = -1;
1959       wccp_wccp_address_table.table_length = 0;
1960       wccp_wccp_address_table.table_ipv4 = (guint32 *) NULL;
1961       wccp_wccp_address_table.table_ipv6 = (struct e_in6_addr *)NULL;
1962
1963       /* ABORT The decode */
1964       return length - address_length;
1965     }
1966
1967     switch (wccp_wccp_address_table.family) {
1968     case 1:
1969       /* IPv4 */
1970       addr  =  tvb_ip_to_str(tvb, offset);
1971       if (wccp_wccp_address_table.table_ipv4 != NULL)
1972         wccp_wccp_address_table.table_ipv4[i] = tvb_get_ntohl(tvb,offset);
1973       break;
1974     case 2:
1975       /* IPv6 */
1976       addr = tvb_ip6_to_str(tvb,offset);
1977       if (wccp_wccp_address_table.table_ipv6 != NULL)
1978         tvb_get_ipv6(tvb, offset, &(wccp_wccp_address_table.table_ipv6[i]));
1979       break;
1980     default:
1981       addr = wmem_strdup_printf(wmem_packet_scope(), "unknown family");
1982     };
1983
1984     if (element_tree) {
1985       proto_tree_add_string_format_value(element_tree, hf_address_table_element, tvb,
1986                                          offset, address_length, addr,
1987                                          "%d: %s", i+1, addr);
1988     }
1989     EAT(address_length);
1990   }
1991   return length;
1992 }
1993
1994
1995
1996
1997
1998 #define HASH_ASSIGNMENT_INFO_MIN_LEN (4+256)
1999
2000 /* part of 5.6.11 Alternate Assignment Component */
2001 static gint
2002 dissect_wccp2_hash_assignment_info(tvbuff_t *tvb, int offset, gint length,
2003                                    packet_info *pinfo, proto_tree *info_tree)
2004 {
2005   guint32 n_web_caches;
2006   guint i;
2007
2008   if (length < HASH_ASSIGNMENT_INFO_MIN_LEN)
2009     return length - ASSIGNMENT_INFO_MIN_LEN;
2010
2011   n_web_caches = tvb_get_ntohl(tvb, offset);
2012   proto_tree_add_uint(info_tree, hf_wc_view_wc_num, tvb, offset, 4, n_web_caches);
2013   EAT(4);
2014
2015   for (i = 0; i < n_web_caches; i++) {
2016     if (length < 4)
2017       return length - 4*(n_web_caches-i)-256;
2018
2019     proto_tree_add_text(info_tree, tvb, offset, 4,
2020                         "Web-Cache %d: IP address %s", i,
2021                         decode_wccp_encoded_address(tvb, offset, pinfo, info_tree));
2022     EAT(4);
2023   }
2024
2025   for (i = 0; i < 256; i += 4) {
2026     if (length < 4)
2027       return length - (256-i);
2028
2029     proto_tree_add_text(info_tree, tvb, offset, 4,
2030                         "Buckets %d - %d: %10s %10s %10s %10s",
2031                         i, i + 3,
2032                         assignment_bucket_name(tvb_get_guint8(tvb, offset)),
2033                         assignment_bucket_name(tvb_get_guint8(tvb, offset+1)),
2034                         assignment_bucket_name(tvb_get_guint8(tvb, offset+2)),
2035                         assignment_bucket_name(tvb_get_guint8(tvb, offset+3)));
2036     EAT(4);
2037   }
2038   return length;
2039 }
2040
2041 /* 5.3.3 Assignment Map Component */
2042 static gint dissect_wccp2_assignment_map(tvbuff_t *tvb, int offset,
2043                                          int length, packet_info *pinfo, proto_tree *info_tree)
2044 {
2045   gint new_length;
2046
2047   new_length=dissect_wccp2_mask_value_set_list(tvb, offset, length, pinfo, info_tree);
2048
2049   NOTE_EATEN_LENGTH(new_length);
2050
2051   return length;
2052 }
2053
2054
2055
2056 #define ALT_ASSIGNMENT_MAP_MIN_LEN  (4)
2057
2058 /* 5.3.4 Alternate Assignment Map Component */
2059 static gint
2060 dissect_wccp2r1_alt_assignment_map_info(tvbuff_t *tvb, int offset,
2061                                         int length, packet_info *pinfo, proto_tree *info_tree)
2062 {
2063   guint16 assignment_type;
2064   guint16 assignment_length;
2065   proto_item *tf=NULL;
2066
2067   if (length < ALT_ASSIGNMENT_MAP_MIN_LEN )
2068     return length - ALT_ASSIGNMENT_MAP_MIN_LEN ;
2069
2070
2071   assignment_type = tvb_get_ntohs(tvb, offset);
2072   proto_tree_add_item(info_tree, hf_alt_assignment_map_assignment_type, tvb, offset, 2, ENC_BIG_ENDIAN);
2073   EAT_AND_CHECK(2,2);
2074
2075   assignment_length = tvb_get_ntohs(tvb, offset);
2076   tf=proto_tree_add_item(info_tree, hf_alt_assignment_map_assignment_length, tvb, offset, 2, ENC_BIG_ENDIAN);
2077   EAT(2);
2078
2079   if (length < assignment_length)
2080     expert_add_info_format(pinfo, tf, &ei_wccp_assignment_length_bad,
2081                            "Assignment length is %d but only %d remain in the packet. Ignoring this for now",
2082                            assignment_length, length);
2083
2084   if (length > assignment_length)  {
2085     expert_add_info_format(pinfo, tf, &ei_wccp_assignment_length_bad,
2086                            "Assignment length is %d but %d remain in the packet. Assuming that the assignment length is wrong and setting it to %d.",
2087                            assignment_length, length, length);
2088     assignment_length = length;
2089   }
2090
2091   switch (assignment_type) {
2092   case WCCP2_HASH_ASSIGNMENT_TYPE:
2093     return dissect_wccp2_assignment_info(tvb, offset, assignment_length,
2094                                          pinfo, info_tree);
2095   case WCCP2_MASK_ASSIGNMENT_TYPE:
2096     return dissect_wccp2_mask_value_set_list(tvb, offset, assignment_length,
2097                                              pinfo, info_tree);
2098   case WCCP2r1_ALT_MASK_ASSIGNMENT_TYPE:
2099     return dissect_wccp2_alternate_mask_value_set_list(tvb, offset, assignment_length,
2100                                                        pinfo, info_tree);
2101   default:
2102     return length;
2103   }
2104 }
2105
2106
2107
2108
2109
2110 /* 6.6 Hash Assignment Data Element */
2111 static gint
2112 dissect_wccp2_hash_assignment_data_element(tvbuff_t *tvb, int offset, gint length,
2113                                            packet_info *pinfo _U_,
2114                                            proto_tree *info_tree)
2115
2116 {
2117   proto_item *bucket_item;
2118   proto_tree *bucket_tree;
2119   int i;
2120   guint8 bucket_info;
2121   int n;
2122
2123
2124   bucket_item = proto_tree_add_text(info_tree, tvb, offset, 8*4,
2125                                     "Hash Assignment Data");
2126   bucket_tree = proto_item_add_subtree(bucket_item, ett_hash_assignment_buckets);
2127
2128   for (i = 0, n = 0; i < 32; i++) {
2129     if (length == 0) {
2130       return -i-2-2;
2131     }
2132
2133     bucket_info = tvb_get_guint8(tvb, offset);
2134     n = wccp_bucket_info(bucket_info, bucket_tree, n, tvb, offset);
2135     EAT(1);
2136   }
2137
2138   if (length < 2){
2139     return -2-2;
2140   }
2141
2142   return dissect_wccp2_assignment_weight_and_status_element(tvb, offset, length, pinfo, info_tree);
2143 }
2144
2145 /* 6.7 Mask Assignment Data Element */
2146 static gint
2147 dissect_wccp2_mask_assignment_data_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
2148                                            proto_tree *info_tree)
2149
2150 {
2151   proto_item *mask_item;
2152   proto_tree *mask_tree;
2153   gint new_length,start;
2154
2155
2156   mask_item = proto_tree_add_text(info_tree, tvb, offset, 4,
2157                                   "Mask Assignment Data");
2158   mask_tree = proto_item_add_subtree(mask_item, ett_mask_assignment_data_element);
2159   start = offset;
2160
2161   new_length=dissect_wccp2_mask_value_set_list(tvb, offset, length, pinfo, mask_tree);
2162
2163   NOTE_EATEN_LENGTH(new_length);
2164
2165   if (length < 2)
2166     return length-4;
2167
2168   new_length =  dissect_wccp2_assignment_weight_and_status_element(tvb, offset, length, pinfo, info_tree);
2169   NOTE_EATEN_LENGTH(new_length);
2170
2171   proto_item_set_len(mask_item, offset-start);
2172   return length;
2173 }
2174
2175
2176 /* 5.7.5 Alternate Mask Assignment Data Element */
2177 static gint
2178 dissect_wccp2_alternate_mask_assignment_data_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
2179                                                      proto_tree *info_tree)
2180 {
2181   proto_item *mask_item;
2182   proto_tree *mask_tree;
2183
2184   mask_item = proto_tree_add_text(info_tree, tvb, offset, length,
2185                                   "Alternate Mask Assignment Data");
2186   mask_tree = proto_item_add_subtree(mask_item, ett_alternate_mask_assignment_data_element);
2187
2188   if (length < 4)
2189     return length-4;
2190
2191   if (length > 4)
2192     for (;length >4;)
2193       {
2194         gint new_length;
2195
2196         new_length=dissect_wccp2_alternate_mask_value_set_list(tvb, offset, length, pinfo, mask_tree);
2197
2198         NOTE_EATEN_LENGTH(new_length);
2199       }
2200
2201   if (length < 2)
2202     return -2;
2203
2204   return  dissect_wccp2_assignment_weight_and_status_element(tvb, offset, length, pinfo, info_tree);
2205 }
2206
2207
2208 /* 6.9 Assignment Weight and Status Data Element */
2209 static gint
2210 dissect_wccp2_assignment_weight_and_status_element(tvbuff_t *tvb, int offset, gint length,
2211                                                    packet_info *pinfo _U_,
2212                                                    proto_tree *info_tree)
2213
2214 {
2215   if (length < 4)
2216     return length - 4;
2217
2218
2219   proto_tree_add_item(info_tree, hf_assignment_weight, tvb, offset, 2, ENC_BIG_ENDIAN);
2220   EAT_AND_CHECK(2,2);
2221   proto_tree_add_item(info_tree, hf_assignment_status, tvb, offset, 2, ENC_BIG_ENDIAN);
2222   EAT(2);
2223   return length;
2224 }
2225
2226
2227 /* 6.10 Extended Assignment Data Element */
2228 static gint
2229 dissect_wccp2_extended_assignment_data_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo,
2230                                                proto_tree *info_tree)
2231 {
2232   proto_item *element_item, *header;
2233   proto_tree *item_tree;
2234
2235   guint type_of_assignment;
2236
2237   gint assignment_length;
2238
2239   if (length < 4)
2240     return length-4;
2241
2242
2243   header = proto_tree_add_text(info_tree, tvb, offset, length,
2244                                "Extended Assignment Data Element");
2245
2246   item_tree = proto_item_add_subtree(header, ett_extended_assigment_data_element);
2247
2248   type_of_assignment = tvb_get_ntohs(tvb, offset);
2249   proto_tree_add_item(item_tree, hf_extended_assignment_data_type, tvb, offset, 2, ENC_BIG_ENDIAN);
2250   EAT_AND_CHECK(2,2);
2251
2252   assignment_length = tvb_get_ntohs(tvb,offset);
2253   element_item = proto_tree_add_item(item_tree, hf_extended_assignment_data_length, tvb, offset, 2, ENC_BIG_ENDIAN);
2254   EAT(2);
2255
2256   if (length < assignment_length)
2257     expert_add_info_format(pinfo, element_item, &ei_wccp_assignment_length_bad,
2258                            "Assignment length is %d but only %d remain in the packet. Ignoring this for now",
2259                            assignment_length, length);
2260
2261   /* Now a common bug seems to be to set the assignment_length to the length -4
2262      check for this */
2263   if ((length > assignment_length) &&
2264       (length == (assignment_length + 4)))
2265     {
2266       expert_add_info_format(pinfo, element_item, &ei_wccp_assignment_length_bad,
2267                              "Assignment length is %d but %d remain in the packet. Assuming that this is wrong as this is only 4 bytes to small, proceding with the assumption it is %d",
2268                              assignment_length, length, length);
2269       assignment_length = length;
2270     }
2271
2272
2273   proto_item_set_len(header, assignment_length+4);
2274
2275   switch (type_of_assignment)
2276     {
2277     case WCCP2_HASH_ASSIGNMENT_TYPE:
2278       return dissect_wccp2_hash_assignment_data_element(tvb, offset, assignment_length,
2279                                                         pinfo, item_tree);
2280     case WCCP2_MASK_ASSIGNMENT_TYPE:
2281       return dissect_wccp2_mask_assignment_data_element(tvb, offset, assignment_length,
2282                                                         pinfo, item_tree);
2283     case WCCP2r1_ALT_MASK_ASSIGNMENT_TYPE:
2284       return dissect_wccp2_alternate_mask_assignment_data_element(tvb, offset, assignment_length,
2285                                                                   pinfo, item_tree);
2286     case WCCP2r1_ASSIGNMENT_WEIGHT_STATUS:
2287       return dissect_wccp2_assignment_weight_and_status_element(tvb, offset, assignment_length,
2288                                                                 pinfo, item_tree);
2289     }
2290   return length;
2291 }
2292
2293
2294
2295
2296
2297
2298 /* 6.11 Capability Element */
2299 static gint
2300 dissect_wccp2_capability_element(tvbuff_t *tvb, int offset, gint length,
2301                                  packet_info *pinfo, proto_tree *info_tree)
2302 {
2303   guint16 capability_type;
2304   guint16 capability_val_len;
2305   proto_item *te, *header, *tf;
2306   proto_tree *element_tree;
2307
2308   if (length < 4)
2309     return length - 4;
2310
2311
2312   capability_type = tvb_get_ntohs(tvb, offset);
2313   capability_val_len = tvb_get_ntohs(tvb, offset + 2);
2314   header = te = proto_tree_add_item(info_tree, hf_capability_element_type, tvb, offset, 2, ENC_BIG_ENDIAN);
2315
2316   proto_item_set_len(te, capability_val_len + 4);
2317   element_tree = proto_item_add_subtree(te, ett_capability_element);
2318
2319   tf = proto_tree_add_uint(element_tree, hf_capability_element_length, tvb, offset+2, 2, capability_val_len);
2320
2321   proto_tree_add_text(element_tree, tvb, offset, 2,
2322                       "Type: %s",
2323                       val_to_str(capability_type,
2324                                  capability_type_vals, "Unknown (0x%08X)"));
2325   if (capability_val_len < 4) {
2326     expert_add_info_format(pinfo, tf, &ei_wccp_capability_element_length,
2327                 "Value Length: %u (illegal, must be >= 4)", capability_val_len);
2328     return -length;
2329   }
2330
2331   if (length < (4+capability_val_len))
2332     return length - 4 - capability_val_len;
2333
2334   switch (capability_type) {
2335   case WCCP2_FORWARDING_METHOD:
2336     dissect_32_bit_capability_flags(tvb, offset,
2337                                     capability_val_len,
2338                                     ett_capability_forwarding_method,
2339                                     forwarding_method_flags, element_tree, header);
2340     break;
2341
2342   case WCCP2_ASSIGNMENT_METHOD:
2343     dissect_32_bit_capability_flags(tvb, offset,
2344                                     capability_val_len,
2345                                     ett_capability_assignment_method,
2346                                     assignment_method_flags, element_tree, header);
2347     break;
2348
2349   case WCCP2_PACKET_RETURN_METHOD:
2350     dissect_32_bit_capability_flags(tvb, offset,
2351                                     capability_val_len,
2352                                     ett_capability_return_method,
2353                                     packet_return_method_flags, element_tree, header);
2354     break;
2355
2356   case WCCP2_TRANSMIT_T:
2357     dissect_transmit_t_capability(tvb, te, offset,
2358                                   capability_val_len,
2359                                   ett_capability_transmit_t,element_tree);
2360     break;
2361
2362   case WCCP2_TIMER_SCALE:
2363     dissect_timer_scale_capability(tvb, offset,
2364                                    capability_val_len,
2365                                    ett_capability_timer_scale, element_tree);
2366     break;
2367   default:
2368     proto_tree_add_text(element_tree, tvb,
2369                         offset, capability_val_len,
2370                         "Value: %s",
2371                         tvb_bytes_to_ep_str(tvb, offset,
2372                                          capability_val_len));
2373     break;
2374   }
2375   return length - 4 - capability_val_len;
2376 }
2377
2378
2379 /* 6.13 Mask/Value Set List */
2380 static gint
2381 dissect_wccp2_mask_value_set_list(tvbuff_t *tvb, int offset,
2382                                   int length, packet_info *pinfo, proto_tree *info_tree)
2383 {
2384   guint num_of_elem;
2385   guint i;
2386   proto_item *te;
2387   proto_tree *element_tree;
2388   guint start;
2389
2390
2391   if (length < 4)
2392     return length - 4;
2393
2394   te = proto_tree_add_text(info_tree, tvb, offset, 4, "Mask/Value Set List");
2395   element_tree = proto_item_add_subtree(te, ett_mv_set_list);
2396   start = offset;
2397
2398
2399   num_of_elem = tvb_get_ntohl(tvb, offset);
2400   proto_tree_add_item(element_tree, hf_mask_value_set_list_num_elements,
2401                       tvb, offset, 4, ENC_BIG_ENDIAN);
2402   /*  proto_tree_add_uint(element_tree, , tvb, offset, 4, num_of_elem); */
2403   EAT(4);
2404
2405   for (i = 0; i < num_of_elem; i++)
2406     {
2407       gint new_length;
2408
2409       new_length=dissect_wccp2_mask_value_set_element(tvb, offset, length, i, pinfo, element_tree);
2410
2411       NOTE_EATEN_LENGTH(new_length);
2412     }
2413
2414   proto_item_set_len(te, offset-start);
2415   return length;
2416 }
2417
2418
2419
2420
2421
2422 /* 6.15 Mask Element */
2423 static gint
2424 dissect_wccp2_mask_element(tvbuff_t *tvb, int offset, gint length, packet_info *pinfo _U_, proto_tree *info_tree)
2425 {
2426   if (length < 2)
2427     return length-12;
2428
2429   proto_tree_add_item(info_tree, hf_mask_element_src_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
2430   EAT_AND_CHECK(4,4);
2431   proto_tree_add_item(info_tree, hf_mask_element_dest_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
2432
2433   EAT_AND_CHECK(4,2);
2434   proto_tree_add_item(info_tree, hf_mask_element_src_port, tvb, offset, 2, ENC_BIG_ENDIAN);
2435   EAT_AND_CHECK(2,2);
2436   proto_tree_add_item(info_tree, hf_mask_element_dest_port, tvb, offset, 2, ENC_BIG_ENDIAN);
2437   EAT(2);
2438
2439   return length;
2440 }
2441
2442
2443
2444
2445
2446
2447 /* 6.17 Alternate Mask/Value Set List */
2448 static gint dissect_wccp2_alternate_mask_value_set_list(tvbuff_t *tvb, int offset,
2449                                                         int length, packet_info *pinfo, proto_tree *info_tree)
2450 {
2451   proto_item *header;
2452   proto_tree *list_tree;
2453   guint num_of_val_elements;
2454   guint i;
2455
2456   if (length < 4)
2457     return length - 4;
2458
2459   header = proto_tree_add_text(info_tree, tvb, offset, length,
2460                                "Alternate Mask/Value Set List");
2461   list_tree = proto_item_add_subtree(header, ett_alternate_mask_value_set);
2462
2463   num_of_val_elements = tvb_get_ntohl(tvb, offset);
2464   proto_tree_add_uint(list_tree, hf_alt_assignment_mask_value_set_list_num_elements, tvb, offset, 4, num_of_val_elements);
2465   EAT(4);
2466
2467   for(i=0;i<num_of_val_elements;i++) {
2468     gint new_length;
2469
2470     new_length=dissect_wccp2_alternate_mask_value_set_element(tvb, offset, length, i, pinfo, list_tree);
2471
2472     NOTE_EATEN_LENGTH(new_length);
2473   }
2474   return length;
2475 }
2476
2477
2478 /* 6.18 Alternate Mask/Value Set Element */
2479 static gint
2480 dissect_wccp2_alternate_mask_value_set_element(tvbuff_t *tvb, int offset, gint length, guint el_index, packet_info *pinfo, proto_tree *info_tree)
2481 {
2482   proto_item *tl, *header;
2483   proto_tree *element_tree, *value_tree;
2484   guint number_of_elements;
2485   gint new_length, total_length;
2486   guint i;
2487
2488   header = proto_tree_add_text(info_tree, tvb, offset, 0,
2489                                "Alternate Mask/Value Set Element(%d)", el_index);
2490   element_tree = proto_item_add_subtree(header, ett_alternate_mask_value_set_element);
2491
2492   total_length = 0;
2493
2494   new_length=dissect_wccp2_mask_element(tvb,offset,length,pinfo,element_tree);
2495   total_length += length - new_length;
2496   NOTE_EATEN_LENGTH(new_length);
2497
2498   if (length < 4)
2499     return length - 4;
2500
2501   number_of_elements  = tvb_get_ntohl(tvb, offset);
2502   tl = proto_tree_add_uint(element_tree, hf_alt_assignment_mask_value_set_element_num_wc_value_elements, tvb, offset, 4, number_of_elements);
2503   value_tree = proto_item_add_subtree(tl, ett_alternate_mv_set_element_list);
2504   total_length += 4;
2505   EAT(4);
2506
2507   for (i=0; i < number_of_elements; i++) {
2508     new_length=dissect_wccp2_web_cache_value_element(tvb, offset, length, pinfo,  value_tree);
2509     total_length += length - new_length;
2510     NOTE_EATEN_LENGTH(new_length);
2511   }
2512   proto_item_set_len(header, total_length);
2513
2514   return length;
2515 }
2516
2517 /* 6.19 Web-Cache Value Element */
2518 static gint
2519 dissect_wccp2_web_cache_value_element(tvbuff_t *tvb, int offset, gint length,  packet_info *pinfo _U_, proto_tree *info_tree)
2520 {
2521   guint number_of_elements;
2522   proto_item *tl;
2523   proto_tree *element_tree;
2524   guint i;
2525
2526   if (length < 4)
2527     return length - 8;
2528
2529   tl = proto_tree_add_item(info_tree, hf_web_cache_value_element_wc_address, tvb, offset, 4, ENC_BIG_ENDIAN);
2530
2531   element_tree = proto_item_add_subtree(tl, ett_web_cache_value_element_list);
2532   EAT_AND_CHECK(4,4);
2533
2534   number_of_elements  = tvb_get_ntohl(tvb, offset);
2535   proto_tree_add_uint(element_tree, hf_web_cache_value_element_num_values, tvb, offset, 4, number_of_elements);
2536   EAT(4);
2537
2538   for (i=0; i < number_of_elements; i++) {
2539     if (length < 4)
2540       return length - 4*(number_of_elements-i);
2541
2542     proto_tree_add_text(element_tree, tvb, offset, 4,
2543                         "Value Sequence Number %d: %x",
2544                         i+1,
2545                         tvb_get_ntohl(tvb, offset));
2546     EAT(4);
2547   }
2548
2549   return length;
2550 }
2551
2552
2553 /* End of standard functions */
2554
2555
2556 static void
2557 dissect_32_bit_capability_flags(tvbuff_t *tvb, int curr_offset,
2558                                 guint16 capability_val_len, gint ett, const capability_flag *flags,
2559                                 proto_tree *element_tree, proto_item *header)
2560 {
2561   guint32 capability_val;
2562   proto_item *tm;
2563   proto_tree *method_tree;
2564   int i;
2565   gboolean first = TRUE;
2566
2567   capability_val = tvb_get_ntohl(tvb, curr_offset + 4);
2568   tm = proto_tree_add_uint(element_tree, hf_capability_info_value, tvb, curr_offset + 4, 4, capability_val);
2569
2570   DISSECTOR_ASSERT(capability_val_len == 4);
2571
2572   for (i = 0; flags[i].short_name != NULL; i++) {
2573     if (capability_val & flags[i].value) {
2574       if (first) {
2575         proto_item_append_text( tm, " (%s", flags[i].short_name);
2576         proto_item_append_text( header, " (%s", flags[i].short_name);
2577         first = FALSE;
2578       } else {
2579         proto_item_append_text( tm, ", %s", flags[i].short_name);
2580         proto_item_append_text( header, " (%s", flags[i].short_name);
2581       }
2582     }
2583   }
2584
2585   if (first == FALSE) {
2586     proto_item_append_text( tm, ")");
2587     proto_item_append_text( header, ")");
2588   }
2589
2590   method_tree = proto_item_add_subtree(tm, ett);
2591   for (i = 0; flags[i].phf != NULL; i++)
2592     proto_tree_add_item(method_tree, *(flags[i].phf), tvb, curr_offset+4, 4, ENC_BIG_ENDIAN);
2593 }
2594
2595
2596
2597 /* 6.11.4 Capability Type WCCP2_TRANSMIT_T */
2598 static void
2599 dissect_transmit_t_capability(tvbuff_t *tvb, proto_item *te, int curr_offset,
2600                               guint16 capability_val_len, gint ett, proto_tree *element_tree)
2601 {
2602   guint16 upper_limit, lower_limit;
2603   proto_item *tm;
2604   proto_tree *method_tree;
2605
2606   DISSECTOR_ASSERT(capability_val_len == 4);
2607
2608   upper_limit = tvb_get_ntohs(tvb, curr_offset);
2609   lower_limit = tvb_get_ntohs(tvb, curr_offset + 2);
2610
2611   if ( upper_limit == 0) {
2612     tm = proto_tree_add_text(element_tree, tvb, curr_offset, 2,
2613                              "Only accepting one value");
2614     method_tree = proto_item_add_subtree(tm, ett);
2615     proto_tree_add_text(method_tree, tvb, curr_offset, 2,
2616                         "Reserved, must be 0: %d", upper_limit);
2617
2618     proto_tree_add_item(method_tree, hf_capability_transmit_t , tvb, curr_offset+2, 2, ENC_BIG_ENDIAN);
2619     proto_item_append_text(te, " %d ms", lower_limit);
2620   } else {
2621     tm = proto_tree_add_text(element_tree, tvb, curr_offset, 2,
2622                              "Accepting a range");
2623     method_tree = proto_item_add_subtree(tm, ett);
2624     proto_tree_add_item(method_tree, hf_capability_transmit_t_upper_limit,
2625                         tvb, curr_offset, 2, ENC_BIG_ENDIAN);
2626
2627     proto_tree_add_item(method_tree, hf_capability_transmit_t_lower_limit,
2628                         tvb, curr_offset+2, 2, ENC_BIG_ENDIAN);
2629     proto_item_append_text(te, " < %d ms > %d ms", lower_limit, upper_limit);
2630   }
2631 }
2632
2633
2634 static void
2635 dissect_timer_scale_capability(tvbuff_t *tvb, int curr_offset,
2636                                guint16 capability_val_len, gint ett, proto_tree *element_tree)
2637 {
2638   guint8 a,c;
2639   proto_item *tm;
2640   proto_tree *method_tree;
2641
2642   DISSECTOR_ASSERT(capability_val_len == 4);
2643
2644   a = tvb_get_guint8(tvb, curr_offset);
2645   c = tvb_get_guint8(tvb, curr_offset+2);
2646
2647   if ( a == 0) {
2648     if ( c == 0) {
2649       tm = proto_tree_add_text(element_tree, tvb, curr_offset, 2,
2650                                "Only accepting one value");
2651
2652       method_tree = proto_item_add_subtree(tm, ett);
2653       proto_tree_add_text(method_tree, tvb, curr_offset, 1,
2654                           "Reserved, must be 0: %d", a);
2655
2656       proto_tree_add_item(method_tree, hf_capability_timer_scale_timeout_scale,
2657                           tvb, curr_offset+1, 1, ENC_BIG_ENDIAN);
2658       proto_tree_add_text(method_tree, tvb, curr_offset+2, 1,
2659                           "Reserved, must be 0: %d", c);
2660       proto_tree_add_item(method_tree, hf_capability_timer_scale_ra_timer_scale,
2661                           tvb, curr_offset+3, 1, ENC_BIG_ENDIAN);
2662     } else {
2663       proto_tree_add_text(element_tree, tvb, curr_offset, 1,
2664                                "Error A is 0, but C is not");
2665     }
2666   } else {
2667     if ( c == 0) {
2668       proto_tree_add_text(element_tree, tvb, curr_offset, 1,
2669                                "Error C is 0, but A is not");
2670     } else {
2671       tm = proto_tree_add_text(element_tree, tvb, curr_offset, 2,
2672                                "Accepting a range");
2673       method_tree = proto_item_add_subtree(tm, ett);
2674       proto_tree_add_item(method_tree, hf_capability_timer_scale_timeout_scale_upper_limit,
2675                           tvb, curr_offset, 1, ENC_BIG_ENDIAN);
2676
2677       proto_tree_add_item(method_tree, hf_capability_timer_scale_timeout_scale_lower_limit,
2678                           tvb, curr_offset+1, 1, ENC_BIG_ENDIAN);
2679       proto_tree_add_item(method_tree, hf_capability_timer_scale_ra_scale_upper_limit,
2680                           tvb, curr_offset+2, 1, ENC_BIG_ENDIAN);
2681       proto_tree_add_item(method_tree, hf_capability_timer_scale_ra_scale_lower_limit,
2682                           tvb, curr_offset+3, 1, ENC_BIG_ENDIAN);
2683     }
2684   }
2685 }
2686
2687
2688 /* 6.16 Value Element */
2689 static gint
2690 dissect_wccp2_value_element(tvbuff_t *tvb, int offset, gint length, int idx, packet_info *pinfo, proto_tree *info_tree)
2691 {
2692   proto_item *tl;
2693   proto_tree *element_tree;
2694
2695   if (length < 4)
2696     return length - 16;
2697
2698   tl = proto_tree_add_text(info_tree, tvb, offset, 16, "Value Element(%u) %s",
2699                            idx,decode_wccp_encoded_address(tvb, offset+4+4+2+2, pinfo, info_tree));
2700   element_tree = proto_item_add_subtree(tl, ett_value_element);
2701
2702   proto_tree_add_item(element_tree, hf_value_element_src_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
2703   EAT_AND_CHECK(4,4);
2704   proto_tree_add_item(element_tree, hf_value_element_dest_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
2705
2706   EAT_AND_CHECK(4,2);
2707   proto_tree_add_item(element_tree, hf_value_element_src_port, tvb, offset, 2, ENC_BIG_ENDIAN);
2708   EAT_AND_CHECK(2,2);
2709   proto_tree_add_item(element_tree, hf_value_element_dest_port, tvb, offset, 2, ENC_BIG_ENDIAN);
2710   EAT_AND_CHECK(2,4);
2711
2712   proto_tree_add_item(element_tree, hf_value_element_web_cache_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
2713   EAT(4);
2714
2715   return length;
2716 }
2717
2718
2719 /* 6.14 Mask/Value Set Element */
2720 static gint
2721 dissect_wccp2_mask_value_set_element(tvbuff_t *tvb, int offset, gint length, int idx, packet_info *pinfo, proto_tree *info_tree)
2722 {
2723   proto_item *tl, *te;
2724   proto_tree *element_tree, *value_tree;
2725   guint num_of_val_elements;
2726   guint i;
2727   gint new_length;
2728
2729   tl = proto_tree_add_text(info_tree, tvb, offset, 0,
2730                            "Mask/Value Set Element(%d)", idx);
2731   element_tree = proto_item_add_subtree(tl, ett_mv_set_element);
2732
2733   new_length = dissect_wccp2_mask_element(tvb,offset,length,pinfo,element_tree);
2734   NOTE_EATEN_LENGTH(new_length);
2735
2736   if (length < 4)
2737     return length-4;
2738
2739   num_of_val_elements = tvb_get_ntohl(tvb, offset);
2740   te = proto_tree_add_uint(element_tree, hf_mask_value_set_element_value_element_num, tvb, offset, 4, num_of_val_elements);
2741
2742   value_tree = proto_item_add_subtree(te, ett_mv_set_value_list);
2743   EAT(4);
2744
2745   for (i = 0; i < num_of_val_elements; i++)
2746     {
2747       new_length=dissect_wccp2_value_element(tvb, offset, length, i, pinfo,  value_tree);
2748
2749       NOTE_EATEN_LENGTH(new_length);
2750     }
2751
2752   proto_item_set_len(tl, 16+num_of_val_elements*16);
2753
2754   return length;
2755 }
2756
2757 #define ALT_ASSIGNMENT_INFO_MIN_LEN    (4+4)
2758
2759 /* 5.4.2 Alternate Assignment Component */
2760 static gint
2761 dissect_wccp2_alternate_assignment_info(tvbuff_t *tvb, int offset, gint length,
2762                                         packet_info *pinfo, proto_tree *info_tree)
2763 {
2764   guint16 assignment_type;
2765   guint16 assignment_length;
2766   proto_item *tf=NULL;
2767
2768   guint32 n_routers;
2769   guint i;
2770   proto_item *te;
2771   proto_tree *element_tree;
2772   gint new_length;
2773
2774
2775   if (length < ALT_ASSIGNMENT_INFO_MIN_LEN)
2776     return length - ALT_ASSIGNMENT_INFO_MIN_LEN;
2777
2778
2779   assignment_type = tvb_get_ntohs(tvb, offset);
2780   proto_tree_add_item(info_tree, hf_alt_assignment_info_assignment_type, tvb, offset, 2, ENC_BIG_ENDIAN);
2781   EAT_AND_CHECK(2,2);
2782
2783   assignment_length = tvb_get_ntohs(tvb, offset);
2784   tf=proto_tree_add_item(info_tree, hf_alt_assignment_info_assignment_length, tvb, offset, 2, ENC_BIG_ENDIAN);
2785   EAT(2);
2786
2787   if (length < assignment_length)
2788     expert_add_info_format(pinfo, tf, &ei_wccp_assignment_length_bad,
2789                            "Assignment length is %d but only %d remain in the packet. Ignoring this for now",
2790                            assignment_length, length);
2791
2792   if (length > assignment_length)  {
2793     expert_add_info_format(pinfo, tf, &ei_wccp_assignment_length_bad,
2794                            "Assignment length is %d but %d remain in the packet. Assuming that the assignment length is wrong and setting it to %d.",
2795                            assignment_length, length, length);
2796   }
2797
2798   new_length=dissect_wccp2_assignment_key_element(tvb, offset, length, pinfo,  info_tree);
2799   NOTE_EATEN_LENGTH(new_length);
2800
2801   n_routers = tvb_get_ntohl(tvb, offset);
2802   proto_tree_add_uint(info_tree, hf_alt_assignment_info_num_routers, tvb, offset, 4, n_routers);
2803   EAT(4);
2804
2805   for (i = 0; i < n_routers; i++) {
2806     if (length < 12)
2807       return length - 12*(n_routers-i);
2808
2809     te = proto_tree_add_text(info_tree, tvb, offset, 12,
2810                              "Router %d Assignment Element: IP address %s", i,
2811                              decode_wccp_encoded_address(tvb, offset, pinfo, info_tree));
2812
2813     element_tree = proto_item_add_subtree(te, ett_router_alt_assignment_element);
2814     dissect_wccp2_router_assignment_element(tvb, offset, length , pinfo, element_tree);
2815     EAT(12);
2816   }
2817
2818   switch (assignment_type) {
2819   case WCCP2_HASH_ASSIGNMENT_TYPE:
2820     return dissect_wccp2_hash_assignment_info(tvb, offset, length,
2821                                               pinfo, info_tree);
2822   case WCCP2_MASK_ASSIGNMENT_TYPE:
2823     return dissect_wccp2_mask_value_set_list(tvb, offset, length,
2824                                              pinfo, info_tree);
2825   case WCCP2r1_ALT_MASK_ASSIGNMENT_TYPE:
2826     return dissect_wccp2_alternate_mask_value_set_list(tvb, offset, length,
2827                                                        pinfo, info_tree);
2828   default:
2829     return length;
2830   }
2831 }
2832
2833
2834
2835
2836 /* End of utility functions */
2837
2838 void
2839 proto_register_wccp(void)
2840 {
2841   static hf_register_info hf[] = {
2842     { &hf_wccp_message_type,
2843       { "WCCP Message Type", "wccp.message", FT_UINT32, BASE_DEC, VALS(wccp_type_vals), 0x0,
2844         "The WCCP message that was sent", HFILL }
2845     },
2846     { &hf_wccp_version,
2847       { "WCCP Version", "wccp.version", FT_UINT32, BASE_HEX, VALS(wccp_version_val), 0x0,
2848         "The WCCP version", HFILL }
2849     },
2850     { &hf_message_header_version,
2851       { "WCCP Version (>=2)", "wccp.message_header_version", FT_UINT16, BASE_HEX, NULL, 0x0,
2852         "The WCCP version for version 2 and above", HFILL }
2853     },
2854     { &hf_hash_revision,
2855       { "Hash Revision", "wccp.hash_revision", FT_UINT32, BASE_DEC, 0x0, 0x0,
2856         "The cache hash revision", HFILL }
2857     },
2858     { &hf_change_num,
2859       { "Change Number", "wccp.change_num", FT_UINT32, BASE_DEC, 0x0, 0x0,
2860         "The Web-Cache list entry change number", HFILL }
2861     },
2862     { &hf_hash_flag,
2863       { "Flags", "wccp.hash_flag", FT_UINT32, BASE_HEX, 0x0, 0x0,
2864         NULL, HFILL }
2865     },
2866     { &hf_hash_flag_u,
2867       { "Hash information", "wccp.hash_flag.u", FT_BOOLEAN, 32, TFS(&tfs_historical_current), 0x10000,
2868         NULL, HFILL }
2869     },
2870     { &hf_recvd_id,
2871       { "Received ID", "wccp.recvd_id", FT_UINT32, BASE_DEC, 0x0, 0x0,
2872         "The number of I_SEE_YOU's that have been sent", HFILL }
2873     },
2874     { &hf_cache_ip,
2875       { "Web Cache IP address", "wccp.cache_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
2876         "The IP address of a Web cache", HFILL }
2877     },
2878     { &hf_wc_num,
2879       { "Number of Web Caches", "wccp.wc_num", FT_UINT32, BASE_DEC, 0x0, 0x0,
2880         NULL, HFILL }
2881     },
2882     { &hf_message_header_length,
2883       { "Length", "wccp.message_header_length", FT_UINT16, BASE_DEC, 0x0, 0x0,
2884         NULL, HFILL }
2885     },
2886     { &hf_item_length,
2887       { "Length", "wccp.item_length", FT_UINT16, BASE_DEC, 0x0, 0x0,
2888         "The Length ofthe WCCPv2 item", HFILL }
2889     },
2890     { &hf_item_type,
2891       { "Type", "wccp.item_type", FT_UINT16, BASE_DEC, VALS(info_type_vals), 0x0,
2892         "The type of the WCCPv2 item", HFILL }
2893     },
2894     { &hf_item_data,
2895       { "Data", "wccp.item_data", FT_BYTES, BASE_NONE, 0x0, 0x0,
2896         "The data for an unknown item type", HFILL }
2897     },
2898     { &hf_security_info_option,
2899       { "Security Option", "wccp.security_info_option", FT_UINT16, BASE_DEC, VALS(security_option_vals), 0x0,
2900         NULL, HFILL }
2901     },
2902     { &hf_security_info_md5_checksum,
2903       { "MD5 checksum (not checked)", "wccp.security_md5_checksum", FT_BYTES, BASE_NONE, 0x0, 0x0,
2904         NULL, HFILL }
2905     },
2906     { &hf_command_element_type,
2907       {"Command Extension Type", "wccp.command_element_type", FT_UINT16, BASE_DEC, VALS(wccp_command_type_vals), 0x0,
2908        NULL, HFILL }
2909     },
2910     { &hf_command_element_length,
2911       {"Command Extension Length", "wccp.command_element_length", FT_UINT16, BASE_DEC, NULL, 0x0,
2912        NULL, HFILL }
2913     },
2914     { &hf_command_element_shutdown_ip,
2915       {"Command Extension Length", "wccp.command_element_shudown_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
2916        NULL, HFILL }
2917     },
2918     { &hf_service_info_type,
2919       { "Service Type", "wccp.service_info_type", FT_UINT8, BASE_DEC, VALS(service_type_vals), 0x0,
2920         NULL, HFILL }
2921     },
2922     { &hf_service_info_id_standard,
2923       { "WCCP Service ID (Standard)", "wccp.service_info_std_id", FT_UINT8, BASE_DEC, VALS(service_id_vals) , 0x0,
2924         "The WCCP Service id (Standard)", HFILL }
2925     },
2926     { &hf_service_info_id_dynamic,
2927       { "WCCP Service ID ( Dynamic)", "wccp.service_info_dyn_id", FT_UINT8, BASE_DEC, NULL , 0x0,
2928         "The WCCP Service id (Dynamic)", HFILL }
2929     },
2930     { &hf_service_info_priority,
2931       { "Priority (highest is 255)", "wccp.service_info_priority", FT_UINT8, BASE_DEC, NULL, 0x0,
2932         NULL, HFILL }
2933     },
2934     { &hf_service_info_protocol,
2935       { "Protocol", "wccp.service_info_protocol", FT_UINT8, BASE_DEC | BASE_EXT_STRING, &ipproto_val_ext, 0x0,
2936         NULL, HFILL }
2937     },
2938     { &hf_service_info_flags,
2939       { "Flags", "wccp.service_info_flags", FT_UINT32, BASE_HEX, 0x0, 0x0,
2940         NULL, HFILL }
2941     },
2942     { &hf_service_info_flags_src_ip_hash,
2943       { "Source IP address in primary hash", "wccp.service_info_flag.src_ip_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_SRC_IP_HASH,
2944         NULL, HFILL }
2945     },
2946     { &hf_service_info_flags_dest_ip_hash,
2947       { "Destination IP address in primary hash", "wccp.service_info_flag.dest_ip_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_DST_IP_HASH,
2948         NULL, HFILL }
2949     },
2950     { &hf_service_info_flags_src_port_hash,
2951       { "Source port in primary hash", "wccp.service_info_flag.src_port_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_SRC_PORT_HASH,
2952         NULL, HFILL }
2953     },
2954     { &hf_service_info_flags_dest_port_hash,
2955       { "Destination port in primary hash", "wccp.service_info_flag.dest_port_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_DST_PORT_HASH,
2956         NULL, HFILL }
2957     },
2958     { &hf_service_info_flags_ports_defined,
2959       { "Ports", "wccp.service_info_flag.ports_defined", FT_BOOLEAN, 32, TFS(&tfs_defined_not_defined), WCCP2_SI_PORTS_DEFINED,
2960         NULL, HFILL }
2961     },
2962     { &hf_service_info_flags_ports_source,
2963       { "Ports refer to", "wccp.service_info_flag.ports_source", FT_BOOLEAN, 32, TFS(&tfs_src_dest_port), WCCP2_SI_PORTS_SOURCE,
2964         NULL, HFILL }
2965     },
2966     { &hf_service_info_flags_redirect_only_protocol_0,
2967       { "Redirect only protocol 0", "wccp.service_info_flag.redirect_only_protocol_0", FT_BOOLEAN, 32, TFS(&tfs_redirect_protocol0), WCCP2r1_SI_REDIRECT_ONLY_PROTOCOL_0,
2968         NULL, HFILL }
2969     },
2970     { &hf_service_info_flags_src_ip_alt_hash,
2971       { "Source IP address in secondary hash", "wccp.service_info_flag.src_ip_alt_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_SRC_IP_ALT_HASH,
2972         NULL, HFILL }
2973     },
2974     { &hf_service_info_flags_dest_ip_alt_hash,
2975       { "Destination IP address in secondary hash", "wccp.service_info_flag.dest_ip_alt_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_DST_IP_ALT_HASH,
2976         NULL, HFILL }
2977     },
2978     { &hf_service_info_flags_src_port_alt_hash,
2979       { "Source port in secondary hash", "wccp.service_info_flag.src_port_alt_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_SRC_PORT_ALT_HASH,
2980         NULL, HFILL }
2981     },
2982     { &hf_service_info_flags_dest_port_alt_hash,
2983       { "Destination port in secondary hash", "wccp.service_info_flag.dest_port_alt_hash", FT_BOOLEAN, 32, TFS(&tfs_used_notused), WCCP2_SI_DST_PORT_ALT_HASH,
2984         NULL, HFILL }
2985     },
2986     { &hf_service_info_source_port,
2987       { "Source Port", "wccp.service_info_source_port", FT_UINT16, BASE_DEC, NULL, 0x0,
2988         NULL, HFILL }
2989     },
2990     { &hf_service_info_destination_port,
2991       { "Destination Port", "wccp.service_info_destination_port", FT_UINT16, BASE_DEC, NULL, 0x0,
2992         NULL, HFILL }
2993     },
2994     { &hf_router_identity_ip,
2995       { "IP Address", "wccp.router_identity.ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
2996         NULL, HFILL }
2997     },
2998     { &hf_router_identity_receive_id,
2999       { "Received ID", "wccp.router_identity.receive_id", FT_UINT32, BASE_DEC, 0x0, 0x0,
3000         NULL, HFILL }
3001     },
3002     { &hf_router_identity_send_to_ip,
3003       { "Sent To IP Address", "wccp.router_identity.send_to_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3004         NULL, HFILL }
3005     },
3006     { &hf_router_identity_received_from_num,
3007       { "Number of Received From IP addresses (Webcache to which the message is directed)", "wccp.router.num_recv_ip", FT_UINT32, BASE_DEC, 0x0, 0x0,
3008         NULL, HFILL }
3009     },
3010     { &hf_web_cache_identity_ip,
3011       { "Web-Cache IP Address", "wccp.web_cache_identity.ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3012         NULL, HFILL }
3013     },
3014     { &hf_web_cache_identity_hash_rev,
3015       { "Hash Revision", "wccp.web_cache_identity.hash_rev", FT_UINT16, BASE_DEC, NULL, 0x0,
3016         NULL, HFILL }
3017     },
3018     { &hf_web_cache_identity_flags,
3019       { "Flags", "wccp.web_cache_identity.flags", FT_UINT16, BASE_HEX, NULL, 0x0,
3020         NULL, HFILL }
3021     },
3022     { &hf_web_cache_identity_flag_hash_info,
3023       { "Hash information", "wccp.web_cache_identity.flags.hash_info", FT_BOOLEAN, 16,
3024         TFS(&tfs_historical_current), 0x1,
3025         NULL, HFILL }
3026     },
3027     { &hf_web_cache_identity_flag_assign_type,
3028       { "Assignment Type", "wccp.web_cache_identity.flags.assign_type", FT_UINT16, BASE_HEX,
3029         VALS(&wccp_web_cache_assignment_data_type_val), 0x6,
3030         NULL, HFILL }
3031     },
3032     { &hf_web_cache_identity_flag_version_request,
3033       { "Version Request", "wccp.web_cache_identity.flags.version_request", FT_BOOLEAN, 16,
3034         TFS(&tfs_version_min_max), 0x8,
3035         NULL, HFILL }
3036     },
3037     { &hf_mask_value_set_element_value_element_num,
3038       { "Number of Value Elements", "wccp.mask_value_set_selement.value_element_num", FT_UINT32, BASE_DEC, 0x0, 0x0,
3039         NULL, HFILL }
3040     },
3041     { &hf_assignment_weight,
3042       { "Assignment Weight", "wccp.assignment_weight", FT_UINT16, BASE_DEC, NULL, 0x0,
3043         NULL, HFILL }
3044     },
3045     { &hf_assignment_status,
3046       { "Status", "wccp.assignment_status", FT_UINT16, BASE_HEX, NULL, 0x0,
3047         NULL, HFILL }
3048     },
3049     { &hf_assignment_key_ip,
3050       { "Assignment Key IP Address", "wccp.assignment_key.ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3051         NULL, HFILL }
3052     },
3053     { &hf_assignment_key_change_num,
3054       { "Assignment Key Change Number", "wccp.assignment_key.change_num", FT_UINT32, BASE_DEC, NULL, 0x0,
3055         NULL, HFILL }
3056     },
3057     { &hf_router_view_member_change_num,
3058       { "Member Change Number", "wccp.router_view.member_change_num", FT_UINT32, BASE_DEC, NULL, 0x0,
3059         NULL, HFILL }
3060     },
3061     { &hf_router_router_num,
3062       { "Number of Routers", "wccp.router_view.router_num", FT_UINT32, BASE_DEC, NULL, 0x0,
3063         NULL, HFILL }
3064     },
3065     { &hf_router_identity_router_ip,
3066       { "Router IP Address", "wccp.router_identity.router_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3067         NULL, HFILL }
3068     },
3069     { &hf_router_identity_received_from_ip,
3070       { "Received From IP Address/Target Web Cache IP", "wccp.router_identity.received_from_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3071         NULL, HFILL }
3072     },
3073     { &hf_wc_view_info_change_num,
3074       { "Change Number", "wccp.wc_view_info.change_num", FT_UINT32, BASE_DEC, NULL, 0x0,
3075         NULL, HFILL }
3076     },
3077     { &hf_wc_view_info_router_ip,
3078       { "Router IP", "wccp.wc_view_info.router_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3079         NULL, HFILL }
3080     },
3081     { &hf_wc_view_info_wc_ip,
3082       { "Web Cache IP", "wccp.wc_view_info.wc_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3083         NULL, HFILL }
3084     },
3085     { &hf_wc_view_router_num,
3086       { "Number of Routers", "wccp.wc_view_info.router_num", FT_UINT32, BASE_DEC, NULL, 0x0,
3087         NULL, HFILL }
3088     },
3089     { &hf_wc_view_wc_num,
3090       { "Number of Web Caches", "wccp.wc_view_info.wc_num", FT_UINT32, BASE_DEC, 0x0, 0x0,
3091         NULL, HFILL }
3092     },
3093     { &hf_wc_identity_ip_address,
3094       { "Web Cache Identity", "wccp.hf_wc_identity_ip_address", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3095         "The IP identifying the Web Cache", HFILL }
3096     },
3097     { &hf_router_assignment_element_change_num,
3098       { "Change Number", "wccp.router_assignment_element.change_num", FT_UINT32, BASE_DEC, NULL, 0x0,
3099         NULL, HFILL }
3100     },
3101     { &hf_assignment_info_router_num,
3102       { "Number of Routers", "wccp.assignment_info.router_num", FT_UINT32, BASE_DEC, NULL, 0x0,
3103         NULL, HFILL }
3104     },
3105     { &hf_assignment_info_router_ip,
3106       { "Router IP", "wccp.assignment_info.router_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3107         NULL, HFILL }
3108     },
3109     { &hf_hash_buckets_assignment_wc_num,
3110       { "Number of WC", "wccp.hash_buckets_assignment.wc_num", FT_UINT32, BASE_DEC, NULL, 0x0,
3111         NULL, HFILL }
3112     },
3113     { &hf_hash_buckets_assignment_wc_ip,
3114       { "WC IP", "wccp.hash_buckets_assignment.wc_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3115         NULL, HFILL }
3116     },
3117     { &hf_router_view_ip,
3118       { "Router IP Address", "wccp.router_view.ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3119         NULL, HFILL }
3120     },
3121     { &hf_router_query_info_ip,
3122       { "Web-Cache Identity Element IP address", "wccp.router_query_info.ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3123         NULL, HFILL }
3124     },
3125     { &hf_router_query_info_send_to_ip,
3126       { "Sent To IP Address", "wccp.router_query_info.send_to_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3127         NULL, HFILL }
3128     },
3129     { &hf_router_query_info_target_ip,
3130       { "Target IP Address", "wccp.router_query_info.target_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3131         NULL, HFILL }
3132     },
3133     { &hf_capability_element_type,
3134       { "Type", "wccp.capability_element.type", FT_UINT16, BASE_DEC, VALS(capability_type_vals), 0x0,
3135         NULL, HFILL }
3136     },
3137     { &hf_capability_element_length,
3138       { "Value Length", "wccp.capability_element.length", FT_UINT16, BASE_DEC, NULL, 0x0,
3139         NULL, HFILL }
3140     },
3141     { &hf_capability_info_value,
3142       { "Value", "wccp.capability_info.value", FT_UINT32, BASE_HEX, NULL, 0x0,
3143         NULL, HFILL }
3144     },
3145     { &hf_capability_forwarding_method_flag_gre,
3146       { "GRE-encapsulated", "wccp.capability_info.forwarding_method_flag.gre", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_FORWARDING_METHOD_GRE,
3147         NULL, HFILL }
3148     },
3149     { &hf_capability_forwarding_method_flag_l2,
3150       { "L2 rewrite", "wccp.capability_info.forwarding_method_flag.l2", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_FORWARDING_METHOD_L2,
3151         NULL, HFILL }
3152     },
3153     { &hf_capability_assignment_method_flag_hash,
3154       { "Hash", "wccp.capability_info.assignment_method_flag.hash", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_ASSIGNMENT_METHOD_HASH,
3155         NULL, HFILL }
3156     },
3157     { &hf_capability_assignment_method_flag_mask,
3158       { "Mask", "wccp.capability_info.assignment_method_flag.mask", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_ASSIGNMENT_METHOD_MASK,
3159         NULL, HFILL }
3160     },
3161     { &hf_capability_return_method_flag_gre,
3162       { "GRE-encapsulated", "wccp.capability_info.return_method_flag.gre", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_PACKET_RETURN_METHOD_GRE,
3163         NULL, HFILL }
3164     },
3165     { &hf_capability_return_method_flag_l2,
3166       { "L2 rewrite", "wccp.capability_info.return_method_flag.l2", FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), WCCP2_PACKET_RETURN_METHOD_L2,
3167         NULL, HFILL }
3168     },
3169     { &hf_capability_transmit_t,
3170       { "Message interval in milliseconds", "wccp.capability.transmit_t", FT_UINT16, BASE_DEC, NULL, 0x0,
3171         NULL, HFILL }
3172     },
3173     { &hf_capability_transmit_t_upper_limit,
3174       { "Message interval upper limit in milliseconds", "wccp.capability.transmit_t.upper_limit", FT_UINT16, BASE_DEC, NULL, 0x0,
3175         NULL, HFILL }
3176     },
3177     { &hf_capability_transmit_t_lower_limit,
3178       { "Message interval lower limit in milliseconds", "wccp.capability.transmit_t.upper_limit", FT_UINT16, BASE_DEC, NULL, 0x0,
3179         NULL, HFILL }
3180     },
3181     { &hf_capability_timer_scale_timeout_scale,
3182       { "Timer scale", "wccp.capability.timer_scale.timeout_scale", FT_UINT8, BASE_DEC, NULL, 0x0,
3183         NULL, HFILL }
3184     },
3185     { &hf_capability_timer_scale_timeout_scale_upper_limit,
3186       { "Timer scale upper limit", "wccp.capability.timer_scale.timeout_scale.upper_limit", FT_UINT8, BASE_DEC, NULL, 0x0,
3187         NULL, HFILL }
3188     },
3189     { &hf_capability_timer_scale_timeout_scale_lower_limit,
3190       { "Timer scale lower limit", "wccp.capability.timer_scale.timeout_scale.lower_limit", FT_UINT8, BASE_DEC, NULL, 0x0,
3191         NULL, HFILL }
3192     },
3193     { &hf_capability_timer_scale_ra_timer_scale,
3194       { "RA Timer scale", "wccp.capability.timer_scale.ra_timer_scale", FT_UINT8, BASE_DEC, NULL, 0x0,
3195         NULL, HFILL }
3196     },
3197     { &hf_capability_timer_scale_ra_scale_upper_limit,
3198       { "RA Timer scale upper limit", "wccp.capability.timer_scale.ra_timer_scale.upper_limit", FT_UINT8, BASE_DEC, NULL, 0x0,
3199         NULL, HFILL }
3200     },
3201     { &hf_capability_timer_scale_ra_scale_lower_limit,
3202       { "RA Timer scale lower limit", "wccp.capability.timer_scale.ra_timer_scale.lower_limit", FT_UINT8, BASE_DEC, NULL, 0x0,
3203         NULL, HFILL }
3204     },
3205     { &hf_value_element_src_ip,
3206       { "Source Address", "wccp.value_element.src_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3207         NULL, HFILL }
3208     },
3209     { &hf_value_element_dest_ip,
3210       { "Destination Address", "wccp.value_element.dest_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3211         NULL, HFILL }
3212     },
3213     { &hf_value_element_src_port,
3214       { "Source Port", "wccp.value_element.src_port", FT_UINT16, BASE_DEC, NULL, 0x0,
3215         NULL, HFILL }
3216     },
3217     { &hf_value_element_dest_port,
3218       { "Destination Port", "wccp.value_element.dest_port", FT_UINT16, BASE_DEC, NULL, 0x0,
3219         NULL, HFILL }
3220     },
3221     { &hf_value_element_web_cache_ip,
3222       { "Web Cache Address", "wccp.value_element.web_cache_ip", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3223         NULL, HFILL }
3224     },
3225     { &hf_mask_value_set_list_num_elements,
3226       { "Number of elements", "wccp.mask_value_set_list.num_elements", FT_UINT32, BASE_DEC, NULL, 0x0,
3227         NULL, HFILL }
3228     },
3229     { &hf_mask_element_src_ip,
3230       { "Source Address Mask", "wccp.mask_element.src_ip", FT_UINT32, BASE_HEX, NULL, 0x0,
3231         NULL, HFILL }
3232     },
3233     { &hf_mask_element_dest_ip,
3234       { "Destination Address Mask", "wccp.mask_element.dest_ip", FT_UINT32, BASE_HEX, NULL, 0x0,
3235         NULL, HFILL }
3236     },
3237     { &hf_mask_element_src_port,
3238       { "Source Port Mask", "wccp.mask_element.src_port", FT_UINT16, BASE_HEX, NULL, 0x0,
3239         NULL, HFILL }
3240     },
3241     { &hf_mask_element_dest_port,
3242       { "Destination Port Mask", "wccp.mask_element.dest_port", FT_UINT16, BASE_HEX, NULL, 0x0,
3243         NULL, HFILL }
3244     },
3245     { &hf_alt_assignment_info_assignment_type,
3246       { "Assignment type", "wccp.alt_assignment_info.assignment_type", FT_UINT16, BASE_DEC, VALS(assignment_type_vals), 0x0,
3247         NULL, HFILL }
3248     },
3249     { &hf_extended_assignment_data_type,
3250       { "Assignment type", "wccp.extended_assignment_data.type", FT_UINT16, BASE_DEC, VALS(assignment_type_vals), 0x0,
3251         NULL, HFILL }
3252     },
3253     { &hf_alt_assignment_map_assignment_type,
3254       { "Assignment type", "wccp.alt_assignment_map.assignment_type", FT_UINT16, BASE_DEC, VALS(assignment_type_vals), 0x0,
3255         NULL, HFILL }
3256     },
3257     { &hf_alt_assignment_map_assignment_length,
3258       { "Assignment length", "wccp.alt_assignment_map.assignment_length", FT_UINT16, BASE_DEC, NULL, 0x0,
3259         NULL, HFILL }
3260     },
3261     { &hf_alt_assignment_info_assignment_length,
3262       { "Assignment length", "wccp.alt_assignment_info.assignment_length", FT_UINT16, BASE_DEC, NULL, 0x0,
3263         NULL, HFILL }
3264     },
3265     { &hf_extended_assignment_data_length,
3266       { "Assignment length", "wccp.extended_assignment_data.length", FT_UINT16, BASE_DEC, NULL, 0x0,
3267         NULL, HFILL }
3268     },
3269     { &hf_alt_assignment_info_num_routers,
3270       { "Number of routers", "wccp.alt_assignment_info.num_routers", FT_UINT32, BASE_DEC, NULL, 0x0,
3271         NULL, HFILL }
3272     },
3273     { &hf_alt_assignment_mask_value_set_element_num_wc_value_elements,
3274       { "Number of Web-Cache Value Elements", "wccp.alt_assignment_mask_value_set_element.num_wc_value_elements", FT_UINT32, BASE_DEC, NULL, 0x0,
3275         NULL, HFILL }
3276     },
3277     { &hf_web_cache_value_element_wc_address,
3278       { "Web-Cache Address", "wccp.web_cache_value_element.wc_address", FT_UINT32, BASE_CUSTOM, wccp_fmt_ipadddress, 0x0,
3279         NULL, HFILL }
3280     },
3281     { &hf_web_cache_value_element_num_values,
3282       { "Number of Valye Sequence Numbers", "wccp.web_cache_value_element.num_values", FT_UINT32, BASE_DEC, NULL, 0x0,
3283         NULL, HFILL }
3284     },
3285     { &hf_alt_assignment_mask_value_set_list_num_elements,
3286       { "Number of Alternate Mask/Value Set Elements", "wccp.alt_assignment_mask_value_list.num_elements", FT_UINT32, BASE_DEC, NULL, 0x0,
3287         NULL, HFILL }
3288     },
3289     { &hf_address_table_family,
3290       { "Family Type", "wccp.address_table.family_type", FT_UINT16, BASE_DEC, VALS(wccp_address_family_val), 0x0,
3291         "The WCCP Address Table Family type", HFILL }
3292     },
3293     { &hf_address_table_address_length,
3294       { "Address Length", "wccp.address_table.address_length", FT_UINT16, BASE_DEC, NULL, 0x0,
3295         "The WCCP Address Table Address Length", HFILL }
3296     },
3297     { &hf_address_table_length,
3298       { "Length", "wccp.address_table.length", FT_UINT16, BASE_DEC, NULL, 0x0,
3299         "The WCCP Address Table Length", HFILL }
3300     },
3301     { &hf_address_table_element,
3302       { "Address", "wccp.address_table.element", FT_STRING, BASE_NONE, NULL, 0x0,
3303         NULL, HFILL }
3304     },
3305
3306   };
3307   static gint *ett[] = {
3308     &ett_wccp,
3309     &ett_buckets,
3310     &ett_hash_assignment_buckets,
3311     &ett_mask_assignment_data_element,
3312     &ett_alternate_mask_assignment_data_element,
3313     &ett_extended_assigment_data_element,
3314     &ett_table_element,
3315     &ett_hash_flags,
3316     &ett_wc_identity_flags,
3317     &ett_cache_info,
3318     &ett_security_info,
3319     &ett_service_info,
3320     &ett_service_flags,
3321     &ett_service_info_ports,
3322     &ett_wc_view_info_router_element,
3323     &ett_router_identity_info,
3324     &ett_wc_identity_element,
3325     &ett_wc_identity_info,
3326     &ett_router_view_info,
3327     &ett_wc_view_info,
3328     &ett_query_info,
3329     &ett_router_assignment_element,
3330     &ett_hash_buckets_assignment_wc_element,
3331     &ett_hash_buckets_assignment_buckets,
3332     &ett_router_alt_assignment_element,
3333     &ett_router_assignment_info,
3334     &ett_capabilities_info,
3335     &ett_capability_element,
3336     &ett_capability_forwarding_method,
3337     &ett_capability_assignment_method,
3338     &ett_capability_return_method,
3339     &ett_capability_transmit_t,
3340     &ett_capability_timer_scale,
3341     &ett_mv_set_list,
3342     &ett_mv_set_element,
3343     &ett_mv_set_value_list,
3344     &ett_alternate_mv_set_element_list,
3345     &ett_web_cache_value_element_list,
3346     &ett_alternate_mv_set_element,
3347     &ett_value_element,
3348     &ett_alt_assignment_info,
3349     &ett_alt_assignment_map,
3350     &ett_assignment_map,
3351     &ett_address_table,
3352     &ett_unknown_info,
3353     &ett_alternate_mask_value_set,
3354     &ett_alternate_mask_value_set_element,
3355     &ett_command_extension,
3356   };
3357
3358   static ei_register_info ei[] = {
3359      { &ei_wccp_missing_security_info, { "wccp.missing.security_info", PI_PROTOCOL, PI_ERROR, "This message should contain a Security Info component, but it is missing", EXPFILL }},
3360      { &ei_wccp_missing_service_info, { "wccp.missing.service_info", PI_PROTOCOL, PI_ERROR, "This message should contain a Service Info component, but it is missing", EXPFILL }},
3361      { &ei_wccp_missing_wc_id_info, { "wccp.missing.wc_id_info", PI_PROTOCOL, PI_ERROR, "This message should contain a Web-Cache Identity Info component, but it is missing", EXPFILL }},
3362      { &ei_wccp_missing_router_id_info, { "wccp.missing.router_id_info", PI_PROTOCOL, PI_ERROR, "This message should contain a Router Identity Info component, but it is missing", EXPFILL }},
3363      { &ei_wccp_missing_query_info, { "wccp.missing.query_info", PI_PROTOCOL, PI_ERROR, "This message should contain a Query Info component, but it is missing", EXPFILL }},
3364      { &ei_wccp_missing_wc_view_info, { "wccp.missing.wc_view_info", PI_PROTOCOL, PI_ERROR, "This message should contain a Web-Cache View Info component, but it is missing", EXPFILL }},
3365      { &ei_wccp_missing_rtr_view_info, { "wccp.missing.rtr_view_info", PI_PROTOCOL, PI_ERROR, "This message should contain a Router View Info component, but it is missing", EXPFILL }},
3366      { &ei_wccp_missing_assignment, { "wccp.missing.assignment", PI_PROTOCOL, PI_ERROR, "This message should contain a Alternate Assignment, Assignment Map, Assignment Info or "
3367                                       "Alternative Assignment Map component, but it is missing", EXPFILL }},
3368      { &ei_wccp_contains_redirect_assignment, { "wccp.contains.redirect_assignment", PI_PROTOCOL, PI_ERROR, "This message contains a Assignment Info component, but it should not", EXPFILL }},
3369      { &ei_wccp_contains_router_id_info, { "wccp.contains.router_id_info", PI_PROTOCOL, PI_ERROR, "This message contains a Router Identity Info component, but it should not", EXPFILL }},
3370      { &ei_wccp_contains_rtr_view_info, { "wccp.contains.rtr_view_info", PI_PROTOCOL, PI_ERROR, "This message contains a Router View Info component, but it should not", EXPFILL }},
3371      { &ei_wccp_contains_query_info, { "wccp.contains.query_info", PI_PROTOCOL, PI_ERROR, "This message contains a Query Info component, but it should not", EXPFILL }},
3372      { &ei_wccp_contains_alt_assignment, { "wccp.contains.alt_assignment", PI_PROTOCOL, PI_ERROR, "This message contains a Alternate Assignment component, but it should not", EXPFILL }},
3373      { &ei_wccp_contains_assign_map, { "wccp.contains.assign_map", PI_PROTOCOL, PI_ERROR, "This message contains a Assignment Map component, but it should not", EXPFILL }},
3374      { &ei_wccp_contains_alt_assignment_map, { "wccp.contains.alt_assignment_map", PI_PROTOCOL, PI_ERROR, "This message contains a Alternative Assignment Map component, but it should not", EXPFILL }},
3375      { &ei_wccp_contains_wc_id_info, { "wccp.contains.wc_id_info", PI_PROTOCOL, PI_ERROR, "This message contains a Web-Cache Identity Info component, but it should not", EXPFILL }},
3376      { &ei_wccp_contains_wc_view_info, { "wccp.contains.wc_view_info", PI_PROTOCOL, PI_ERROR, "This message contains a Web-Cache View Info component, but it should not", EXPFILL }},
3377      { &ei_wccp_contains_capabilities_info, { "wccp.contains.capabilities_info", PI_PROTOCOL, PI_ERROR, "This message contains a Capabilities Info component, but it should not", EXPFILL }},
3378      { &ei_wccp_contains_command_extension, { "wccp.contains.command_extension", PI_PROTOCOL, PI_ERROR, "This message contains a Command Extension component, but it should not", EXPFILL }},
3379      { &ei_wccp_assignment_length_bad, { "wccp.assignment_length_bad", PI_PROTOCOL, PI_ERROR, "Assignment length bad", EXPFILL }},
3380      { &ei_wccp_length_bad, { "wccp.length_bad", PI_PROTOCOL, PI_ERROR, "Length bad", EXPFILL }},
3381      { &ei_wccp_service_info_priority_nonzero, { "wccp.service_info_priority.nonzero", PI_PROTOCOL, PI_WARN, "The priority must be zero for well-known services.", EXPFILL }},
3382      { &ei_wccp_service_info_protocol_nonzero, { "wccp.service_info_protocol.nonzero", PI_PROTOCOL, PI_WARN, "The protocol must be zero for well-known services.", EXPFILL }},
3383      { &ei_wccp_router_identity_receive_id_zero, { "wccp.router_identity.receive_id.zero", PI_PROTOCOL, PI_WARN, "Receive ID shouldn't be 0", EXPFILL }},
3384      { &ei_wccp_web_cache_identity_hash_rev_zero, { "wccp.web_cache_identity.hash_rev.zero", PI_PROTOCOL, PI_WARN, "Should be 0 (6.4)", EXPFILL }},
3385      { &ei_wccp_address_table_family_unknown, { "wccp.address_table.family_type.unknown", PI_PROTOCOL, PI_ERROR, "Unknown address family", EXPFILL }},
3386      { &ei_wccp_capability_element_length, { "wccp.capability_element.length.invalid", PI_PROTOCOL, PI_WARN, "Value Length invalid", EXPFILL }},
3387   };
3388
3389   expert_module_t* expert_wccp;
3390
3391   proto_wccp = proto_register_protocol("Web Cache Communication Protocol",
3392                                        "WCCP", "wccp");
3393   proto_register_field_array(proto_wccp, hf, array_length(hf));
3394   proto_register_subtree_array(ett, array_length(ett));
3395   expert_wccp = expert_register_protocol(proto_wccp);
3396   expert_register_field_array(expert_wccp, ei, array_length(ei));
3397 }
3398
3399 void
3400 proto_reg_handoff_wccp(void)
3401 {
3402   dissector_handle_t wccp_handle;
3403
3404   wccp_handle = new_create_dissector_handle(dissect_wccp, proto_wccp);
3405   dissector_add_uint("udp.port", UDP_PORT_WCCP, wccp_handle);
3406 }
3407
3408 /*
3409  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
3410  *
3411  * Local variables:
3412  * c-basic-offset: 2
3413  * tab-width: 8
3414  * indent-tabs-mode: nil
3415  * End:
3416  *
3417  * vi: set shiftwidth=2 tabstop=8 expandtab:
3418  * :indentSize=2:tabSize=8:noTabs=true:
3419  */
3420