1 /* packet-enrp.c
2  * Routines for Endpoint Handlespace Redundancy Protocol (ENRP)
3  * It is hopefully (needs testing) compliant to
4  * RFC 5353
5  * RFC 5354
6  * RFC 5356
7  * https://tools.ietf.org/html/draft-dreibholz-rserpool-enrp-takeover-21
8  *
9  * Copyright 2008-2021 Thomas Dreibholz <dreibh [AT] iem.uni-due.de>
10  * Copyright 2004-2007 Michael Tüxen <tuexen [AT] fh-muenster.de>
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * Copied from README.developer
17  *
18  * SPDX-License-Identifier: GPL-2.0-or-later
19  */
20 
21 #include "config.h"
22 
23 #include <epan/packet.h>
24 #include <epan/to_str.h>
25 #include <epan/sctpppids.h>
26 #include <epan/stat_tap_ui.h>
27 
28 #include <wsutil/str_util.h>
29 
30 #include "packet-asap+enrp-common.h"
31 
32 void proto_register_enrp(void);
33 void proto_reg_handoff_enrp(void);
34 
35 /* Initialize the protocol and registered fields */
36 static int enrp_tap = -1;
37 static int proto_enrp = -1;
38 static int hf_cause_code = -1;
39 static int hf_cause_length = -1;
40 static int hf_cause_info = -1;
41 static int hf_cause_padding = -1;
42 static int hf_message_type = -1;
43 static int hf_message_flags = -1;
44 static int hf_message_length = -1;
45 static int hf_message_value = -1;
46 static int hf_parameter_type = -1;
47 static int hf_parameter_length = -1;
48 static int hf_parameter_value = -1;
49 static int hf_parameter_padding = -1;
50 static int hf_parameter_ipv4_address = -1;
51 static int hf_parameter_ipv6_address = -1;
52 static int hf_dccp_port = -1;
53 static int hf_dccp_reserved = -1;
54 static int hf_dccp_service_code = -1;
55 static int hf_sctp_port = -1;
56 static int hf_transport_use = -1;
57 static int hf_tcp_port = -1;
58 static int hf_udp_port = -1;
59 static int hf_udp_reserved = -1;
60 static int hf_udp_lite_port = -1;
61 static int hf_udp_lite_reserved = -1;
62 static int hf_policy_type = -1;
63 static int hf_policy_value = -1;
64 static int hf_policy_weight = -1;
65 static int hf_policy_priority = -1;
66 static int hf_policy_load = -1;
67 static int hf_policy_degradation = -1;
68 static int hf_policy_loaddpf = -1;
69 static int hf_policy_weightdpf = -1;
70 static int hf_policy_distance = -1;
71 static int hf_pool_handle = -1;
72 static int hf_pe_pe_identifier = -1;
73 static int hf_home_enrp_id = -1;
74 static int hf_reg_life = -1;
75 static int hf_server_identifier = -1;
76 static int hf_cookie = -1;
77 static int hf_pe_identifier = -1;
78 static int hf_pe_checksum = -1;
79 static int hf_sender_servers_id = -1;
80 static int hf_receiver_servers_id = -1;
81 static int hf_target_servers_id = -1;
82 static int hf_update_action = -1;
83 static int hf_pmu_reserved = -1;
84 static int hf_reply_required_bit = -1;
85 static int hf_own_children_only_bit = -1;
86 static int hf_more_to_send_bit = -1;
87 static int hf_reject_bit = -1;
88 static int hf_tos_bit = -1;
89 
90 /* Initialize the subtree pointers */
91 static gint ett_enrp = -1;
92 static gint ett_enrp_parameter = -1;
93 static gint ett_enrp_cause = -1;
94 static gint ett_enrp_flags = -1;
95 
96 static guint64 enrp_total_msgs = 0;
97 static guint64 enrp_total_bytes = 0;
98 
99 static void
100 dissect_parameters(tvbuff_t *, proto_tree *);
101 static void
102 dissect_parameter(tvbuff_t *, proto_tree *);
103 static int
104 dissect_enrp(tvbuff_t *, packet_info *, proto_tree *, void*);
105 
106 #define ENRP_UDP_PORT  9901
107 #define ENRP_SCTP_PORT 9901
108 
109 typedef struct _enrp_tap_rec_t {
110   guint8      type;
111   guint16     size;
112   const char* type_string;
113 } enrp_tap_rec_t;
114 
115 /* Dissectors for error causes. This is common for ASAP and ENRP. */
116 
117 static void
dissect_unknown_cause(tvbuff_t * cause_tvb,proto_tree * cause_tree,proto_item * cause_item)118 dissect_unknown_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
119 {
120   guint16 code, length, cause_info_length;
121 
122   code              = tvb_get_ntohs(cause_tvb, CAUSE_CODE_OFFSET);
123   length            = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
124   cause_info_length = length - CAUSE_HEADER_LENGTH;
125   if (cause_info_length > 0)
126     proto_tree_add_item(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, ENC_NA);
127   proto_item_append_text(cause_item, " (code %u and %u byte%s information)", code, cause_info_length, plurality(cause_info_length, "", "s"));
128 }
129 
130 static void
dissect_error_cause(tvbuff_t * cause_tvb,proto_tree * parameter_tree)131 dissect_error_cause(tvbuff_t *cause_tvb, proto_tree *parameter_tree)
132 {
133   guint16 code, length, padding_length;
134   proto_item *cause_item;
135   proto_tree *cause_tree;
136   tvbuff_t *parameter_tvb, *message_tvb;
137 
138   code           = tvb_get_ntohs(cause_tvb, CAUSE_CODE_OFFSET);
139   length         = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
140   padding_length = tvb_captured_length(cause_tvb) - length;
141 
142   cause_tree = proto_tree_add_subtree(parameter_tree, cause_tvb, CAUSE_HEADER_OFFSET, -1,
143                     ett_enrp_cause, &cause_item, val_to_str_const(code, cause_code_values, "Unknown error cause"));
144 
145   proto_tree_add_item(cause_tree, hf_cause_code,   cause_tvb, CAUSE_CODE_OFFSET,   CAUSE_CODE_LENGTH,   ENC_BIG_ENDIAN);
146   proto_tree_add_item(cause_tree, hf_cause_length, cause_tvb, CAUSE_LENGTH_OFFSET, CAUSE_LENGTH_LENGTH, ENC_BIG_ENDIAN);
147 
148   switch(code) {
149   case UNRECOGNIZED_PARAMETER_CAUSE_CODE:
150     parameter_tvb = tvb_new_subset_remaining(cause_tvb, CAUSE_INFO_OFFSET);
151     dissect_parameter(parameter_tvb, cause_tree);
152     break;
153   case UNRECONGNIZED_MESSAGE_CAUSE_CODE:
154     message_tvb = tvb_new_subset_remaining(cause_tvb, CAUSE_INFO_OFFSET);
155     dissect_enrp(message_tvb, NULL, cause_tree, NULL);
156     break;
157   case INVALID_VALUES:
158     parameter_tvb = tvb_new_subset_remaining(cause_tvb, CAUSE_INFO_OFFSET);
159     dissect_parameter(parameter_tvb, cause_tree);
160     break;
161   case NON_UNIQUE_PE_IDENTIFIER:
162     break;
163   case POOLING_POLICY_INCONSISTENT_CAUSE_CODE:
164     parameter_tvb = tvb_new_subset_remaining(cause_tvb, CAUSE_INFO_OFFSET);
165     dissect_parameter(parameter_tvb, cause_tree);
166     break;
167   case LACK_OF_RESOURCES_CAUSE_CODE:
168     break;
169   case INCONSISTENT_TRANSPORT_TYPE_CAUSE_CODE:
170     parameter_tvb = tvb_new_subset_remaining(cause_tvb, CAUSE_INFO_OFFSET);
171     dissect_parameter(parameter_tvb, cause_tree);
172     break;
173   case INCONSISTENT_DATA_CONTROL_CONFIGURATION_CAUSE_CODE:
174     break;
175   case UNKNOWN_POOL_HANDLE:
176     break;
177   case REJECTION_DUE_TO_SECURITY_CAUSE_CODE:
178     break;
179   default:
180     dissect_unknown_cause(cause_tvb, cause_tree, cause_item);
181     break;
182   }
183   if (padding_length > 0)
184     proto_tree_add_item(cause_tree, hf_cause_padding, cause_tvb, CAUSE_HEADER_OFFSET + length, padding_length, ENC_NA);
185 }
186 
187 static void
dissect_error_causes(tvbuff_t * error_causes_tvb,proto_tree * parameter_tree)188 dissect_error_causes(tvbuff_t *error_causes_tvb, proto_tree *parameter_tree)
189 {
190   guint16 length, total_length;
191   gint offset;
192   tvbuff_t *error_cause_tvb;
193 
194   offset = 0;
195   while(tvb_reported_length_remaining(error_causes_tvb, offset) > 0) {
196     length          = tvb_get_ntohs(error_causes_tvb, offset + CAUSE_LENGTH_OFFSET);
197     total_length    = ADD_PADDING(length);
198     error_cause_tvb = tvb_new_subset_length(error_causes_tvb, offset, total_length);
199     dissect_error_cause(error_cause_tvb, parameter_tree);
200     offset += total_length;
201   }
202 }
203 
204 /* Dissectors for parameters. This is common for ASAP and ENRP. */
205 
206 static void
dissect_ipv4_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)207 dissect_ipv4_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
208 {
209   proto_tree_add_item(parameter_tree, hf_parameter_ipv4_address, parameter_tvb, IPV4_ADDRESS_OFFSET, IPV4_ADDRESS_LENGTH, ENC_BIG_ENDIAN);
210   proto_item_append_text(parameter_item, " (%s)", tvb_ip_to_str(wmem_packet_scope(), parameter_tvb, IPV4_ADDRESS_OFFSET));
211 }
212 
213 static void
dissect_ipv6_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)214 dissect_ipv6_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
215 {
216   proto_tree_add_item(parameter_tree, hf_parameter_ipv6_address, parameter_tvb, IPV6_ADDRESS_OFFSET, IPV6_ADDRESS_LENGTH, ENC_NA);
217   proto_item_append_text(parameter_item, " (%s)", tvb_ip6_to_str(wmem_packet_scope(), parameter_tvb, IPV6_ADDRESS_OFFSET));
218 }
219 
220 static void
dissect_dccp_transport_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree)221 dissect_dccp_transport_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
222 {
223   tvbuff_t *parameters_tvb;
224 
225   proto_tree_add_item(parameter_tree, hf_dccp_port,         parameter_tvb, DCCP_PORT_OFFSET,         DCCP_PORT_LENGTH,         ENC_BIG_ENDIAN);
226   proto_tree_add_item(parameter_tree, hf_dccp_reserved,     parameter_tvb, DCCP_RESERVED_OFFSET,     DCCP_RESERVED_LENGTH,     ENC_BIG_ENDIAN);
227   proto_tree_add_item(parameter_tree, hf_dccp_service_code, parameter_tvb, DCCP_SERVICE_CODE_OFFSET, DCCP_SERVICE_CODE_LENGTH, ENC_BIG_ENDIAN);
228 
229   parameters_tvb = tvb_new_subset_remaining(parameter_tvb, DCCP_ADDRESS_OFFSET);
230   dissect_parameters(parameters_tvb, parameter_tree);
231 }
232 
233 static void
dissect_sctp_transport_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree)234 dissect_sctp_transport_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
235 {
236   tvbuff_t *parameters_tvb;
237 
238   proto_tree_add_item(parameter_tree, hf_sctp_port,     parameter_tvb, SCTP_PORT_OFFSET,          SCTP_PORT_LENGTH,          ENC_BIG_ENDIAN);
239   proto_tree_add_item(parameter_tree, hf_transport_use, parameter_tvb, SCTP_TRANSPORT_USE_OFFSET, SCTP_TRANSPORT_USE_LENGTH, ENC_BIG_ENDIAN);
240 
241   parameters_tvb = tvb_new_subset_remaining(parameter_tvb, SCTP_ADDRESS_OFFSET);
242   dissect_parameters(parameters_tvb, parameter_tree);
243 }
244 
245 static void
dissect_tcp_transport_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree)246 dissect_tcp_transport_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
247 {
248   tvbuff_t *parameters_tvb;
249 
250   proto_tree_add_item(parameter_tree, hf_tcp_port,      parameter_tvb, TCP_PORT_OFFSET,          TCP_PORT_LENGTH,          ENC_BIG_ENDIAN);
251   proto_tree_add_item(parameter_tree, hf_transport_use, parameter_tvb, TCP_TRANSPORT_USE_OFFSET, TCP_TRANSPORT_USE_LENGTH, ENC_BIG_ENDIAN);
252 
253   parameters_tvb = tvb_new_subset_remaining(parameter_tvb, TCP_ADDRESS_OFFSET);
254   dissect_parameters(parameters_tvb, parameter_tree);
255 }
256 
257 static void
dissect_udp_transport_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree)258 dissect_udp_transport_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
259 {
260   tvbuff_t *parameters_tvb;
261 
262   proto_tree_add_item(parameter_tree, hf_udp_port,     parameter_tvb, UDP_PORT_OFFSET,     UDP_PORT_LENGTH,     ENC_BIG_ENDIAN);
263   proto_tree_add_item(parameter_tree, hf_udp_reserved, parameter_tvb, UDP_RESERVED_OFFSET, UDP_RESERVED_LENGTH, ENC_BIG_ENDIAN);
264 
265   parameters_tvb = tvb_new_subset_remaining(parameter_tvb, UDP_ADDRESS_OFFSET);
266   dissect_parameters(parameters_tvb, parameter_tree);
267 }
268 
269 static void
dissect_udp_lite_transport_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree)270 dissect_udp_lite_transport_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
271 {
272   tvbuff_t *parameters_tvb;
273 
274   proto_tree_add_item(parameter_tree, hf_udp_lite_port,     parameter_tvb, UDP_LITE_PORT_OFFSET,     UDP_LITE_PORT_LENGTH,     ENC_BIG_ENDIAN);
275   proto_tree_add_item(parameter_tree, hf_udp_lite_reserved, parameter_tvb, UDP_LITE_RESERVED_OFFSET, UDP_LITE_RESERVED_LENGTH, ENC_BIG_ENDIAN);
276 
277   parameters_tvb = tvb_new_subset_remaining(parameter_tvb, UDP_LITE_ADDRESS_OFFSET);
278   dissect_parameters(parameters_tvb, parameter_tree);
279 }
280 
281 static void
dissect_pool_member_selection_policy_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree)282 dissect_pool_member_selection_policy_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
283 {
284   guint32 type;
285   guint   length;
286 
287   proto_tree_add_item(parameter_tree, hf_policy_type,  parameter_tvb, POLICY_TYPE_OFFSET,  POLICY_TYPE_LENGTH,  ENC_BIG_ENDIAN);
288   type = tvb_get_ntohl(parameter_tvb, POLICY_TYPE_OFFSET);
289   switch (type) {
290   case RANDOM_POLICY:
291   case ROUND_ROBIN_POLICY:
292     break;
293   case WEIGHTED_RANDOM_POLICY:
294   case WEIGHTED_ROUND_ROBIN_POLICY:
295     proto_tree_add_item(parameter_tree, hf_policy_weight, parameter_tvb, POLICY_WEIGHT_OFFSET, POLICY_WEIGHT_LENGTH, ENC_BIG_ENDIAN);
296     break;
297   case PRIORITY_POLICY:
298     proto_tree_add_item(parameter_tree, hf_policy_priority, parameter_tvb, POLICY_PRIORITY_OFFSET, POLICY_PRIORITY_LENGTH, ENC_BIG_ENDIAN);
299     break;
300   case LEAST_USED_POLICY:
301   case RANDOMIZED_LEAST_USED_POLICY:
302     proto_tree_add_double_format_value(parameter_tree, hf_policy_load, parameter_tvb, POLICY_LOAD_OFFSET, POLICY_LOAD_LENGTH,
303                                        100.0 * tvb_get_ntohl(parameter_tvb, POLICY_LOAD_OFFSET) / (double)0xffffffff, "%1.2f%%",
304                                        100.0 * tvb_get_ntohl(parameter_tvb, POLICY_LOAD_OFFSET) / (double)0xffffffff);
305     break;
306   case LEAST_USED_WITH_DEG_POLICY:
307   case PRIORITY_LEAST_USED_POLICY:
308     proto_tree_add_double_format_value(parameter_tree, hf_policy_load, parameter_tvb, POLICY_LOAD_OFFSET, POLICY_LOAD_LENGTH,
309                                        100.0 * tvb_get_ntohl(parameter_tvb, POLICY_LOAD_OFFSET) / (double)0xffffffff, "%1.2f%%",
310                                        100.0 * tvb_get_ntohl(parameter_tvb, POLICY_LOAD_OFFSET) / (double)0xffffffff);
311     proto_tree_add_double_format_value(parameter_tree, hf_policy_degradation, parameter_tvb, POLICY_DEGRADATION_OFFSET, POLICY_DEGRADATION_LENGTH,
312                                        100.0 * tvb_get_ntohl(parameter_tvb, POLICY_DEGRADATION_OFFSET) / (double)0xffffffff, "%1.2f%%",
313                                        100.0 * tvb_get_ntohl(parameter_tvb, POLICY_DEGRADATION_OFFSET) / (double)0xffffffff);
314     break;
315   case LEAST_USED_DPF_POLICY:
316     proto_tree_add_double_format_value(parameter_tree, hf_policy_load, parameter_tvb, POLICY_LOAD_OFFSET, POLICY_LOAD_LENGTH,
317                                       100.0 * tvb_get_ntohl(parameter_tvb, POLICY_LOAD_OFFSET) / (double)0xffffffff, "%1.2f%%",
318                                       100.0 * tvb_get_ntohl(parameter_tvb, POLICY_LOAD_OFFSET) / (double)0xffffffff);
319     proto_tree_add_double_format_value(parameter_tree, hf_policy_loaddpf, parameter_tvb, POLICY_LUDPF_LOADDPF_OFFSET, POLICY_LUDPF_LOADDPF_LENGTH,
320                                       tvb_get_ntohl(parameter_tvb, POLICY_LUDPF_LOADDPF_OFFSET) / (double)0xffffffff, "%1.5f",
321                                       tvb_get_ntohl(parameter_tvb, POLICY_LUDPF_LOADDPF_OFFSET) / (double)0xffffffff);
322     proto_tree_add_item(parameter_tree, hf_policy_distance, parameter_tvb, POLICY_LUDPF_DISTANCE_OFFSET, POLICY_LUDPF_DISTANCE_LENGTH, ENC_BIG_ENDIAN);
323     break;
324   case WEIGHTED_RANDOM_DPF_POLICY:
325     proto_tree_add_item(parameter_tree, hf_policy_weight, parameter_tvb, POLICY_WEIGHT_OFFSET, POLICY_WEIGHT_LENGTH, ENC_BIG_ENDIAN);
326     proto_tree_add_double_format_value(parameter_tree, hf_policy_weightdpf, parameter_tvb, POLICY_WRANDDPF_WEIGHTDPF_OFFSET, POLICY_WRANDDPF_WEIGHTDPF_LENGTH,
327                                        tvb_get_ntohl(parameter_tvb, POLICY_WRANDDPF_WEIGHTDPF_OFFSET) / (double)0xffffffff, "%1.5f",
328                                        tvb_get_ntohl(parameter_tvb, POLICY_WRANDDPF_WEIGHTDPF_OFFSET) / (double)0xffffffff);
329     proto_tree_add_item(parameter_tree, hf_policy_distance, parameter_tvb, POLICY_WRANDDPF_DISTANCE_OFFSET, POLICY_WRANDDPF_DISTANCE_LENGTH, ENC_BIG_ENDIAN);
330     break;
331   default:
332     length = tvb_reported_length(parameter_tvb) - POLICY_VALUE_OFFSET;
333     if (length > 0) {
334       proto_tree_add_item(parameter_tree, hf_policy_value, parameter_tvb, POLICY_VALUE_OFFSET, length, ENC_NA);
335     }
336     break;
337   }
338 }
339 
340 static void
dissect_pool_handle_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree)341 dissect_pool_handle_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
342 {
343   guint16 handle_length;
344   proto_item*    pi;
345 
346   handle_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
347   pi = proto_tree_add_item(parameter_tree, hf_pool_handle, parameter_tvb, POOL_HANDLE_OFFSET, handle_length, ENC_NA);
348 
349   proto_item_append_text(pi, " (%s)",
350                          tvb_format_text(wmem_packet_scope(), parameter_tvb, POOL_HANDLE_OFFSET, handle_length) );
351 }
352 
353 static void
dissect_pool_element_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree)354 dissect_pool_element_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
355 {
356   tvbuff_t*   parameters_tvb;
357 
358   proto_tree_add_item(parameter_tree, hf_pe_pe_identifier, parameter_tvb, PE_PE_IDENTIFIER_OFFSET,      PE_PE_IDENTIFIER_LENGTH,      ENC_BIG_ENDIAN);
359   proto_tree_add_item(parameter_tree, hf_home_enrp_id,     parameter_tvb, HOME_ENRP_INDENTIFIER_OFFSET, HOME_ENRP_INDENTIFIER_LENGTH, ENC_BIG_ENDIAN);
360   proto_tree_add_item(parameter_tree, hf_reg_life,    parameter_tvb, REGISTRATION_LIFE_OFFSET,     REGISTRATION_LIFE_LENGTH,     ENC_BIG_ENDIAN);
361 
362   parameters_tvb = tvb_new_subset_remaining(parameter_tvb, USER_TRANSPORT_PARAMETER_OFFSET);
363   dissect_parameters(parameters_tvb, parameter_tree);
364 }
365 
366 static void
dissect_server_information_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree)367 dissect_server_information_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
368 {
369   tvbuff_t *parameters_tvb;
370 
371   proto_tree_add_item(parameter_tree, hf_server_identifier, parameter_tvb, SERVER_ID_OFFSET, SERVER_ID_LENGTH, ENC_BIG_ENDIAN);
372 
373   parameters_tvb = tvb_new_subset_remaining(parameter_tvb, SERVER_TRANSPORT_OFFSET);
374   dissect_parameters(parameters_tvb, parameter_tree);
375 }
376 
377 static void
dissect_operation_error_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree)378 dissect_operation_error_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
379 {
380   tvbuff_t *error_causes_tvb;
381 
382   error_causes_tvb = tvb_new_subset_remaining(parameter_tvb, ERROR_CAUSES_OFFSET);
383   dissect_error_causes(error_causes_tvb, parameter_tree);
384 }
385 
386 static void
dissect_cookie_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)387 dissect_cookie_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
388 {
389   guint16 cookie_length;
390 
391   cookie_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
392   if (cookie_length > 0)
393     proto_tree_add_item(parameter_tree, hf_cookie, parameter_tvb, COOKIE_OFFSET, cookie_length, ENC_NA);
394   proto_item_append_text(parameter_item, " (%u byte%s)", cookie_length, plurality(cookie_length, "", "s"));
395 }
396 
397 static void
dissect_pe_identifier_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)398 dissect_pe_identifier_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
399 {
400   proto_tree_add_item(parameter_tree, hf_pe_identifier, parameter_tvb, PE_IDENTIFIER_OFFSET, PE_IDENTIFIER_LENGTH, ENC_BIG_ENDIAN);
401   proto_item_append_text(parameter_item, " (0x%x)", tvb_get_ntohl(parameter_tvb, PE_IDENTIFIER_OFFSET));
402 }
403 
404 static void
dissect_pe_checksum_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)405 dissect_pe_checksum_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
406 {
407   proto_tree_add_item(parameter_tree, hf_pe_checksum,  parameter_tvb, PE_CHECKSUM_OFFSET, PE_CHECKSUM_LENGTH, ENC_BIG_ENDIAN);
408   proto_item_append_text(parameter_item, " (0x%x)", tvb_get_ntohs(parameter_tvb, PE_CHECKSUM_OFFSET));
409 }
410 
411 static void
dissect_unknown_parameter(tvbuff_t * parameter_tvb,proto_tree * parameter_tree,proto_item * parameter_item)412 dissect_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
413 {
414   guint16 type, parameter_value_length;
415 
416   type                   = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET);
417   parameter_value_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
418 
419   if (parameter_value_length > 0)
420     proto_tree_add_item(parameter_tree, hf_parameter_value, parameter_tvb, PARAMETER_VALUE_OFFSET, parameter_value_length, ENC_NA);
421 
422   proto_item_append_text(parameter_item, " (type %u and %u byte%s value)", type, parameter_value_length, plurality(parameter_value_length, "", "s"));
423 }
424 
425 static void
dissect_parameter(tvbuff_t * parameter_tvb,proto_tree * enrp_tree)426 dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *enrp_tree)
427 {
428   guint16 type, length, padding_length;
429   proto_tree *parameter_item;
430   proto_tree *parameter_tree;
431 
432   /* extract tag and length from the parameter */
433   type           = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET);
434   length         = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
435   padding_length = tvb_captured_length(parameter_tvb) - length;
436 
437   /* create proto_tree stuff */
438   parameter_tree   = proto_tree_add_subtree(enrp_tree, parameter_tvb, PARAMETER_HEADER_OFFSET, -1,
439       ett_enrp_parameter, &parameter_item, val_to_str_const(type, parameter_type_values, "Unknown Parameter"));
440 
441   /* add tag and length to the enrp tree */
442   proto_tree_add_item(parameter_tree, hf_parameter_type,   parameter_tvb, PARAMETER_TYPE_OFFSET,   PARAMETER_TYPE_LENGTH,   ENC_BIG_ENDIAN);
443   proto_tree_add_item(parameter_tree, hf_parameter_length, parameter_tvb, PARAMETER_LENGTH_OFFSET, PARAMETER_LENGTH_LENGTH, ENC_BIG_ENDIAN);
444 
445   switch(type) {
446   case IPV4_ADDRESS_PARAMETER_TYPE:
447     dissect_ipv4_parameter(parameter_tvb, parameter_tree, parameter_item);
448     break;
449   case IPV6_ADDRESS_PARAMETER_TYPE:
450     dissect_ipv6_parameter(parameter_tvb, parameter_tree, parameter_item);
451     break;
452   case DCCP_TRANSPORT_PARAMETER_TYPE:
453     dissect_dccp_transport_parameter(parameter_tvb, parameter_tree);
454     break;
455   case SCTP_TRANSPORT_PARAMETER_TYPE:
456     dissect_sctp_transport_parameter(parameter_tvb, parameter_tree);
457     break;
458   case TCP_TRANSPORT_PARAMETER_TYPE:
459     dissect_tcp_transport_parameter(parameter_tvb, parameter_tree);
460     break;
461   case UDP_TRANSPORT_PARAMETER_TYPE:
462     dissect_udp_transport_parameter(parameter_tvb, parameter_tree);
463     break;
464   case UDP_LITE_TRANSPORT_PARAMETER_TYPE:
465     dissect_udp_lite_transport_parameter(parameter_tvb, parameter_tree);
466     break;
467   case POOL_MEMBER_SELECTION_POLICY_PARAMETER_TYPE:
468     dissect_pool_member_selection_policy_parameter(parameter_tvb, parameter_tree);
469     break;
470   case POOL_HANDLE_PARAMETER_TYPE:
471     dissect_pool_handle_parameter(parameter_tvb, parameter_tree);
472     break;
473   case POOL_ELEMENT_PARAMETER_TYPE:
474     dissect_pool_element_parameter(parameter_tvb, parameter_tree);
475     break;
476   case SERVER_INFORMATION_PARAMETER_TYPE:
477     dissect_server_information_parameter(parameter_tvb, parameter_tree);
478     break;
479   case OPERATION_ERROR_PARAMETER_TYPE:
480     dissect_operation_error_parameter(parameter_tvb, parameter_tree);
481     break;
482   case COOKIE_PARAMETER_TYPE:
483     dissect_cookie_parameter(parameter_tvb, parameter_tree, parameter_item);
484     break;
485   case PE_IDENTIFIER_PARAMETER_TYPE:
486     dissect_pe_identifier_parameter(parameter_tvb, parameter_tree, parameter_item);
487     break;
488   case PE_CHECKSUM_PARAMETER_TYPE:
489     dissect_pe_checksum_parameter(parameter_tvb, parameter_tree, parameter_item);
490     break;
491   default:
492     dissect_unknown_parameter(parameter_tvb, parameter_tree, parameter_item);
493     break;
494   };
495 
496   if (padding_length > 0)
497     proto_tree_add_item(parameter_tree, hf_parameter_padding, parameter_tvb, PARAMETER_HEADER_OFFSET + length, padding_length, ENC_NA);
498 }
499 
500 static void
dissect_parameters(tvbuff_t * parameters_tvb,proto_tree * tree)501 dissect_parameters(tvbuff_t *parameters_tvb, proto_tree *tree)
502 {
503   gint offset, length, total_length, remaining_length;
504   tvbuff_t *parameter_tvb;
505 
506   offset = 0;
507   while((remaining_length = tvb_reported_length_remaining(parameters_tvb, offset)) > 0) {
508     length       = tvb_get_ntohs(parameters_tvb, offset + PARAMETER_LENGTH_OFFSET);
509     total_length = ADD_PADDING(length);
510     if (remaining_length >= length)
511       total_length = MIN(total_length, remaining_length);
512     /* create a tvb for the parameter including the padding bytes */
513     parameter_tvb  = tvb_new_subset_length(parameters_tvb, offset, total_length);
514     dissect_parameter(parameter_tvb, tree);
515     /* get rid of the handled parameter */
516     offset += total_length;
517   }
518 }
519 
520 /* Dissectors for messages. This is specific to ENRP */
521 
522 #define SENDER_SERVERS_ID_LENGTH   4
523 #define RECEIVER_SERVERS_ID_LENGTH 4
524 
525 #define SENDER_SERVERS_ID_OFFSET   MESSAGE_VALUE_OFFSET
526 #define RECEIVER_SERVERS_ID_OFFSET (SENDER_SERVERS_ID_OFFSET + SENDER_SERVERS_ID_LENGTH)
527 #define MESSAGE_PARAMETERS_OFFSET  (RECEIVER_SERVERS_ID_OFFSET + RECEIVER_SERVERS_ID_LENGTH)
528 
529 #define REPLY_REQUIRED_BIT_MASK 0x01
530 
531 static const true_false_string reply_required_bit_value = {
532   "Reply required",
533   "Reply not required"
534 };
535 
536 static void
dissect_enrp_presence_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree)537 dissect_enrp_presence_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree)
538 {
539   tvbuff_t *parameters_tvb;
540 
541   proto_tree_add_item(flags_tree,   hf_reply_required_bit,  message_tvb, MESSAGE_FLAGS_OFFSET,       MESSAGE_FLAGS_LENGTH,       ENC_BIG_ENDIAN);
542   proto_tree_add_item(message_tree, hf_sender_servers_id,   message_tvb, SENDER_SERVERS_ID_OFFSET,   SENDER_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
543   proto_tree_add_item(message_tree, hf_receiver_servers_id, message_tvb, RECEIVER_SERVERS_ID_OFFSET, RECEIVER_SERVERS_ID_LENGTH, ENC_BIG_ENDIAN);
544   parameters_tvb = tvb_new_subset_remaining(message_tvb, MESSAGE_PARAMETERS_OFFSET);
545   dissect_parameters(parameters_tvb, message_tree);
546 }
547 
548 #define OWN_CHILDREN_ONLY_BIT_MASK 0x01
549 
550 static const true_false_string own_children_only_bit_value = {
551   "Only information for own PEs",
552   "Information for all PEs"
553 };
554 
555 
556 static void
dissect_enrp_handle_table_request_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree)557 dissect_enrp_handle_table_request_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree)
558 {
559   /* FIXME: ensure that the length is 12 bytes. */
560   proto_tree_add_item(flags_tree,   hf_own_children_only_bit,  message_tvb, MESSAGE_FLAGS_OFFSET,       MESSAGE_FLAGS_LENGTH,       ENC_BIG_ENDIAN);
561   proto_tree_add_item(message_tree, hf_sender_servers_id,      message_tvb, SENDER_SERVERS_ID_OFFSET,   SENDER_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
562   proto_tree_add_item(message_tree, hf_receiver_servers_id,    message_tvb, RECEIVER_SERVERS_ID_OFFSET, RECEIVER_SERVERS_ID_LENGTH, ENC_BIG_ENDIAN);
563 }
564 
565 #define REJECT_BIT_MASK       0x01
566 #define MORE_TO_SEND_BIT_MASK 0x02
567 
568 static const true_false_string reject_bit_value = {
569   "Rejected",
570   "Accepted"
571 };
572 
573 static const true_false_string more_to_send_bit_value = {
574   "More information available",
575   "All information included"
576 };
577 
578 static void
dissect_enrp_handle_table_response_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree)579 dissect_enrp_handle_table_response_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree)
580 {
581   tvbuff_t *parameters_tvb;
582 
583   proto_tree_add_item(flags_tree,   hf_more_to_send_bit,    message_tvb, MESSAGE_FLAGS_OFFSET,       MESSAGE_FLAGS_LENGTH,       ENC_BIG_ENDIAN);
584   proto_tree_add_item(flags_tree,   hf_reject_bit,          message_tvb, MESSAGE_FLAGS_OFFSET,       MESSAGE_FLAGS_LENGTH,       ENC_BIG_ENDIAN);
585   proto_tree_add_item(message_tree, hf_sender_servers_id,   message_tvb, SENDER_SERVERS_ID_OFFSET,   SENDER_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
586   proto_tree_add_item(message_tree, hf_receiver_servers_id, message_tvb, RECEIVER_SERVERS_ID_OFFSET, RECEIVER_SERVERS_ID_LENGTH, ENC_BIG_ENDIAN);
587   parameters_tvb = tvb_new_subset_remaining(message_tvb, MESSAGE_PARAMETERS_OFFSET);
588   dissect_parameters(parameters_tvb, message_tree);
589 }
590 
591 #define UPDATE_ACTION_LENGTH 2
592 #define PNU_RESERVED_LENGTH  2
593 
594 #define UPDATE_ACTION_OFFSET           (MESSAGE_VALUE_OFFSET + SENDER_SERVERS_ID_LENGTH + RECEIVER_SERVERS_ID_LENGTH)
595 #define PNU_RESERVED_OFFSET            (UPDATE_ACTION_OFFSET + UPDATE_ACTION_LENGTH)
596 #define PNU_MESSAGE_PARAMETERS_OFFSET  (PNU_RESERVED_OFFSET + PNU_RESERVED_LENGTH)
597 
598 static const value_string update_action_values[] = {
599   { 0, "Add pool element"    },
600   { 1, "Delete pool element" },
601   { 0, NULL                  } };
602 
603 #define TOS_BIT_MASK 0x01
604 
605 static const true_false_string tos_bit_value = {
606   "Takeover suggested",
607   "Takeover not suggested"
608 };
609 
610 static void
dissect_enrp_handle_update_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree)611 dissect_enrp_handle_update_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree)
612 {
613   tvbuff_t *parameters_tvb;
614 
615   proto_tree_add_item(flags_tree,   hf_tos_bit,             message_tvb, MESSAGE_FLAGS_OFFSET,       MESSAGE_FLAGS_LENGTH,       ENC_BIG_ENDIAN);
616   proto_tree_add_item(message_tree, hf_sender_servers_id,   message_tvb, SENDER_SERVERS_ID_OFFSET,   SENDER_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
617   proto_tree_add_item(message_tree, hf_receiver_servers_id, message_tvb, RECEIVER_SERVERS_ID_OFFSET, RECEIVER_SERVERS_ID_LENGTH, ENC_BIG_ENDIAN);
618   proto_tree_add_item(message_tree, hf_update_action,       message_tvb, UPDATE_ACTION_OFFSET,       UPDATE_ACTION_LENGTH,       ENC_BIG_ENDIAN);
619   proto_tree_add_item(message_tree, hf_pmu_reserved,        message_tvb, PNU_RESERVED_OFFSET,        PNU_RESERVED_LENGTH,        ENC_BIG_ENDIAN);
620   parameters_tvb = tvb_new_subset_remaining(message_tvb, PNU_MESSAGE_PARAMETERS_OFFSET);
621   dissect_parameters(parameters_tvb, message_tree);
622 }
623 
624 static void
dissect_enrp_list_request_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree _U_)625 dissect_enrp_list_request_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree _U_)
626 {
627   /* FIXME: ensure that the length is 12 bytes. */
628   proto_tree_add_item(message_tree, hf_sender_servers_id,   message_tvb, SENDER_SERVERS_ID_OFFSET,   SENDER_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
629   proto_tree_add_item(message_tree, hf_receiver_servers_id, message_tvb, RECEIVER_SERVERS_ID_OFFSET, RECEIVER_SERVERS_ID_LENGTH, ENC_BIG_ENDIAN);
630 }
631 
632 static void
dissect_enrp_list_response_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree)633 dissect_enrp_list_response_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree)
634 {
635   tvbuff_t *parameters_tvb;
636 
637   proto_tree_add_item(flags_tree,   hf_reject_bit,          message_tvb, MESSAGE_FLAGS_OFFSET,       MESSAGE_FLAGS_LENGTH,       ENC_BIG_ENDIAN);
638   proto_tree_add_item(message_tree, hf_sender_servers_id,   message_tvb, SENDER_SERVERS_ID_OFFSET,   SENDER_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
639   proto_tree_add_item(message_tree, hf_receiver_servers_id, message_tvb, RECEIVER_SERVERS_ID_OFFSET, RECEIVER_SERVERS_ID_LENGTH, ENC_BIG_ENDIAN);
640   parameters_tvb = tvb_new_subset_remaining(message_tvb, MESSAGE_PARAMETERS_OFFSET);
641   dissect_parameters(parameters_tvb, message_tree);
642 }
643 
644 #define TARGET_SERVERS_ID_LENGTH 4
645 #define TARGET_SERVERS_ID_OFFSET (RECEIVER_SERVERS_ID_OFFSET + RECEIVER_SERVERS_ID_LENGTH)
646 
647 static void
dissect_enrp_init_takeover_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree _U_)648 dissect_enrp_init_takeover_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree _U_)
649 {
650   /* FIXME: ensure that the length is 16 bytes. */
651   proto_tree_add_item(message_tree, hf_sender_servers_id,   message_tvb, SENDER_SERVERS_ID_OFFSET,   SENDER_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
652   proto_tree_add_item(message_tree, hf_receiver_servers_id, message_tvb, RECEIVER_SERVERS_ID_OFFSET, RECEIVER_SERVERS_ID_LENGTH, ENC_BIG_ENDIAN);
653   proto_tree_add_item(message_tree, hf_target_servers_id,   message_tvb, TARGET_SERVERS_ID_OFFSET,   TARGET_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
654 }
655 
656 static void
dissect_enrp_init_takeover_ack_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree _U_)657 dissect_enrp_init_takeover_ack_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree _U_)
658 {
659   /* FIXME: ensure that the length is 16 bytes. */
660   proto_tree_add_item(message_tree, hf_sender_servers_id,   message_tvb, SENDER_SERVERS_ID_OFFSET,   SENDER_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
661   proto_tree_add_item(message_tree, hf_receiver_servers_id, message_tvb, RECEIVER_SERVERS_ID_OFFSET, RECEIVER_SERVERS_ID_LENGTH, ENC_BIG_ENDIAN);
662   proto_tree_add_item(message_tree, hf_target_servers_id,   message_tvb, TARGET_SERVERS_ID_OFFSET,   TARGET_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
663 }
664 
665 static void
dissect_enrp_init_takeover_server_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree _U_)666 dissect_enrp_init_takeover_server_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree _U_)
667 {
668   /* FIXME: ensure that the length is 16 bytes. */
669   proto_tree_add_item(message_tree, hf_sender_servers_id,   message_tvb, SENDER_SERVERS_ID_OFFSET,   SENDER_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
670   proto_tree_add_item(message_tree, hf_receiver_servers_id, message_tvb, RECEIVER_SERVERS_ID_OFFSET, RECEIVER_SERVERS_ID_LENGTH, ENC_BIG_ENDIAN);
671   proto_tree_add_item(message_tree, hf_target_servers_id,   message_tvb, TARGET_SERVERS_ID_OFFSET,   TARGET_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
672 }
673 
674 static void
dissect_enrp_error_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree _U_)675 dissect_enrp_error_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree _U_)
676 {
677   tvbuff_t *parameters_tvb;
678 
679   proto_tree_add_item(message_tree, hf_sender_servers_id,   message_tvb, SENDER_SERVERS_ID_OFFSET,   SENDER_SERVERS_ID_LENGTH,   ENC_BIG_ENDIAN);
680   proto_tree_add_item(message_tree, hf_receiver_servers_id, message_tvb, RECEIVER_SERVERS_ID_OFFSET, RECEIVER_SERVERS_ID_LENGTH, ENC_BIG_ENDIAN);
681   parameters_tvb = tvb_new_subset_remaining(message_tvb, MESSAGE_PARAMETERS_OFFSET);
682   dissect_parameters(parameters_tvb, message_tree);
683 }
684 
685 static void
dissect_unknown_message(tvbuff_t * message_tvb,proto_tree * message_tree,proto_tree * flags_tree _U_)686 dissect_unknown_message(tvbuff_t *message_tvb, proto_tree *message_tree, proto_tree *flags_tree _U_)
687 {
688   proto_tree_add_item(message_tree, hf_message_value, message_tvb, MESSAGE_VALUE_OFFSET, tvb_captured_length(message_tvb) - MESSAGE_HEADER_LENGTH, ENC_NA);
689 }
690 
691 #define ENRP_PRESENCE_MESSAGE_TYPE              0x01
692 #define ENRP_HANDLE_TABLE_REQUEST_MESSAGE_TYPE  0x02
693 #define ENRP_HANDLE_TABLE_RESPONSE_MESSAGE_TYPE 0x03
694 #define ENRP_HANDLE_UPDATE_MESSAGE_TYPE         0x04
695 #define ENRP_LIST_REQUEST_MESSAGE_TYPE          0x05
696 #define ENRP_LIST_RESPONSE_MESSAGE_TYPE         0x06
697 #define ENRP_INIT_TAKEOVER_MESSAGE_TYPE         0x07
698 #define ENRP_INIT_TAKEOVER_ACK_MESSAGE_TYPE     0x08
699 #define ENRP_TAKEOVER_SERVER_MESSAGE_TYPE       0x09
700 #define ENRP_ERROR_MESSAGE_TYPE                 0x0a
701 
702 static const value_string message_type_values[] = {
703   { ENRP_PRESENCE_MESSAGE_TYPE,              "ENRP Presence" },
704   { ENRP_HANDLE_TABLE_REQUEST_MESSAGE_TYPE,  "ENRP Handle Table Request" },
705   { ENRP_HANDLE_TABLE_RESPONSE_MESSAGE_TYPE, "ENRP Handle Table Response" },
706   { ENRP_HANDLE_UPDATE_MESSAGE_TYPE,         "ENRP Handle Update" },
707   { ENRP_LIST_REQUEST_MESSAGE_TYPE,          "ENRP List Request" },
708   { ENRP_LIST_RESPONSE_MESSAGE_TYPE,         "ENRP List Response" },
709   { ENRP_INIT_TAKEOVER_MESSAGE_TYPE,         "ENRP Init Takeover" },
710   { ENRP_INIT_TAKEOVER_ACK_MESSAGE_TYPE,     "ENRP Init Takeover Ack" },
711   { ENRP_TAKEOVER_SERVER_MESSAGE_TYPE,       "ENRP Takeover Server" },
712   { ENRP_ERROR_MESSAGE_TYPE,                 "ENRP Error" },
713   { 0,                                       NULL } };
714 
715 static void
dissect_enrp_message(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * enrp_tree)716 dissect_enrp_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *enrp_tree)
717 {
718   enrp_tap_rec_t *tap_rec;
719   proto_item *flags_item;
720   proto_tree *flags_tree;
721   guint8 type;
722 
723   type = tvb_get_guint8(message_tvb, MESSAGE_TYPE_OFFSET);
724   /* pinfo is NULL only if dissect_enrp_message is called via dissect_error_cause */
725   if (pinfo) {
726     tap_rec = wmem_new0(pinfo->pool, enrp_tap_rec_t);
727     tap_rec->type        = type;
728     tap_rec->size        = tvb_get_ntohs(message_tvb, MESSAGE_LENGTH_OFFSET);
729     tap_rec->type_string = val_to_str_const(tap_rec->type, message_type_values, "Unknown ENRP type");
730     tap_queue_packet(enrp_tap, pinfo, tap_rec);
731 
732     col_add_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(type, message_type_values, "Unknown ENRP Type"));
733   }
734 
735   if (enrp_tree) {
736     proto_tree_add_item(enrp_tree, hf_message_type,   message_tvb, MESSAGE_TYPE_OFFSET,   MESSAGE_TYPE_LENGTH,   ENC_BIG_ENDIAN);
737     flags_item = proto_tree_add_item(enrp_tree, hf_message_flags,  message_tvb, MESSAGE_FLAGS_OFFSET,  MESSAGE_FLAGS_LENGTH,  ENC_BIG_ENDIAN);
738     flags_tree  = proto_item_add_subtree(flags_item, ett_enrp_flags);
739     proto_tree_add_item(enrp_tree, hf_message_length, message_tvb, MESSAGE_LENGTH_OFFSET, MESSAGE_LENGTH_LENGTH, ENC_BIG_ENDIAN);
740     switch (type) {
741       case ENRP_PRESENCE_MESSAGE_TYPE:
742         dissect_enrp_presence_message(message_tvb, enrp_tree, flags_tree);
743         break;
744       case ENRP_HANDLE_TABLE_REQUEST_MESSAGE_TYPE:
745         dissect_enrp_handle_table_request_message(message_tvb, enrp_tree, flags_tree);
746         break;
747       case ENRP_HANDLE_TABLE_RESPONSE_MESSAGE_TYPE:
748         dissect_enrp_handle_table_response_message(message_tvb, enrp_tree, flags_tree);
749         break;
750       case ENRP_HANDLE_UPDATE_MESSAGE_TYPE:
751         dissect_enrp_handle_update_message(message_tvb, enrp_tree, flags_tree);
752         break;
753       case ENRP_LIST_REQUEST_MESSAGE_TYPE:
754         dissect_enrp_list_request_message(message_tvb, enrp_tree, flags_tree);
755         break;
756       case ENRP_LIST_RESPONSE_MESSAGE_TYPE:
757         dissect_enrp_list_response_message(message_tvb, enrp_tree, flags_tree);
758         break;
759       case ENRP_INIT_TAKEOVER_MESSAGE_TYPE:
760         dissect_enrp_init_takeover_message(message_tvb, enrp_tree, flags_tree);
761         break;
762       case ENRP_INIT_TAKEOVER_ACK_MESSAGE_TYPE:
763         dissect_enrp_init_takeover_ack_message(message_tvb, enrp_tree, flags_tree);
764         break;
765       case ENRP_TAKEOVER_SERVER_MESSAGE_TYPE:
766         dissect_enrp_init_takeover_server_message(message_tvb, enrp_tree, flags_tree);
767         break;
768       case ENRP_ERROR_MESSAGE_TYPE:
769         dissect_enrp_error_message(message_tvb, enrp_tree, flags_tree);
770         break;
771       default:
772         dissect_unknown_message(message_tvb, enrp_tree, flags_tree);
773         break;
774     }
775   }
776 }
777 
778 static int
dissect_enrp(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)779 dissect_enrp(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
780 {
781   proto_item *enrp_item;
782   proto_tree *enrp_tree;
783 
784   /* pinfo is NULL only if dissect_enrp is called from dissect_error_cause */
785   if (pinfo)
786     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENRP");
787 
788   /* create the enrp protocol tree */
789   enrp_item = proto_tree_add_item(tree, proto_enrp, message_tvb, 0, -1, ENC_NA);
790   enrp_tree = proto_item_add_subtree(enrp_item, ett_enrp);
791 
792   /* dissect the message */
793   dissect_enrp_message(message_tvb, pinfo, enrp_tree);
794   return tvb_captured_length(message_tvb);
795 }
796 
797 /* TAP STAT INFO */
798 typedef enum
799 {
800   MESSAGE_TYPE_COLUMN = 0,
801   MESSAGES_COLUMN,
802   MESSAGES_SHARE_COLUMN,
803   BYTES_COLUMN,
804   BYTES_SHARE_COLUMN,
805   FIRST_SEEN_COLUMN,
806   LAST_SEEN_COLUMN,
807   INTERVAL_COLUMN,
808   MESSAGE_RATE_COLUMN,
809   BYTE_RATE_COLUMN
810 } enrp_stat_columns;
811 
812 static stat_tap_table_item enrp_stat_fields[] = {
813   { TABLE_ITEM_STRING, TAP_ALIGN_LEFT,  "NetPerfMeter Message Type", "%-25s" },
814   { TABLE_ITEM_UINT,   TAP_ALIGN_RIGHT, "Messages ",            "%u"       },
815   { TABLE_ITEM_UINT,   TAP_ALIGN_RIGHT, "Messages Share (%)"  , "%1.3f %%" },
816   { TABLE_ITEM_UINT,   TAP_ALIGN_RIGHT, "Bytes (B)",            "%u"       },
817   { TABLE_ITEM_UINT,   TAP_ALIGN_RIGHT, "Bytes Share (%) ",     "%1.3f %%" },
818   { TABLE_ITEM_FLOAT,  TAP_ALIGN_LEFT,  "First Seen (s)",       "%1.6f"    },
819   { TABLE_ITEM_FLOAT,  TAP_ALIGN_LEFT,  "Last Seen (s)",        "%1.6f"    },
820   { TABLE_ITEM_FLOAT,  TAP_ALIGN_LEFT,  "Interval (s)",         "%1.6f"    },
821   { TABLE_ITEM_FLOAT,  TAP_ALIGN_LEFT,  "Message Rate (Msg/s)", "%1.2f"    },
822   { TABLE_ITEM_FLOAT,  TAP_ALIGN_LEFT,  "Byte Rate (B/s)",      "%1.2f"    }
823 };
824 
enrp_stat_init(stat_tap_table_ui * new_stat)825 static void enrp_stat_init(stat_tap_table_ui* new_stat)
826 {
827   const char *table_name = "NetPerfMeter Statistics";
828   int num_fields = sizeof(enrp_stat_fields)/sizeof(stat_tap_table_item);
829   stat_tap_table *table;
830   int i = 0;
831   stat_tap_table_item_type items[sizeof(enrp_stat_fields)/sizeof(stat_tap_table_item)];
832 
833   table = stat_tap_find_table(new_stat, table_name);
834   if (table) {
835     if (new_stat->stat_tap_reset_table_cb) {
836       new_stat->stat_tap_reset_table_cb(table);
837     }
838     return;
839   }
840 
841   table = stat_tap_init_table(table_name, num_fields, 0, NULL);
842   stat_tap_add_table(new_stat, table);
843 
844   /* Add a row for each value type */
845   while (message_type_values[i].strptr) {
846     items[MESSAGE_TYPE_COLUMN].type                = TABLE_ITEM_STRING;
847     items[MESSAGE_TYPE_COLUMN].value.string_value  = message_type_values[i].strptr;
848     items[MESSAGES_COLUMN].type                    = TABLE_ITEM_UINT;
849     items[MESSAGES_COLUMN].value.uint_value        = 0;
850     items[MESSAGES_SHARE_COLUMN].type              = TABLE_ITEM_NONE;
851     items[MESSAGES_SHARE_COLUMN].value.float_value = -1.0;
852     items[BYTES_COLUMN].type                       = TABLE_ITEM_UINT;
853     items[BYTES_COLUMN].value.uint_value           = 0;
854     items[BYTES_SHARE_COLUMN].type                 = TABLE_ITEM_NONE;
855     items[BYTES_SHARE_COLUMN].value.float_value    = -1.0;
856     items[FIRST_SEEN_COLUMN].type                  = TABLE_ITEM_NONE;
857     items[FIRST_SEEN_COLUMN].value.float_value     = DBL_MAX;
858     items[LAST_SEEN_COLUMN].type                   = TABLE_ITEM_NONE;
859     items[LAST_SEEN_COLUMN].value.float_value      = DBL_MIN;
860     items[INTERVAL_COLUMN].type                    = TABLE_ITEM_NONE;
861     items[INTERVAL_COLUMN].value.float_value       = -1.0;
862     items[MESSAGE_RATE_COLUMN].type                = TABLE_ITEM_NONE;
863     items[MESSAGE_RATE_COLUMN].value.float_value   = -1.0;
864     items[BYTE_RATE_COLUMN].type                   = TABLE_ITEM_NONE;
865     items[BYTE_RATE_COLUMN].value.float_value      = -1.0;
866     stat_tap_init_table_row(table, i, num_fields, items);
867     i++;
868   }
869 }
870 
871 static tap_packet_status
enrp_stat_packet(void * tapdata,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * data)872 enrp_stat_packet(void* tapdata, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* data)
873 {
874   stat_data_t*              stat_data = (stat_data_t*)tapdata;
875   const enrp_tap_rec_t*     tap_rec   = (const enrp_tap_rec_t*)data;
876   stat_tap_table*           table;
877   stat_tap_table_item_type* msg_data;
878   gint                      idx;
879   guint64                   messages;
880   guint64                   bytes;
881   int                       i         = 0;
882   double                    firstSeen = -1.0;
883   double                    lastSeen  = -1.0;
884 
885   idx = str_to_val_idx(tap_rec->type_string, message_type_values);
886   if (idx < 0)
887     return TAP_PACKET_DONT_REDRAW;
888 
889   table = g_array_index(stat_data->stat_tap_data->tables, stat_tap_table*, 0);
890 
891   /* Update packets counter */
892   enrp_total_msgs++;
893   msg_data = stat_tap_get_field_data(table, idx, MESSAGES_COLUMN);
894   msg_data->value.uint_value++;
895   messages = msg_data->value.uint_value;
896   stat_tap_set_field_data(table, idx, MESSAGES_COLUMN, msg_data);
897 
898   /* Update bytes counter */
899   enrp_total_bytes += tap_rec->size;
900   msg_data = stat_tap_get_field_data(table, idx, BYTES_COLUMN);
901   msg_data->value.uint_value += tap_rec->size;
902   bytes = msg_data->value.uint_value;
903   stat_tap_set_field_data(table, idx, BYTES_COLUMN, msg_data);
904 
905   /* Update messages and bytes share */
906   while (message_type_values[i].strptr) {
907     msg_data = stat_tap_get_field_data(table, i, MESSAGES_COLUMN);
908     const guint m = msg_data->value.uint_value;
909     msg_data = stat_tap_get_field_data(table, i, BYTES_COLUMN);
910     const guint b = msg_data->value.uint_value;
911 
912     msg_data = stat_tap_get_field_data(table, i, MESSAGES_SHARE_COLUMN);
913     msg_data->type = TABLE_ITEM_FLOAT;
914     msg_data->value.float_value = 100.0 * m / (double)enrp_total_msgs;
915     stat_tap_set_field_data(table, i, MESSAGES_SHARE_COLUMN, msg_data);
916 
917     msg_data = stat_tap_get_field_data(table, i, BYTES_SHARE_COLUMN);
918     msg_data->type = TABLE_ITEM_FLOAT;
919     msg_data->value.float_value = 100.0 * b / (double)enrp_total_bytes;
920     stat_tap_set_field_data(table, i, BYTES_SHARE_COLUMN, msg_data);
921     i++;
922   }
923 
924   /* Update first seen time */
925   if (pinfo->presence_flags & PINFO_HAS_TS) {
926     msg_data = stat_tap_get_field_data(table, idx, FIRST_SEEN_COLUMN);
927     msg_data->type = TABLE_ITEM_FLOAT;
928     msg_data->value.float_value = MIN(msg_data->value.float_value, nstime_to_sec(&pinfo->rel_ts));
929     firstSeen = msg_data->value.float_value;
930     stat_tap_set_field_data(table, idx, FIRST_SEEN_COLUMN, msg_data);
931   }
932 
933   /* Update last seen time */
934   if (pinfo->presence_flags & PINFO_HAS_TS) {
935     msg_data = stat_tap_get_field_data(table, idx, LAST_SEEN_COLUMN);
936     msg_data->type = TABLE_ITEM_FLOAT;
937     msg_data->value.float_value = MAX(msg_data->value.float_value, nstime_to_sec(&pinfo->rel_ts));
938     lastSeen = msg_data->value.float_value;
939     stat_tap_set_field_data(table, idx, LAST_SEEN_COLUMN, msg_data);
940   }
941 
942   if ((lastSeen - firstSeen) > 0.0) {
943     /* Update interval */
944     msg_data = stat_tap_get_field_data(table, idx, INTERVAL_COLUMN);
945     msg_data->type = TABLE_ITEM_FLOAT;
946     msg_data->value.float_value = lastSeen - firstSeen;
947     stat_tap_set_field_data(table, idx, INTERVAL_COLUMN, msg_data);
948 
949     /* Update message rate */
950     msg_data = stat_tap_get_field_data(table, idx, MESSAGE_RATE_COLUMN);
951     msg_data->type = TABLE_ITEM_FLOAT;
952     msg_data->value.float_value = messages / (lastSeen - firstSeen);
953     stat_tap_set_field_data(table, idx, MESSAGE_RATE_COLUMN, msg_data);
954 
955     /* Update byte rate */
956     msg_data = stat_tap_get_field_data(table, idx, BYTE_RATE_COLUMN);
957     msg_data->type = TABLE_ITEM_FLOAT;
958     msg_data->value.float_value = bytes / (lastSeen - firstSeen);
959     stat_tap_set_field_data(table, idx, BYTE_RATE_COLUMN, msg_data);
960   }
961 
962   return TAP_PACKET_REDRAW;
963 }
964 
965 static void
enrp_stat_reset(stat_tap_table * table)966 enrp_stat_reset(stat_tap_table* table)
967 {
968   guint element;
969   stat_tap_table_item_type* item_data;
970 
971   for (element = 0; element < table->num_elements; element++) {
972     item_data = stat_tap_get_field_data(table, element, MESSAGES_COLUMN);
973     item_data->value.uint_value = 0;
974     stat_tap_set_field_data(table, element, MESSAGES_COLUMN, item_data);
975 
976     item_data = stat_tap_get_field_data(table, element, MESSAGES_SHARE_COLUMN);
977     item_data->type = TABLE_ITEM_NONE;
978     item_data->value.float_value = -1.0;
979     stat_tap_set_field_data(table, element, MESSAGES_SHARE_COLUMN, item_data);
980 
981     item_data = stat_tap_get_field_data(table, element, BYTES_COLUMN);
982     item_data->value.uint_value = 0;
983     stat_tap_set_field_data(table, element, BYTES_COLUMN, item_data);
984 
985     item_data = stat_tap_get_field_data(table, element, BYTES_SHARE_COLUMN);
986     item_data->type = TABLE_ITEM_NONE;
987     item_data->value.float_value = -1.0;
988     stat_tap_set_field_data(table, element, BYTES_SHARE_COLUMN, item_data);
989 
990     item_data = stat_tap_get_field_data(table, element, FIRST_SEEN_COLUMN);
991     item_data->type = TABLE_ITEM_NONE;
992     item_data->value.float_value = DBL_MAX;
993     stat_tap_set_field_data(table, element, FIRST_SEEN_COLUMN, item_data);
994 
995     item_data = stat_tap_get_field_data(table, element, LAST_SEEN_COLUMN);
996     item_data->type = TABLE_ITEM_NONE;
997     item_data->value.float_value = DBL_MIN;
998     stat_tap_set_field_data(table, element, LAST_SEEN_COLUMN, item_data);
999 
1000     item_data = stat_tap_get_field_data(table, element, INTERVAL_COLUMN);
1001     item_data->type = TABLE_ITEM_NONE;
1002     item_data->value.float_value = -1.0;
1003     stat_tap_set_field_data(table, element, INTERVAL_COLUMN, item_data);
1004 
1005     item_data = stat_tap_get_field_data(table, element, MESSAGE_RATE_COLUMN);
1006     item_data->type = TABLE_ITEM_NONE;
1007     item_data->value.float_value = -1.0;
1008     stat_tap_set_field_data(table, element, MESSAGE_RATE_COLUMN, item_data);
1009 
1010     item_data = stat_tap_get_field_data(table, element, BYTE_RATE_COLUMN);
1011     item_data->type = TABLE_ITEM_NONE;
1012     item_data->value.float_value = -1.0;
1013     stat_tap_set_field_data(table, element, BYTE_RATE_COLUMN, item_data);
1014   }
1015   enrp_total_msgs  = 0;
1016   enrp_total_bytes = 0;
1017 }
1018 
1019 /* Register the protocol with Wireshark */
1020 void
proto_register_enrp(void)1021 proto_register_enrp(void)
1022 {
1023 
1024   /* Setup list of header fields */
1025   static hf_register_info hf[] = {
1026     { &hf_message_type,           { "Type",                        "enrp.message_type",                             FT_UINT8,   BASE_DEC,  VALS(message_type_values),         0x0,                        NULL, HFILL } },
1027     { &hf_message_flags,          { "Flags",                       "enrp.message_flags",                            FT_UINT8,   BASE_HEX,  NULL,                              0x0,                        NULL, HFILL } },
1028     { &hf_message_length,         { "Length",                      "enrp.message_length",                           FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1029     { &hf_message_value,          { "Value",                       "enrp.message_value",                            FT_BYTES,   BASE_NONE, NULL,                              0x0,                        NULL, HFILL } },
1030     { &hf_cause_code,             { "Cause Code",                  "enrp.cause_code",                               FT_UINT16,  BASE_HEX,  VALS(cause_code_values),           0x0,                        NULL, HFILL } },
1031     { &hf_cause_length,           { "Cause Length",                "enrp.cause_length",                             FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1032     { &hf_cause_info,             { "Cause Info",                  "enrp.cause_info",                               FT_BYTES,   BASE_NONE, NULL,                              0x0,                        NULL, HFILL } },
1033     { &hf_cause_padding,          { "Padding",                     "enrp.cause_padding",                            FT_BYTES,   BASE_NONE, NULL,                              0x0,                        NULL, HFILL } },
1034     { &hf_parameter_type,         { "Parameter Type",              "enrp.parameter_type",                           FT_UINT16,  BASE_HEX,  VALS(parameter_type_values),       0x0,                        NULL, HFILL } },
1035     { &hf_parameter_length,       { "Parameter Length",            "enrp.parameter_length",                         FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1036     { &hf_parameter_value,        { "Parameter Value",             "enrp.parameter_value",                          FT_BYTES,   BASE_NONE, NULL,                              0x0,                        NULL, HFILL } },
1037     { &hf_parameter_padding,      { "Padding",                     "enrp.parameter_padding",                        FT_BYTES,   BASE_NONE, NULL,                              0x0,                        NULL, HFILL } },
1038     { &hf_parameter_ipv4_address, { "IP Version 4 Address",        "enrp.ipv4_address",                             FT_IPv4,    BASE_NONE, NULL,                              0x0,                        NULL, HFILL } },
1039     { &hf_parameter_ipv6_address, { "IP Version 6 Address",        "enrp.ipv6_address",                             FT_IPv6,    BASE_NONE, NULL,                              0x0,                        NULL, HFILL } },
1040     { &hf_dccp_port,              { "Port",                        "enrp.dccp_transport_port",                      FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1041     { &hf_dccp_reserved,          { "Reserved",                    "enrp.dccp_transport_reserved",                  FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1042     { &hf_dccp_service_code,      { "Service Code",                "enrp.dccp_transport_service_code",              FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1043     { &hf_sctp_port,              { "Port",                        "enrp.sctp_transport_port",                      FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1044     { &hf_transport_use,          { "Transport Use",               "enrp.transport_use",                            FT_UINT16,  BASE_DEC,  VALS(transport_use_values),        0x0,                        NULL, HFILL } },
1045     { &hf_tcp_port,               { "Port",                        "enrp.tcp_transport_port",                       FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1046     { &hf_udp_port,               { "Port",                        "enrp.udp_transport_port",                       FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1047     { &hf_udp_reserved,           { "Reserved",                    "enrp.udp_transport_reserved",                   FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1048     { &hf_udp_lite_port,          { "Port",                        "enrp.udp_lite_transport_port",                  FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1049     { &hf_udp_lite_reserved,      { "Reserved",                    "enrp.udp_lite_transport_reserved",              FT_UINT16,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1050     { &hf_policy_type,            { "Policy Type",                 "enrp.pool_member_selection_policy_type",        FT_UINT32,  BASE_HEX,  VALS(policy_type_values),          0x0,                        NULL, HFILL } },
1051     { &hf_policy_weight,          { "Policy Weight",               "enrp.pool_member_selection_policy_weight",      FT_UINT32,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1052     { &hf_policy_priority,        { "Policy Priority",             "enrp.pool_member_selection_policy_priority",    FT_UINT32,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1053     { &hf_policy_load,            { "Policy Load",                 "enrp.pool_member_selection_policy_load",        FT_DOUBLE,  BASE_NONE,  NULL,                              0x0,                        NULL, HFILL } },
1054     { &hf_policy_degradation,     { "Policy Degradation",          "enrp.pool_member_selection_policy_degradation", FT_DOUBLE,  BASE_NONE,  NULL,                              0x0,                        NULL, HFILL } },
1055     { &hf_policy_loaddpf,         { "Policy Load DPF",             "enrp.pool_member_selection_policy_load_dpf",    FT_DOUBLE,  BASE_NONE,  NULL,                              0x0,                        NULL, HFILL } },
1056     { &hf_policy_weightdpf,       { "Policy Weight DPF",           "enrp.pool_member_selection_policy_weight_dpf",  FT_DOUBLE,  BASE_NONE,  NULL,                              0x0,                        NULL, HFILL } },
1057     { &hf_policy_distance,        { "Policy Distance",             "enrp.pool_member_selection_policy_distance",    FT_UINT32,  BASE_DEC,  NULL,                              0x0,                        NULL, HFILL } },
1058     { &hf_policy_value,           { "Policy Value",                "enrp.pool_member_selection_policy_value",       FT_BYTES,   BASE_NONE, NULL,                              0x0,                        NULL, HFILL } },
1059     { &hf_pool_handle,            { "Pool Handle",                 "enrp.pool_handle_pool_handle",                  FT_BYTES,   BASE_NONE,  NULL,                              0x0,                        NULL, HFILL } },
1060     { &hf_pe_pe_identifier,       { "PE Identifier",               "enrp.pool_element_pe_identifier",               FT_UINT32,  BASE_HEX,  NULL,                              0x0,                        NULL, HFILL } },
1061     { &hf_home_enrp_id,           { "Home ENRP Server Identifier", "enrp.pool_element_home_enrp_server_identifier", FT_UINT32,  BASE_HEX,  NULL,                              0x0,                        NULL, HFILL } },
1062     { &hf_reg_life,               { "Registration Life",           "enrp.pool_element_registration_life",           FT_INT32,   BASE_DEC|BASE_UNIT_STRING, &units_milliseconds, 0x0,                        NULL, HFILL } },
1063     { &hf_server_identifier,      { "Server Identifier",           "enrp.server_information_server_identifier",     FT_UINT32,  BASE_HEX,  NULL,                              0x0,                        NULL, HFILL } },
1064     { &hf_cookie,                 { "Cookie",                      "enrp.cookie",                                   FT_BYTES,   BASE_NONE,  NULL,                              0x0,                        NULL, HFILL } },
1065     { &hf_pe_identifier,          { "PE Identifier",               "enrp.pe_identifier",                            FT_UINT32,  BASE_HEX,  NULL,                              0x0,                        NULL, HFILL } },
1066     { &hf_pe_checksum,            { "PE Checksum",                 "enrp.pe_checksum",                              FT_UINT16,  BASE_HEX,  NULL,                              0x0,                        NULL, HFILL } },
1067     { &hf_sender_servers_id,      { "Sender Server's ID",          "enrp.sender_servers_id",                        FT_UINT32,  BASE_HEX,  NULL,                              0x0,                        NULL, HFILL } },
1068     { &hf_receiver_servers_id,    { "Receiver Server's ID",        "enrp.receiver_servers_id",                      FT_UINT32,  BASE_HEX,  NULL,                              0x0,                        NULL, HFILL } },
1069     { &hf_target_servers_id,      { "Target Server's ID",          "enrp.target_servers_id",                        FT_UINT32,  BASE_HEX,  NULL,                              0x0,                        NULL, HFILL } },
1070     { &hf_update_action,          { "Update Action",               "enrp.update_action",                            FT_UINT16,  BASE_DEC,  VALS(update_action_values),        0x0,                        NULL, HFILL } },
1071     { &hf_pmu_reserved,           { "Reserved",                    "enrp.reserved",                                 FT_UINT16,  BASE_HEX,  NULL,                              0x0,                        NULL, HFILL } },
1072     { &hf_reply_required_bit,     { "R Bit",                       "enrp.r_bit",                                    FT_BOOLEAN, 8,         TFS(&reply_required_bit_value),    REPLY_REQUIRED_BIT_MASK,    NULL, HFILL } },
1073     { &hf_own_children_only_bit,  { "W Bit",                       "enrp.w_bit",                                    FT_BOOLEAN, 8,         TFS(&own_children_only_bit_value), OWN_CHILDREN_ONLY_BIT_MASK, NULL, HFILL } },
1074     { &hf_more_to_send_bit,       { "M Bit",                       "enrp.m_bit",                                    FT_BOOLEAN, 8,         TFS(&more_to_send_bit_value),      MORE_TO_SEND_BIT_MASK,      NULL, HFILL } },
1075     { &hf_reject_bit,             { "R Bit",                       "enrp.r_bit",                                    FT_BOOLEAN, 8,         TFS(&reject_bit_value),            REJECT_BIT_MASK,            NULL, HFILL } },
1076     { &hf_tos_bit,                { "T Bit",                       "enrp.t_bit",                                    FT_BOOLEAN, 8,         TFS(&tos_bit_value),               TOS_BIT_MASK,               NULL, HFILL } },
1077   };
1078 
1079   /* Setup protocol subtree array */
1080   static gint *ett[] = {
1081     &ett_enrp,
1082     &ett_enrp_parameter,
1083     &ett_enrp_cause,
1084     &ett_enrp_flags,
1085   };
1086 
1087   static tap_param enrp_stat_params[] = {
1088     { PARAM_FILTER, "filter", "Filter", NULL, TRUE }
1089   };
1090 
1091   static stat_tap_table_ui enrp_stat_table = {
1092     REGISTER_STAT_GROUP_RSERPOOL,
1093     "ENRP Statistics",
1094     "enrp",
1095     "enrp,stat",
1096     enrp_stat_init,
1097     enrp_stat_packet,
1098     enrp_stat_reset,
1099     NULL,
1100     NULL,
1101     sizeof(enrp_stat_fields)/sizeof(stat_tap_table_item), enrp_stat_fields,
1102     sizeof(enrp_stat_params)/sizeof(tap_param), enrp_stat_params,
1103     NULL,
1104     0
1105   };
1106 
1107   /* Register the protocol name and description */
1108   proto_enrp = proto_register_protocol("Endpoint Handlespace Redundancy Protocol", "ENRP",  "enrp");
1109 
1110   /* Required function calls to register the header fields and subtrees used */
1111   proto_register_field_array(proto_enrp, hf, array_length(hf));
1112   proto_register_subtree_array(ett, array_length(ett));
1113   enrp_tap = register_tap("enrp");
1114 
1115   register_stat_tap_table_ui(&enrp_stat_table);
1116 }
1117 
1118 void
proto_reg_handoff_enrp(void)1119 proto_reg_handoff_enrp(void)
1120 {
1121   dissector_handle_t enrp_handle;
1122 
1123   enrp_handle = create_dissector_handle(dissect_enrp, proto_enrp);
1124   dissector_add_uint("sctp.ppi",  ENRP_PAYLOAD_PROTOCOL_ID, enrp_handle);
1125   dissector_add_uint("sctp.port", ENRP_SCTP_PORT,           enrp_handle);
1126   dissector_add_uint_with_preference("udp.port",  ENRP_UDP_PORT, enrp_handle);
1127 }
1128 
1129 /*
1130  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1131  *
1132  * Local Variables:
1133  * c-basic-offset: 2
1134  * tab-width: 8
1135  * indent-tabs-mode: nil
1136  * End:
1137  *
1138  * ex: set shiftwidth=2 tabstop=8 expandtab:
1139  * :indentSize=2:tabSize=8:noTabs=true:
1140  */
1141