3 * Routines for P_Mul (ACP142) packet disassembly.
4 * A protocol for reliable multicast messaging in bandwidth constrained
5 * and delayed acknowledgement (EMCON) environments.
7 * Copyright 2005, Stig Bjorlykke <stig@bjorlykke.org>, Thales Norway AS
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
15 * Ref: http://jcs.dtic.mil/j6/cceb/acps/acp142/
20 * - Obtain dedicated UDP port numbers
21 * - SEQ/ACK analysis for Announce/Request/Reject/Release PDU
27 #include <epan/packet.h>
28 #include <epan/prefs.h>
29 #include <epan/reassemble.h>
30 #include <epan/expert.h>
31 #include <epan/in_cksum.h>
32 #include <epan/proto_data.h>
34 #include <wsutil/array.h>
36 #include <wsutil/str_util.h>
38 #include "packet-cdt.h"
39 #include "packet-ber.h"
40 #include "packet-s5066sis.h"
42 void proto_register_p_mul(void);
43 void proto_reg_handoff_p_mul(void);
45 #define PNAME "P_Mul (ACP142)"
46 #define PSNAME "P_MUL"
47 #define PFNAME "p_mul"
49 /* Recommended UDP Port Numbers */
50 #define DEFAULT_P_MUL_PORT_RANGE ""
55 #define Address_PDU 0x02
56 #define Discard_Message_PDU 0x03
57 #define Announce_PDU 0x04
58 #define Request_PDU 0x05
59 #define Reject_PDU 0x06
60 #define Release_PDU 0x07
61 #define FEC_Address_PDU 0x08
62 #define Extra_Address_PDU 0x12
63 #define Extra_FEC_Address_PDU 0x18
64 #define Ack_Ack_PDU 0xFF /* Fake type to indicate Ack-Ack */
66 /* Type of content to decode from Data_PDU */
71 static int proto_p_mul
;
74 static int hf_priority
;
75 static int hf_map_first
;
76 static int hf_map_last
;
77 static int hf_map_unused
;
78 static int hf_pdu_type
;
79 static int hf_pdu_type_value
;
80 static int hf_no_pdus
;
82 static int hf_unused8
;
83 static int hf_unused16
;
84 static int hf_checksum
;
85 static int hf_checksum_good
;
86 static int hf_checksum_bad
;
87 static int hf_source_id_ack
;
88 static int hf_source_id
;
89 static int hf_message_id
;
90 static int hf_expiry_time
;
91 static int hf_mc_group
;
92 static int hf_ann_mc_group
;
93 static int hf_fec_len
;
95 static int hf_fec_parameters
;
96 static int hf_count_of_dest
;
97 static int hf_length_of_res
;
98 static int hf_ack_count
;
99 static int hf_ack_entry
;
100 static int hf_ack_length
;
101 static int hf_miss_seq_no
;
102 static int hf_miss_seq_range
;
103 static int hf_miss_seq_range_from
;
104 static int hf_miss_seq_range_delimiter
;
105 static int hf_miss_seq_range_to
;
106 static int hf_tot_miss_seq_no
;
107 static int hf_timestamp_option
;
108 static int hf_dest_entry
;
109 static int hf_dest_id
;
110 static int hf_msg_seq_no
;
111 static int hf_sym_key
;
112 static int hf_data_fragment
;
114 static int hf_msg_fragments
;
115 static int hf_msg_fragment
;
116 static int hf_msg_fragment_overlap
;
117 static int hf_msg_fragment_overlap_conflicts
;
118 static int hf_msg_fragment_multiple_tails
;
119 static int hf_msg_fragment_too_long_fragment
;
120 static int hf_msg_fragment_error
;
121 static int hf_msg_fragment_count
;
122 static int hf_msg_reassembled_in
;
123 static int hf_msg_reassembled_length
;
125 static int hf_analysis_ack_time
;
126 static int hf_analysis_trans_time
;
127 static int hf_analysis_retrans_time
;
128 static int hf_analysis_total_retrans_time
;
129 static int hf_analysis_last_pdu_num
;
130 static int hf_analysis_addr_pdu_num
;
131 static int hf_analysis_acks_addr_pdu_num
;
132 static int hf_analysis_acks_acked_addr_pdu_num
;
133 static int hf_analysis_addr_pdu_time
;
134 static int hf_analysis_prev_pdu_num
;
135 static int hf_analysis_prev_pdu_time
;
136 static int hf_analysis_retrans_no
;
137 static int hf_analysis_ack_num
;
138 static int hf_analysis_ack_missing
;
139 static int hf_analysis_ack_dup_no
;
140 static int hf_analysis_msg_resend_from
;
141 static int hf_analysis_ack_resend_from
;
142 static int hf_analysis_total_time
;
144 static int ett_p_mul
;
145 static int ett_pdu_type
;
146 static int ett_dest_entry
;
147 static int ett_ack_entry
;
148 static int ett_range_entry
;
149 static int ett_checksum
;
150 static int ett_seq_analysis
;
151 static int ett_ack_analysis
;
152 static int ett_seq_ack_analysis
;
153 static int ett_msg_fragment
;
154 static int ett_msg_fragments
;
156 static expert_field ei_more_data
;
157 static expert_field ei_checksum_bad
;
158 static expert_field ei_illegal_seq_no
;
159 static expert_field ei_tot_miss_seq_no
;
160 static expert_field ei_miss_seq_no
;
161 static expert_field ei_analysis_ack_missing
;
162 static expert_field ei_miss_seq_range
;
163 static expert_field ei_address_pdu_missing
;
164 static expert_field ei_analysis_ack_dup_no
;
165 static expert_field ei_length
;
166 static expert_field ei_analysis_prev_pdu_missing
;
167 static expert_field ei_message_discarded
;
168 static expert_field ei_ack_length
;
169 static expert_field ei_analysis_retrans_no
;
171 static dissector_handle_t p_mul_handle
;
173 typedef struct _p_mul_id_key
{
179 typedef struct _p_mul_seq_val
{
180 int msg_type
; /* Message type */
181 uint32_t prev_msg_id
; /* Previous message package num */
182 nstime_t prev_msg_time
; /* Previous message receive time */
183 uint32_t addr_id
; /* PDU package num for Address_PDU */
184 nstime_t addr_time
; /* PDU received time for Address_PDU */
185 uint32_t pdu_id
; /* PDU package num */
186 nstime_t pdu_time
; /* PDU receive time */
187 uint32_t prev_pdu_id
; /* Previous PDU package num */
188 nstime_t prev_pdu_time
; /* Previous PDU receive time */
189 uint16_t last_found_pdu
; /* Last PDU num */
190 nstime_t first_msg_time
; /* First message receive time */
191 uint32_t msg_resend_count
; /* Message resend counter */
192 wmem_map_t
*ack_data
;
195 typedef struct _p_mul_ack_data
{
196 uint32_t ack_id
; /* Ack PDU package num */
197 uint32_t ack_resend_count
; /* Ack resend counter */
200 /* Hash table with current data for seq/ack analysis */
201 static wmem_map_t
*p_mul_id_hash_table
;
203 /* User definable values to use for dissection */
204 static bool p_mul_reassemble
= true;
205 static int decode_option
= DECODE_NONE
;
206 static bool use_relative_msgid
= true;
207 static bool use_seq_ack_analysis
= true;
209 static reassembly_table p_mul_reassembly_table
;
211 static uint32_t message_id_offset
;
213 static const fragment_items p_mul_frag_items
= {
214 /* Fragment subtrees */
217 /* Fragment fields */
220 &hf_msg_fragment_overlap
,
221 &hf_msg_fragment_overlap_conflicts
,
222 &hf_msg_fragment_multiple_tails
,
223 &hf_msg_fragment_too_long_fragment
,
224 &hf_msg_fragment_error
,
225 &hf_msg_fragment_count
,
226 /* Reassembled in field */
227 &hf_msg_reassembled_in
,
228 /* Reassembled length field */
229 &hf_msg_reassembled_length
,
230 /* Reassembled data field */
236 static const value_string pdu_vals
[] = {
237 { Data_PDU
, "Data PDU" },
238 { Ack_PDU
, "Ack PDU" },
239 { Address_PDU
, "Address PDU" },
240 { Discard_Message_PDU
, "Discard Message PDU" },
241 { Announce_PDU
, "Announce PDU" },
242 { Request_PDU
, "Request PDU" },
243 { Reject_PDU
, "Reject PDU" },
244 { Release_PDU
, "Release PDU" },
245 { FEC_Address_PDU
, "FEC Address PDU" },
246 { Extra_Address_PDU
, "Extra Address PDU" },
247 { Extra_FEC_Address_PDU
, "Extra FEC Address PDU" },
248 { Ack_Ack_PDU
, "Ack-Ack PDU" },
252 static const enum_val_t decode_options
[] = {
253 { "none", "No decoding", DECODE_NONE
},
254 { "ber", "BER encoded ASN.1", DECODE_BER
},
255 { "cdt", "Compressed Data Type", DECODE_CDT
},
260 static const char *get_type (uint8_t value
)
262 return val_to_str_const (value
, pdu_vals
, "Unknown");
266 /* Function checksum, found in ACP 142 annex B04 (Fletcher algorithm) */
267 static uint16_t checksum_acp142 (uint8_t *buffer
, int len
, int offset
)
269 uint16_t c0
= 0, c1
= 0, ret
, ctmp
;
273 if (len
< offset
+2) {
274 /* Buffer too small */
278 ctmp
= len
- offset
- 1;
283 if ((c0
+= *hpp
++) > 254) { c0
-= 255; }
284 if ((c1
+= c0
) > 254) { c1
-= 255; }
287 if ((cs
= ((ctmp
* c0
) - c1
) % 255) < 0) { cs
+= 255; }
289 if ((cs
= (c1
- ((ctmp
+ 1L) * c0
)) % 255) < 0) { cs
+= 255; }
295 static unsigned p_mul_id_hash (const void *k
)
297 const p_mul_id_key
*p_mul
= (const p_mul_id_key
*)k
;
301 static int p_mul_id_hash_equal (const void *k1
, const void *k2
)
303 const p_mul_id_key
*p_mul1
= (const p_mul_id_key
*)k1
;
304 const p_mul_id_key
*p_mul2
= (const p_mul_id_key
*)k2
;
306 if (p_mul1
->id
!= p_mul2
->id
)
309 if (p_mul1
->seq
!= p_mul2
->seq
)
312 return (addresses_equal (&p_mul1
->addr
, &p_mul2
->addr
));
315 static p_mul_seq_val
*lookup_seq_val (uint32_t message_id
, uint16_t seq_no
,
318 p_mul_seq_val
*pkg_data
;
319 p_mul_id_key
*p_mul_key
= wmem_new(wmem_file_scope(), p_mul_id_key
);
321 p_mul_key
->id
= message_id
;
322 p_mul_key
->seq
= seq_no
;
323 copy_address_wmem(wmem_file_scope(), &p_mul_key
->addr
, addr
);
325 pkg_data
= (p_mul_seq_val
*) wmem_map_lookup (p_mul_id_hash_table
, p_mul_key
);
330 static void copy_hashtable_data (void *key
, void *value
, void *user_data
)
332 p_mul_ack_data
*ack_data1
= (p_mul_ack_data
*)value
;
333 p_mul_ack_data
*ack_data2
;
334 wmem_map_t
*table
= (wmem_map_t
*)user_data
;
336 ack_data2
= wmem_new(wmem_file_scope(), p_mul_ack_data
);
337 ack_data2
->ack_id
= ack_data1
->ack_id
;
338 ack_data2
->ack_resend_count
= ack_data1
->ack_resend_count
;
340 wmem_map_insert (table
, key
, ack_data2
);
343 static p_mul_seq_val
*register_p_mul_id (packet_info
*pinfo
, address
*addr
, uint32_t dstIP
,
344 uint8_t pdu_type
, uint32_t message_id
,
345 uint16_t seq_no
, int no_missing
)
347 p_mul_seq_val
*p_mul_data
= NULL
, *pkg_data
= NULL
;
348 p_mul_id_key
*p_mul_key
;
349 p_mul_ack_data
*ack_data
= NULL
;
350 nstime_t addr_time
, prev_time
;
351 unsigned addr_id
= 0, prev_id
= 0;
352 uint16_t last_found_pdu
= 0;
353 bool missing_pdu
= false, need_set_address
= false;
354 wmem_map_t
*pkg_list
;
356 if (pinfo
->flags
.in_error_pkt
) {
357 /* No analysis of error packets */
361 if (pdu_type
== Data_PDU
&& seq_no
== 0) {
362 /* Illegal sequence number for Data PDU */
366 nstime_set_zero(&addr_time
);
367 nstime_set_zero(&prev_time
);
369 p_mul_key
= wmem_new(wmem_file_scope(), p_mul_id_key
);
371 if (!pinfo
->fd
->visited
&&
372 (pdu_type
== Address_PDU
|| pdu_type
== Data_PDU
|| pdu_type
== Discard_Message_PDU
))
374 /* Try to match corresponding address PDU */
375 p_mul_key
->id
= message_id
;
377 copy_address_wmem(wmem_file_scope(), &p_mul_key
->addr
, addr
);
378 need_set_address
= true;
380 p_mul_data
= (p_mul_seq_val
*) wmem_map_lookup (p_mul_id_hash_table
, p_mul_key
);
383 /* Found address PDU */
384 last_found_pdu
= p_mul_data
->last_found_pdu
;
385 p_mul_data
->last_found_pdu
= seq_no
;
386 addr_id
= p_mul_data
->pdu_id
;
387 addr_time
= p_mul_data
->pdu_time
;
389 /* Save data for last found PDU */
390 p_mul_data
->prev_pdu_id
= pinfo
->num
;
391 p_mul_data
->prev_pdu_time
= pinfo
->abs_ts
;
393 if (pdu_type
== Data_PDU
&& p_mul_data
->msg_resend_count
== 0 && last_found_pdu
!= seq_no
- 1) {
394 /* Data_PDU and missing previous PDU */
398 if (last_found_pdu
) {
399 /* Try to match previous data PDU */
400 p_mul_key
->seq
= last_found_pdu
;
401 p_mul_data
= (p_mul_seq_val
*) wmem_map_lookup (p_mul_id_hash_table
, p_mul_key
);
405 /* Found a previous PDU (Address or Data) */
406 if (p_mul_data
->prev_msg_id
> 0) {
407 prev_id
= p_mul_data
->prev_msg_id
;
409 prev_id
= p_mul_data
->pdu_id
;
411 prev_time
= p_mul_data
->pdu_time
;
413 } else if (pdu_type
== Address_PDU
) {
414 addr_id
= pinfo
->num
;
415 addr_time
= pinfo
->abs_ts
;
419 pkg_list
= (wmem_map_t
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_p_mul
, 0);
421 /* Never saved list for this packet, create a new */
422 pkg_list
= wmem_map_new(wmem_file_scope(), g_direct_hash
, g_direct_equal
);
423 p_add_proto_data(wmem_file_scope(), pinfo
, proto_p_mul
, 0, pkg_list
);
426 if (!pinfo
->fd
->visited
) {
427 p_mul_key
->id
= message_id
;
428 p_mul_key
->seq
= seq_no
;
429 if (!need_set_address
) {
430 copy_address_wmem(wmem_file_scope(), &p_mul_key
->addr
, addr
);
432 p_mul_data
= (p_mul_seq_val
*) wmem_map_lookup (p_mul_id_hash_table
, p_mul_key
);
435 if (pdu_type
== Ack_PDU
) {
436 /* Only save this data if positive ack */
437 if (no_missing
== 0) {
438 ack_data
= (p_mul_ack_data
*)wmem_map_lookup (p_mul_data
->ack_data
, GUINT_TO_POINTER(dstIP
));
440 /* Only save reference to first ACK */
441 ack_data
= wmem_new0(wmem_file_scope(), p_mul_ack_data
);
442 ack_data
->ack_id
= pinfo
->num
;
443 wmem_map_insert (p_mul_data
->ack_data
, GUINT_TO_POINTER(dstIP
), ack_data
);
445 /* Only count when resending */
446 ack_data
->ack_resend_count
++;
451 p_mul_data
->msg_resend_count
++;
452 p_mul_data
->prev_msg_id
= pinfo
->num
;
453 p_mul_data
->prev_msg_time
= p_mul_data
->pdu_time
;
454 p_mul_data
->pdu_time
= pinfo
->abs_ts
;
456 if (pdu_type
== Data_PDU
) {
457 p_mul_data
->prev_pdu_id
= prev_id
;
458 p_mul_data
->prev_pdu_time
= prev_time
;
463 if (pdu_type
== Ack_PDU
) {
464 /* Data is just copied to the structure and never stored,
465 so keep a "more temporary" structure */
466 p_mul_data
= wmem_new0(pinfo
->pool
, p_mul_seq_val
);
468 p_mul_data
= wmem_new0(wmem_file_scope(), p_mul_seq_val
);
470 p_mul_data
->msg_type
= pdu_type
;
471 if (pdu_type
== Address_PDU
|| pdu_type
== Ack_PDU
) {
472 p_mul_data
->ack_data
= wmem_map_new(wmem_file_scope(), g_direct_hash
, g_direct_equal
);
475 if (pdu_type
== Ack_PDU
) {
476 /* No matching message for this ack */
477 ack_data
= wmem_new0(wmem_file_scope(), p_mul_ack_data
);
478 ack_data
->ack_id
= pinfo
->num
;
479 wmem_map_insert (p_mul_data
->ack_data
, GUINT_TO_POINTER(dstIP
), ack_data
);
481 p_mul_data
->pdu_id
= pinfo
->num
;
482 p_mul_data
->pdu_time
= pinfo
->abs_ts
;
483 p_mul_data
->addr_id
= addr_id
;
484 p_mul_data
->addr_time
= addr_time
;
485 p_mul_data
->first_msg_time
= pinfo
->abs_ts
;
487 if (pdu_type
== Data_PDU
&& !missing_pdu
) {
488 p_mul_data
->prev_pdu_id
= prev_id
;
489 p_mul_data
->prev_pdu_time
= prev_time
;
492 wmem_map_insert (p_mul_id_hash_table
, p_mul_key
, p_mul_data
);
496 /* Copy the current package data to the frame */
497 pkg_data
= wmem_new(wmem_file_scope(), p_mul_seq_val
);
498 *pkg_data
= *p_mul_data
;
499 if (p_mul_data
->ack_data
) {
500 /* Copy the hash table for ack data */
501 pkg_data
->ack_data
= wmem_map_new(wmem_file_scope(), g_direct_hash
, g_direct_equal
);
502 wmem_map_foreach (p_mul_data
->ack_data
, copy_hashtable_data
, pkg_data
->ack_data
);
504 wmem_map_insert(pkg_list
, GUINT_TO_POINTER(message_id
), pkg_data
);
506 /* Fetch last values from data saved in packet */
507 pkg_data
= (p_mul_seq_val
*)wmem_map_lookup (pkg_list
, GUINT_TO_POINTER(message_id
));
510 DISSECTOR_ASSERT (pkg_data
);
514 static void add_ack_analysis (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*p_mul_tree
,
515 int offset
, uint8_t pdu_type
, address
*src
, address
*dst
,
516 uint32_t message_id
, int no_missing
)
518 proto_tree
*analysis_tree
= NULL
;
519 proto_item
*sa
= NULL
;
520 proto_item
*en
= NULL
;
521 p_mul_seq_val
*pkg_data
= NULL
;
522 p_mul_ack_data
*ack_data
= NULL
;
523 bool item_added
= false;
527 if (pinfo
->flags
.in_error_pkt
) {
528 /* No analysis of error packets */
532 if (pdu_type
== Address_PDU
) {
533 analysis_tree
= proto_tree_add_subtree(p_mul_tree
, tvb
, 0, 0, ett_ack_analysis
, &sa
, "ACK analysis");
534 proto_item_set_generated (sa
);
536 /* Fetch package data */
537 if ((pkg_data
= lookup_seq_val (message_id
, 0, src
)) == NULL
) {
538 /* No need for seq/ack analysis yet */
544 if (pkg_data
->addr_id
) {
545 en
= proto_tree_add_uint (analysis_tree
, hf_analysis_acks_acked_addr_pdu_num
, tvb
,
546 0, 0, pkg_data
->addr_id
);
547 proto_item_set_generated (en
);
549 nstime_delta (&ns
, &pinfo
->abs_ts
, &pkg_data
->addr_time
);
550 en
= proto_tree_add_time (analysis_tree
, hf_analysis_total_time
,
552 proto_item_set_generated (en
);
554 proto_tree_add_expert(analysis_tree
, pinfo
, &ei_address_pdu_missing
, tvb
, offset
, 0);
558 memcpy((uint8_t *)&dstIp
, dst
->data
, 4);
559 if (pkg_data
->ack_data
) {
560 ack_data
= (p_mul_ack_data
*)wmem_map_lookup (pkg_data
->ack_data
, GUINT_TO_POINTER(dstIp
));
563 /* Add reference to Ack_PDU */
564 if (ack_data
&& ack_data
->ack_id
) {
565 en
= proto_tree_add_uint (analysis_tree
, hf_analysis_ack_num
, tvb
,
566 0, 0, ack_data
->ack_id
);
567 proto_item_set_generated (en
);
569 } else if (!pkg_data
->msg_resend_count
) {
570 en
= proto_tree_add_item (analysis_tree
,
571 hf_analysis_ack_missing
,
572 tvb
, offset
, 0, ENC_NA
);
573 if (pinfo
->fd
->visited
) {
574 /* We do not know this on first visit and we do not want to
575 add a entry in the "Expert Severity Info" for this note */
576 expert_add_info(pinfo
, en
, &ei_analysis_ack_missing
);
577 proto_item_set_generated (en
);
584 proto_item_set_hidden (sa
);
586 } else if (pdu_type
== Ack_PDU
) {
587 analysis_tree
= proto_tree_add_subtree(p_mul_tree
, tvb
, 0, 0, ett_seq_ack_analysis
, &sa
, "SEQ/ACK analysis");
588 proto_item_set_generated (sa
);
590 /* Fetch package data */
591 memcpy((uint8_t *)&dstIp
, dst
->data
, 4);
592 if ((pkg_data
= register_p_mul_id (pinfo
, src
, dstIp
, pdu_type
, message_id
, 0, no_missing
)) == NULL
) {
593 /* No need for seq/ack analysis yet */
596 if (pkg_data
->ack_data
) {
597 ack_data
= (p_mul_ack_data
*)wmem_map_lookup(pkg_data
->ack_data
, GUINT_TO_POINTER(dstIp
));
600 /* Add reference to Address_PDU */
601 if (pkg_data
->msg_type
!= Ack_PDU
) {
602 en
= proto_tree_add_uint (analysis_tree
, hf_analysis_acks_addr_pdu_num
, tvb
,
603 0, 0, pkg_data
->pdu_id
);
604 proto_item_set_generated (en
);
606 if (no_missing
== 0) {
607 nstime_delta (&ns
, &pinfo
->abs_ts
, &pkg_data
->first_msg_time
);
608 en
= proto_tree_add_time (analysis_tree
, hf_analysis_trans_time
,
610 proto_item_set_generated (en
);
613 proto_tree_add_expert(analysis_tree
, pinfo
, &ei_address_pdu_missing
, tvb
, offset
, 0);
616 if (pkg_data
->msg_type
!= Ack_PDU
&& pkg_data
->prev_pdu_id
) {
617 /* Add reference to previous PDU */
618 en
= proto_tree_add_uint (analysis_tree
, hf_analysis_last_pdu_num
,
619 tvb
, 0, 0, pkg_data
->prev_pdu_id
);
620 proto_item_set_generated (en
);
622 nstime_delta (&ns
, &pinfo
->abs_ts
, &pkg_data
->prev_pdu_time
);
623 en
= proto_tree_add_time (analysis_tree
, hf_analysis_ack_time
,
625 proto_item_set_generated (en
);
628 if (ack_data
&& ack_data
->ack_resend_count
) {
629 /* Add resend statistics */
630 en
= proto_tree_add_uint (analysis_tree
, hf_analysis_ack_dup_no
,
631 tvb
, 0, 0, ack_data
->ack_resend_count
);
632 proto_item_set_generated (en
);
634 expert_add_info_format(pinfo
, en
, &ei_analysis_ack_dup_no
, "Dup ACK #%d", ack_data
->ack_resend_count
);
636 en
= proto_tree_add_uint (analysis_tree
, hf_analysis_ack_resend_from
,
637 tvb
, 0, 0, ack_data
->ack_id
);
638 proto_item_set_generated (en
);
640 col_append_fstr (pinfo
->cinfo
, COL_INFO
, "[Dup ACK %d#%d] ",
641 ack_data
->ack_id
, ack_data
->ack_resend_count
);
646 static p_mul_seq_val
*add_seq_analysis (tvbuff_t
*tvb
, packet_info
*pinfo
,
647 proto_tree
*p_mul_tree
, address
*src
,
649 uint8_t pdu_type
, uint32_t message_id
,
650 uint16_t seq_no
, int no_missing
)
652 p_mul_seq_val
*pkg_data
;
653 proto_tree
*analysis_tree
;
654 proto_item
*sa
, *en
= NULL
, *eh
= NULL
;
655 bool item_added
= false;
658 pkg_data
= register_p_mul_id (pinfo
, src
, 0, pdu_type
, message_id
, seq_no
,
662 /* No need for seq/ack analysis */
666 analysis_tree
= proto_tree_add_subtree(p_mul_tree
, tvb
, 0, 0, ett_seq_analysis
, &sa
, "SEQ analysis");
667 proto_item_set_generated (sa
);
669 if (pdu_type
== Data_PDU
|| pdu_type
== Discard_Message_PDU
) {
670 /* Add reference to Address_PDU */
671 if (pkg_data
->addr_id
) {
672 en
= proto_tree_add_uint (analysis_tree
, hf_analysis_addr_pdu_num
, tvb
,
673 0, 0, pkg_data
->addr_id
);
674 proto_item_set_generated (en
);
676 nstime_delta (&ns
, &pinfo
->abs_ts
, &pkg_data
->addr_time
);
677 en
= proto_tree_add_time (analysis_tree
, hf_analysis_addr_pdu_time
,
679 proto_item_set_generated (en
);
681 if (pkg_data
->prev_pdu_id
== pkg_data
->addr_id
) {
682 /* Previous pdu time is the same as time since address pdu */
683 en
= proto_tree_add_time (analysis_tree
, hf_analysis_prev_pdu_time
,
685 proto_item_set_generated (en
);
688 } else if (!pkg_data
->msg_resend_count
) {
689 proto_tree_add_expert(analysis_tree
, pinfo
, &ei_address_pdu_missing
, tvb
, offset
, 0);
694 if ((pdu_type
== Data_PDU
) && (pkg_data
->prev_pdu_id
!= pkg_data
->addr_id
)) {
695 /* Add reference to previous Data_PDU */
696 if (pkg_data
->prev_pdu_id
) {
697 en
= proto_tree_add_uint (analysis_tree
, hf_analysis_prev_pdu_num
, tvb
,
698 0, 0, pkg_data
->prev_pdu_id
);
699 proto_item_set_generated (en
);
701 nstime_delta (&ns
, &pinfo
->abs_ts
, &pkg_data
->prev_pdu_time
);
702 en
= proto_tree_add_time (analysis_tree
, hf_analysis_prev_pdu_time
,
704 proto_item_set_generated (en
);
706 } else if (!pkg_data
->msg_resend_count
) {
707 proto_tree_add_expert(analysis_tree
, pinfo
, &ei_analysis_prev_pdu_missing
, tvb
, offset
, 0);
712 if ((pdu_type
== Address_PDU
) || (pdu_type
== Data_PDU
) ||
713 (pdu_type
== Discard_Message_PDU
)) {
714 /* Add resend statistics */
715 if (pkg_data
->msg_resend_count
) {
716 en
= proto_tree_add_uint (analysis_tree
, hf_analysis_retrans_no
,
717 tvb
, 0, 0, pkg_data
->msg_resend_count
);
718 proto_item_set_generated (en
);
720 en
= proto_tree_add_uint (analysis_tree
, hf_analysis_msg_resend_from
,
721 tvb
, 0, 0, pkg_data
->pdu_id
);
722 proto_item_set_generated (en
);
724 expert_add_info_format(pinfo
, en
, &ei_analysis_retrans_no
, "Retransmission #%d", pkg_data
->msg_resend_count
);
726 nstime_delta (&ns
, &pinfo
->abs_ts
, &pkg_data
->prev_msg_time
);
727 en
= proto_tree_add_time (analysis_tree
, hf_analysis_retrans_time
,
729 proto_item_set_generated (en
);
731 nstime_delta (&ns
, &pinfo
->abs_ts
, &pkg_data
->first_msg_time
);
732 eh
= proto_tree_add_time (analysis_tree
, hf_analysis_total_retrans_time
,
734 proto_item_set_generated (eh
);
736 if (pkg_data
->first_msg_time
.secs
== pkg_data
->prev_msg_time
.secs
&&
737 pkg_data
->first_msg_time
.nsecs
== pkg_data
->prev_msg_time
.nsecs
) {
738 /* Time values does not differ, hide the total time */
739 proto_item_set_hidden (eh
);
743 col_append_fstr (pinfo
->cinfo
, COL_INFO
, "[Retrans %d#%d] ",
744 pkg_data
->pdu_id
, pkg_data
->msg_resend_count
);
749 proto_item_set_hidden (sa
);
756 static void dissect_reassembled_data (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
758 DISSECTOR_ASSERT(tvb
!= NULL
);
760 switch (decode_option
) {
762 dissect_unknown_ber (pinfo
, tvb
, 0, tree
);
765 dissect_cdt (tvb
, pinfo
, tree
);
768 call_data_dissector(tvb
, pinfo
, tree
);
773 static int dissect_p_mul (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
775 proto_tree
*p_mul_tree
, *field_tree
, *checksum_tree
;
776 proto_item
*ti
, *en
, *len_en
;
777 bool save_fragmented
;
778 uint32_t message_id
= 0;
779 uint16_t no_dest
= 0, count
= 0, len
, data_len
= 0;
780 uint16_t checksum_calc
, checksum_found
;
781 uint16_t pdu_length
, no_pdus
= 0, seq_no
= 0;
782 uint8_t pdu_type
, *value
, map
= 0, fec_len
;
783 int i
, tot_no_missing
= 0, no_missing
= 0, offset
= 0;
785 wmem_strbuf_t
*message_id_list
= NULL
;
786 bool fletcher
= false;
788 col_set_str (pinfo
->cinfo
, COL_PROTOCOL
, "P_MUL");
789 col_clear (pinfo
->cinfo
, COL_INFO
);
791 /* First fetch PDU Type */
792 pdu_type
= tvb_get_uint8 (tvb
, offset
+ 3) & 0x3F;
794 ti
= proto_tree_add_item (tree
, proto_p_mul
, tvb
, offset
, -1, ENC_NA
);
795 proto_item_append_text (ti
, ", %s", get_type (pdu_type
));
796 p_mul_tree
= proto_item_add_subtree (ti
, ett_p_mul
);
799 pdu_length
= tvb_get_ntohs (tvb
, offset
);
800 len_en
= proto_tree_add_item (p_mul_tree
, hf_length
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
808 case Discard_Message_PDU
:
809 case Extra_Address_PDU
:
810 case FEC_Address_PDU
:
811 case Extra_FEC_Address_PDU
:
813 proto_tree_add_item (p_mul_tree
, hf_priority
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
818 proto_tree_add_item (p_mul_tree
, hf_unused8
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
823 en
= proto_tree_add_uint_format (p_mul_tree
, hf_pdu_type
, tvb
, offset
, 1,
824 pdu_type
, "PDU Type: %s (0x%02x)",
825 get_type (pdu_type
), pdu_type
);
826 field_tree
= proto_item_add_subtree (en
, ett_pdu_type
);
828 if (pdu_type
== Discard_Message_PDU
) {
829 expert_add_info(pinfo
, en
, &ei_message_discarded
);
836 case Extra_Address_PDU
:
837 case FEC_Address_PDU
:
838 case Extra_FEC_Address_PDU
:
839 map
= tvb_get_uint8 (tvb
, offset
);
840 proto_tree_add_item (field_tree
, hf_map_first
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
841 proto_tree_add_item (field_tree
, hf_map_last
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
842 if ((map
& 0x80) || (map
& 0x40)) {
843 proto_item_append_text (en
, ", %s / %s",
844 (map
& 0x80) ? "Not first" : "First",
845 (map
& 0x40) ? "Not last" : "Last");
847 proto_item_append_text (en
, ", Only one PDU");
852 proto_tree_add_item (field_tree
, hf_map_unused
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
855 proto_tree_add_item (field_tree
, hf_pdu_type_value
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
861 case Extra_Address_PDU
:
862 case FEC_Address_PDU
:
863 case Extra_FEC_Address_PDU
:
864 /* Total Number of PDUs */
865 no_pdus
= tvb_get_ntohs (tvb
, offset
);
867 proto_tree_add_item (p_mul_tree
, hf_no_pdus
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
868 proto_item_append_text (ti
, ", No PDUs: %u", no_pdus
);
872 /* Sequence Number of PDUs */
873 seq_no
= tvb_get_ntohs (tvb
, offset
);
874 en
= proto_tree_add_item (p_mul_tree
, hf_seq_no
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
876 expert_add_info(pinfo
, en
, &ei_illegal_seq_no
);
878 proto_item_append_text (ti
, ", Seq no: %u", seq_no
);
882 /* Count of Destination Entries */
883 count
= tvb_get_ntohs (tvb
, offset
);
884 proto_tree_add_item (p_mul_tree
, hf_count_of_dest
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
889 proto_tree_add_item (p_mul_tree
, hf_unused16
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
895 en
= proto_tree_add_item (p_mul_tree
, hf_checksum
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
896 checksum_tree
= proto_item_add_subtree (en
, ett_checksum
);
897 len
= tvb_captured_length (tvb
);
898 value
= (uint8_t *)tvb_memdup (pinfo
->pool
, tvb
, 0, len
);
899 if (len
>= offset
+2) {
903 checksum_found
= tvb_get_ntohs (tvb
, offset
);
904 /* This computed IP checksum is network-byte-order, so convert to host-byte-order */
905 checksum_calc
= g_ntohs (ip_checksum (value
, len
));
906 if (checksum_calc
!= checksum_found
) {
907 uint16_t checksum1
= checksum_acp142 (value
, len
, offset
);
908 if (checksum1
== checksum_found
) {
909 checksum_calc
= checksum1
;
913 if (checksum_calc
== checksum_found
) {
915 proto_item_append_text (en
, " [Fletcher algorithm]");
917 proto_item_append_text (en
, " (correct)");
918 en
= proto_tree_add_boolean (checksum_tree
, hf_checksum_good
, tvb
,
920 proto_item_set_generated (en
);
921 en
= proto_tree_add_boolean (checksum_tree
, hf_checksum_bad
, tvb
,
923 proto_item_set_generated (en
);
925 proto_item_append_text (en
, " (incorrect, should be 0x%04x)", checksum_calc
);
926 expert_add_info(pinfo
, en
, &ei_checksum_bad
);
927 en
= proto_tree_add_boolean (checksum_tree
, hf_checksum_good
, tvb
,
929 proto_item_set_generated (en
);
930 en
= proto_tree_add_boolean (checksum_tree
, hf_checksum_bad
, tvb
,
932 proto_item_set_generated (en
);
936 if (pdu_type
== Ack_PDU
) {
937 /* Source ID of Ack Sender */
938 set_address_tvb (&dst
, AT_IPv4
, 4, tvb
, offset
);
939 proto_tree_add_item (p_mul_tree
, hf_source_id_ack
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
942 /* Count of Ack Info Entries */
943 count
= tvb_get_ntohs (tvb
, offset
);
944 proto_tree_add_item (p_mul_tree
, hf_ack_count
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
948 set_address_tvb (&src
, AT_IPv4
, 4, tvb
, offset
);
949 proto_tree_add_item (p_mul_tree
, hf_source_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
953 message_id
= tvb_get_ntohl (tvb
, offset
);
954 if (use_relative_msgid
) {
955 if (message_id_offset
== 0) {
956 /* First P_Mul package - initialize message_id_offset */
957 message_id_offset
= message_id
;
959 message_id
-= message_id_offset
;
960 proto_tree_add_uint_format_value(p_mul_tree
, hf_message_id
, tvb
, offset
, 4,
961 message_id
, "%u (relative message id)", message_id
);
963 proto_tree_add_item (p_mul_tree
, hf_message_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
967 proto_item_append_text (ti
, ", MSID: %u", message_id
);
970 if (pdu_type
== Address_PDU
|| pdu_type
== Announce_PDU
||
971 pdu_type
== Extra_Address_PDU
|| pdu_type
== FEC_Address_PDU
||
972 pdu_type
== Extra_FEC_Address_PDU
) {
974 proto_tree_add_item (p_mul_tree
, hf_expiry_time
, tvb
, offset
, 4, ENC_TIME_SECS
|ENC_BIG_ENDIAN
);
978 if (pdu_type
== FEC_Address_PDU
|| pdu_type
== Extra_FEC_Address_PDU
) {
979 /* FEC Parameters Length */
980 fec_len
= tvb_get_uint8 (tvb
, offset
);
981 proto_tree_add_item (p_mul_tree
, hf_fec_len
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
985 proto_tree_add_item (p_mul_tree
, hf_fec_id
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
990 proto_tree_add_none_format (p_mul_tree
, hf_fec_parameters
, tvb
, offset
,
991 fec_len
, "FEC Parameters (%d byte%s)",
992 fec_len
, plurality (fec_len
, "", "s"));
1000 case Extra_Address_PDU
:
1001 case FEC_Address_PDU
:
1002 case Extra_FEC_Address_PDU
:
1003 /* Count of Destination Entries */
1004 no_dest
= tvb_get_ntohs (tvb
, offset
);
1005 proto_tree_add_item (p_mul_tree
, hf_count_of_dest
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1008 /* Length of Reserved Field */
1009 len
= tvb_get_ntohs (tvb
, offset
);
1010 proto_tree_add_item (p_mul_tree
, hf_length_of_res
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1013 for (i
= 0; i
< no_dest
; i
++) {
1014 /* Destination Entry */
1015 en
= proto_tree_add_none_format (p_mul_tree
, hf_dest_entry
, tvb
,
1017 "Destination Entry #%d", i
+ 1);
1018 field_tree
= proto_item_add_subtree (en
, ett_dest_entry
);
1020 /* Destination Id */
1021 set_address_tvb (&dst
, AT_IPv4
, 4, tvb
, offset
);
1022 proto_tree_add_item (field_tree
, hf_dest_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1025 /* Message Sequence Number */
1026 proto_tree_add_item (field_tree
, hf_msg_seq_no
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1030 /* Reserved Field (variable length) */
1031 proto_tree_add_none_format (field_tree
, hf_sym_key
, tvb
, offset
,
1032 len
, "Symmetric Key (%d byte%s)",
1033 len
, plurality (len
, "", "s"));
1037 if (use_seq_ack_analysis
) {
1038 add_ack_analysis (tvb
, pinfo
, field_tree
, offset
, pdu_type
, &src
, &dst
,
1042 if (no_dest
== 0 && use_seq_ack_analysis
) {
1043 /* Add Ack-Ack analysis */
1044 add_ack_analysis (tvb
, pinfo
, p_mul_tree
, offset
, pdu_type
, &src
, NULL
,
1048 proto_item_append_text (ti
, ", Count of Dest: %u", no_dest
);
1052 /* Fragment of Data (variable length) */
1053 data_len
= tvb_captured_length_remaining (tvb
, offset
);
1054 proto_tree_add_none_format (p_mul_tree
, hf_data_fragment
, tvb
, offset
,
1055 data_len
, "Fragment %d of Data (%d byte%s)",
1057 plurality (data_len
, "", "s"));
1061 message_id_list
= wmem_strbuf_create(pinfo
->pool
);
1063 for (i
= 0; i
< count
; i
++) {
1064 /* Ack Info Entry */
1065 len
= tvb_get_ntohs (tvb
, offset
);
1067 en
= proto_tree_add_none_format (p_mul_tree
, hf_ack_entry
, tvb
,
1069 "Ack Info Entry #%d", i
+ 1);
1070 field_tree
= proto_item_add_subtree (en
, ett_ack_entry
);
1072 /* Length of Ack Info Entry */
1073 en
= proto_tree_add_item (field_tree
, hf_ack_length
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1077 proto_item_append_text (en
, " (invalid length)");
1078 expert_add_info(pinfo
, en
, &ei_ack_length
);
1082 set_address_tvb (&src
, AT_IPv4
, 4, tvb
, offset
);
1083 proto_tree_add_item (field_tree
, hf_source_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1087 message_id
= tvb_get_ntohl (tvb
, offset
);
1088 if (use_relative_msgid
) {
1089 if (message_id_offset
== 0) {
1090 /* First P_Mul package - initialize message_id_offset */
1091 message_id_offset
= message_id
;
1093 message_id
-= message_id_offset
;
1094 proto_tree_add_uint_format_value(field_tree
, hf_message_id
, tvb
, offset
, 4,
1095 message_id
, "%u (relative message id)", message_id
);
1097 proto_tree_add_item (field_tree
, hf_message_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1102 wmem_strbuf_append_printf (message_id_list
, "%u", message_id
);
1104 wmem_strbuf_append_printf (message_id_list
, ",%u", message_id
);
1108 int num_seq_no
= (len
- 10) / 2;
1109 uint16_t ack_seq_no
, prev_ack_seq_no
= 0;
1110 for (no_missing
= 0; no_missing
< num_seq_no
; no_missing
++) {
1111 /* Missing Data PDU Seq Number */
1112 ack_seq_no
= tvb_get_ntohs (tvb
, offset
);
1113 if ((ack_seq_no
!= 0) && (no_missing
< num_seq_no
- 2) && tvb_get_ntohs (tvb
, offset
+ 2) == 0) {
1114 /* We are handling a range */
1115 uint16_t end_seq_no
= tvb_get_ntohs (tvb
, offset
+ 4);
1117 en
= proto_tree_add_bytes_format_value(field_tree
, hf_miss_seq_range
,
1118 tvb
, offset
, 6, NULL
,
1120 ack_seq_no
, end_seq_no
);
1121 if (ack_seq_no
>= end_seq_no
) {
1122 proto_item_append_text (en
, " (invalid)");
1123 expert_add_info(pinfo
, en
, &ei_miss_seq_range
);
1125 proto_tree
*missing_tree
= proto_item_add_subtree (en
, ett_range_entry
);
1127 proto_tree_add_item (missing_tree
, hf_miss_seq_range_from
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1128 proto_tree_add_item (missing_tree
, hf_miss_seq_range_delimiter
, tvb
, offset
+ 2, 2, ENC_BIG_ENDIAN
);
1129 proto_tree_add_item (missing_tree
, hf_miss_seq_range_to
, tvb
, offset
+ 4, 2, ENC_BIG_ENDIAN
);
1131 tot_no_missing
+= (end_seq_no
- ack_seq_no
+ 1);
1135 no_missing
+= 2; /* Skip the next two */
1136 prev_ack_seq_no
= end_seq_no
;
1138 /* No range, handle one seq no */
1139 en
= proto_tree_add_item (field_tree
, hf_miss_seq_no
, tvb
,offset
, 2, ENC_BIG_ENDIAN
);
1142 if (ack_seq_no
== 0) {
1143 proto_item_append_text (en
, " (invalid)");
1144 expert_add_info(pinfo
, en
, &ei_miss_seq_no
);
1145 } else if (ack_seq_no
<= prev_ack_seq_no
) {
1146 proto_item_append_text (en
, " (end of list indicator)");
1150 prev_ack_seq_no
= ack_seq_no
;
1155 if (use_seq_ack_analysis
) {
1156 add_ack_analysis (tvb
, pinfo
, field_tree
, offset
, pdu_type
, &src
, &dst
,
1157 message_id
, no_missing
);
1160 proto_item_append_text (ti
, ", Count of Ack: %u", count
);
1162 if (tvb_reported_length_remaining (tvb
, offset
) >= 8) {
1163 /* Timestamp Option (in units of 100ms) */
1166 timestamp
= tvb_get_ntoh64 (tvb
, offset
);
1167 proto_tree_add_uint64_format_value(p_mul_tree
, hf_timestamp_option
, tvb
,
1168 offset
, 8, timestamp
,
1169 "%" PRId64
".%d second%s (%" PRIu64
")",
1170 timestamp
/ 10, (int) timestamp
% 10,
1171 (timestamp
== 10) ? "" : "s", timestamp
);
1175 if (tot_no_missing
) {
1176 proto_item_append_text (ti
, ", Missing seq numbers: %u", tot_no_missing
);
1177 en
= proto_tree_add_uint (p_mul_tree
, hf_tot_miss_seq_no
, tvb
, 0, 0,
1179 proto_item_set_generated (en
);
1180 expert_add_info_format(pinfo
, en
, &ei_tot_miss_seq_no
, "Missing seq numbers: %d", tot_no_missing
);
1184 case Discard_Message_PDU
:
1185 seq_no
= UINT16_MAX
; /* To make the seq_no uniq */
1189 /* Announced Multicast Group */
1190 proto_tree_add_item (p_mul_tree
, hf_ann_mc_group
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1193 for (i
= 0; i
< count
; i
++) {
1194 /* Destination Id */
1195 proto_tree_add_item (p_mul_tree
, hf_dest_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1203 /* Multicast Group */
1204 proto_tree_add_item (p_mul_tree
, hf_mc_group
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1213 /* Add SEQ/ACK analysis entry */
1214 if (use_seq_ack_analysis
&& (pdu_type
<= Discard_Message_PDU
) &&
1215 (pdu_type
!= Ack_PDU
) && (pdu_type
!= Address_PDU
|| no_dest
!= 0))
1217 add_seq_analysis (tvb
, pinfo
, p_mul_tree
, &src
, offset
, pdu_type
,
1218 message_id
, seq_no
, tot_no_missing
);
1221 /* Check if printing Ack-Ack */
1222 if (pdu_type
== Address_PDU
&& no_dest
== 0) {
1223 col_append_str (pinfo
->cinfo
, COL_INFO
, get_type (Ack_Ack_PDU
));
1225 col_append_str (pinfo
->cinfo
, COL_INFO
, get_type (pdu_type
));
1227 if (pdu_type
== Address_PDU
|| pdu_type
== Extra_Address_PDU
||
1228 pdu_type
== FEC_Address_PDU
|| pdu_type
== Extra_FEC_Address_PDU
) {
1229 col_append_fstr (pinfo
->cinfo
, COL_INFO
, ", No PDUs: %u", no_pdus
);
1230 } else if (pdu_type
== Data_PDU
) {
1231 col_append_fstr (pinfo
->cinfo
, COL_INFO
, ", Seq no: %u", seq_no
);
1233 if (pdu_type
== Address_PDU
|| pdu_type
== Extra_Address_PDU
||
1234 pdu_type
== FEC_Address_PDU
|| pdu_type
== Extra_FEC_Address_PDU
) {
1236 col_append_fstr (pinfo
->cinfo
, COL_INFO
, ", Count of Dest: %u", no_dest
);
1238 } else if (pdu_type
== Ack_PDU
) {
1239 if (tot_no_missing
) {
1240 col_append_fstr (pinfo
->cinfo
, COL_INFO
, ", Missing seq numbers: %u",
1243 col_append_fstr (pinfo
->cinfo
, COL_INFO
, ", Count of Ack: %u", count
);
1245 if (pdu_type
!= Ack_PDU
) {
1246 col_append_fstr (pinfo
->cinfo
, COL_INFO
, ", MSID: %u", message_id
);
1248 if (message_id_list
&& wmem_strbuf_get_len(message_id_list
) > 0) {
1249 col_append_fstr (pinfo
->cinfo
, COL_INFO
, ", MSID: %s", wmem_strbuf_get_str(message_id_list
));
1253 if (p_mul_reassemble
) {
1254 save_fragmented
= pinfo
->fragmented
;
1256 if (pdu_type
== Address_PDU
&& no_pdus
> 0) {
1257 /* Start fragment table */
1258 fragment_start_seq_check (&p_mul_reassembly_table
,
1259 pinfo
, message_id
, NULL
, no_pdus
- 1);
1260 } else if (pdu_type
== Data_PDU
) {
1261 fragment_head
*frag_msg
;
1264 pinfo
->fragmented
= true;
1266 /* Add fragment to fragment table */
1267 frag_msg
= fragment_add_seq_check (&p_mul_reassembly_table
,
1268 tvb
, offset
, pinfo
, message_id
, NULL
,
1269 seq_no
- 1, data_len
, true);
1270 new_tvb
= process_reassembled_data (tvb
, offset
, pinfo
,
1271 "Reassembled P_MUL", frag_msg
,
1272 &p_mul_frag_items
, NULL
, tree
);
1275 col_append_str (pinfo
->cinfo
, COL_INFO
, " (Message Reassembled)");
1278 dissect_reassembled_data (new_tvb
, pinfo
, tree
);
1282 pinfo
->fragmented
= save_fragmented
;
1285 /* Update length of P_Mul packet and check length values */
1286 proto_item_set_len (ti
, offset
);
1287 if (pdu_length
!= (offset
+ data_len
)) {
1288 proto_item_append_text (len_en
, " (incorrect, should be: %d)",
1290 expert_add_info(pinfo
, len_en
, &ei_length
);
1291 } else if ((len
= tvb_reported_length_remaining (tvb
, pdu_length
)) > 0) {
1292 proto_item_append_text (len_en
, " (more data in packet: %d)", len
);
1293 expert_add_info(pinfo
, len_en
, &ei_more_data
);
1299 static void p_mul_init_routine (void)
1301 message_id_offset
= 0;
1304 void proto_register_p_mul (void)
1306 static hf_register_info hf
[] = {
1308 { "Length of PDU", "p_mul.length", FT_UINT16
, BASE_DEC
,
1309 NULL
, 0x0, NULL
, HFILL
} },
1311 { "Priority", "p_mul.priority", FT_UINT8
, BASE_DEC
,
1312 NULL
, 0x0, NULL
, HFILL
} },
1314 { "First", "p_mul.first", FT_BOOLEAN
, 8,
1315 TFS (&tfs_no_yes
), 0x80, NULL
, HFILL
} },
1317 { "Last", "p_mul.last", FT_BOOLEAN
, 8,
1318 TFS (&tfs_no_yes
), 0x40, NULL
, HFILL
} },
1320 { "MAP unused", "p_mul.unused", FT_UINT8
, BASE_DEC
,
1321 NULL
, 0xC0, NULL
, HFILL
} },
1323 { "PDU Type", "p_mul.pdu_type", FT_UINT8
, BASE_DEC
,
1324 VALS (pdu_vals
), 0x3F, NULL
, HFILL
} },
1325 { &hf_pdu_type_value
,
1326 { "PDU Type", "p_mul.pdu_type_value", FT_UINT8
, BASE_DEC
,
1327 VALS (pdu_vals
), 0x3F, NULL
, HFILL
} },
1329 { "Total Number of PDUs", "p_mul.no_pdus", FT_UINT16
, BASE_DEC
,
1330 NULL
, 0x0, NULL
, HFILL
} },
1332 { "Sequence Number of PDUs", "p_mul.seq_no", FT_UINT16
, BASE_DEC
,
1333 NULL
, 0x0, NULL
, HFILL
} },
1335 { "Unused", "p_mul.unused", FT_UINT8
, BASE_DEC
,
1336 NULL
, 0x0, NULL
, HFILL
} },
1338 { "Unused", "p_mul.unused", FT_UINT16
, BASE_DEC
,
1339 NULL
, 0x0, NULL
, HFILL
} },
1341 { "Checksum", "p_mul.checksum", FT_UINT16
, BASE_HEX
,
1342 NULL
, 0x0, NULL
, HFILL
} },
1343 { &hf_checksum_good
,
1344 { "Good", "p_mul.checksum_good", FT_BOOLEAN
, BASE_NONE
,
1345 NULL
, 0x0, "True: checksum matches packet content; False: doesn't match content or not checked", HFILL
} },
1347 { "Bad", "p_mul.checksum_bad", FT_BOOLEAN
, BASE_NONE
,
1348 NULL
, 0x0, "True: checksum doesn't match packet content; False: matches content or not checked", HFILL
} },
1349 { &hf_source_id_ack
,
1350 { "Source ID of Ack Sender", "p_mul.source_id_ack", FT_IPv4
, BASE_NONE
,
1351 NULL
, 0x0, NULL
, HFILL
} },
1353 { "Source ID", "p_mul.source_id", FT_IPv4
, BASE_NONE
,
1354 NULL
, 0x0, NULL
, HFILL
} },
1356 { "Message ID (MSID)", "p_mul.message_id", FT_UINT32
, BASE_DEC
,
1357 NULL
, 0x0, NULL
, HFILL
} },
1359 { "Expiry Time", "p_mul.expiry_time", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
,
1360 NULL
, 0x0, NULL
, HFILL
} },
1362 { "Multicast Group", "p_mul.mc_group", FT_UINT32
, BASE_DEC
,
1363 NULL
, 0x0, NULL
, HFILL
} },
1365 { "Announced Multicast Group", "p_mul.ann_mc_group", FT_UINT32
, BASE_DEC
,
1366 NULL
, 0x0, NULL
, HFILL
} },
1368 { "FEC Parameter Length", "p_mul.fec.length", FT_UINT8
, BASE_DEC
,
1369 NULL
, 0x0, "Forward Error Correction Parameter Length", HFILL
} },
1371 { "FEC ID", "p_mul.fec.id", FT_UINT8
, BASE_HEX
,
1372 NULL
, 0x0, "Forward Error Correction ID", HFILL
} },
1373 { &hf_fec_parameters
,
1374 { "FEC Parameters", "p_mul.fec.parameters", FT_NONE
, BASE_NONE
,
1375 NULL
, 0x0, "Forward Error Correction Parameters", HFILL
} },
1376 { &hf_count_of_dest
,
1377 { "Count of Destination Entries", "p_mul.dest_count", FT_UINT16
,BASE_DEC
,
1378 NULL
, 0x0, NULL
, HFILL
} },
1379 { &hf_length_of_res
,
1380 { "Length of Reserved Field", "p_mul.reserved_length",FT_UINT16
,BASE_DEC
,
1381 NULL
, 0x0, NULL
, HFILL
} },
1383 { "Count of Ack Info Entries", "p_mul.ack_count", FT_UINT16
, BASE_DEC
,
1384 NULL
, 0x0, NULL
, HFILL
} },
1386 { "Ack Info Entry", "p_mul.ack_info_entry", FT_NONE
, BASE_NONE
,
1387 NULL
, 0x0, NULL
, HFILL
} },
1389 { "Length of Ack Info Entry", "p_mul.ack_length", FT_UINT16
, BASE_DEC
,
1390 NULL
, 0x0, NULL
, HFILL
} },
1392 { "Missing Data PDU Seq Number", "p_mul.missing_seq_no", FT_UINT16
,
1393 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
1394 { &hf_miss_seq_range
,
1395 { "Missing Data PDU Seq Range", "p_mul.missing_seq_range", FT_BYTES
,
1396 BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
1397 { &hf_miss_seq_range_from
,
1398 { "Missing Data PDU Seq Range from", "p_mul.missing_seq_range.from", FT_UINT16
,
1399 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
1400 { &hf_miss_seq_range_delimiter
,
1401 { "Range Delimiter (always zero)", "p_mul.missing_seq_range.delimiter", FT_UINT16
,
1402 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
1403 { &hf_miss_seq_range_to
,
1404 { "Missing Data PDU Seq Range to", "p_mul.missing_seq_range.to", FT_UINT16
,
1405 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
1406 { &hf_tot_miss_seq_no
,
1407 { "Total Number of Missing Data PDU Sequence Numbers",
1408 "p_mul.no_missing_seq_no", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1410 { &hf_timestamp_option
,
1411 { "Timestamp", "p_mul.timestamp", FT_UINT64
, BASE_DEC
,
1412 NULL
, 0x0, "Timestamp Option (in units of 100ms)", HFILL
} },
1414 { "Destination Entry", "p_mul.dest_entry", FT_NONE
, BASE_NONE
,
1415 NULL
, 0x0, NULL
, HFILL
} },
1417 { "Destination ID", "p_mul.dest_id", FT_IPv4
, BASE_NONE
,
1418 NULL
, 0x0, NULL
, HFILL
} },
1420 { "Message Sequence Number", "p_mul.msg_seq_no", FT_UINT32
, BASE_DEC
,
1421 NULL
, 0x0, NULL
, HFILL
} },
1423 { "Symmetric Key", "p_mul.sym_key", FT_NONE
, BASE_NONE
,
1424 NULL
, 0x0, NULL
, HFILL
} },
1425 { &hf_data_fragment
,
1426 { "Fragment of Data", "p_mul.data_fragment", FT_NONE
, BASE_NONE
,
1427 NULL
, 0x0, NULL
, HFILL
} },
1429 /* Fragment entries */
1430 { &hf_msg_fragments
,
1431 { "Message fragments", "p_mul.fragments", FT_NONE
, BASE_NONE
,
1432 NULL
, 0x00, NULL
, HFILL
} },
1434 { "Message fragment", "p_mul.fragment", FT_FRAMENUM
, BASE_NONE
,
1435 NULL
, 0x00, NULL
, HFILL
} },
1436 { &hf_msg_fragment_overlap
,
1437 { "Message fragment overlap", "p_mul.fragment.overlap", FT_BOOLEAN
,
1438 BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
1439 { &hf_msg_fragment_overlap_conflicts
,
1440 { "Message fragment overlapping with conflicting data",
1441 "p_mul.fragment.overlap.conflicts", FT_BOOLEAN
, BASE_NONE
, NULL
,
1442 0x0, NULL
, HFILL
} },
1443 { &hf_msg_fragment_multiple_tails
,
1444 { "Message has multiple tail fragments",
1445 "p_mul.fragment.multiple_tails", FT_BOOLEAN
, BASE_NONE
,
1446 NULL
, 0x0, NULL
, HFILL
} },
1447 { &hf_msg_fragment_too_long_fragment
,
1448 { "Message fragment too long", "p_mul.fragment.too_long_fragment",
1449 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
,
1451 { &hf_msg_fragment_error
,
1452 { "Message defragmentation error", "p_mul.fragment.error", FT_FRAMENUM
,
1453 BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
1454 { &hf_msg_fragment_count
,
1455 { "Message fragment count", "p_mul.fragment.count", FT_UINT32
, BASE_DEC
,
1456 NULL
, 0x00, NULL
, HFILL
} },
1457 { &hf_msg_reassembled_in
,
1458 { "Reassembled in", "p_mul.reassembled.in", FT_FRAMENUM
, BASE_NONE
,
1459 NULL
, 0x00, NULL
, HFILL
} },
1460 { &hf_msg_reassembled_length
,
1461 { "Reassembled P_MUL length", "p_mul.reassembled.length", FT_UINT32
, BASE_DEC
,
1462 NULL
, 0x00, NULL
, HFILL
} },
1465 ** Ack matching / Resend
1467 { &hf_analysis_ack_time
,
1468 { "Ack Time", "p_mul.analysis.ack_time", FT_RELATIVE_TIME
, BASE_NONE
,
1469 NULL
, 0x0, "The time between the Last PDU and the Ack", HFILL
} },
1470 { &hf_analysis_trans_time
,
1471 { "Transfer Time", "p_mul.analysis.trans_time", FT_RELATIVE_TIME
, BASE_NONE
,
1472 NULL
, 0x0, "The time between the first Address PDU and the Ack", HFILL
} },
1473 { &hf_analysis_retrans_time
,
1474 { "Retransmission Time", "p_mul.analysis.retrans_time", FT_RELATIVE_TIME
, BASE_NONE
,
1475 NULL
, 0x0, "The time between the last PDU and this PDU", HFILL
} },
1476 { &hf_analysis_total_retrans_time
,
1477 { "Total Retransmission Time", "p_mul.analysis.total_retrans_time", FT_RELATIVE_TIME
, BASE_NONE
,
1478 NULL
, 0x0, "The time between the first PDU and this PDU", HFILL
} },
1479 { &hf_analysis_addr_pdu_time
,
1480 { "Time since Address PDU", "p_mul.analysis.elapsed_time", FT_RELATIVE_TIME
, BASE_NONE
,
1481 NULL
, 0x0, "The time between the Address PDU and this PDU", HFILL
} },
1482 { &hf_analysis_prev_pdu_time
,
1483 { "PDU Delay", "p_mul.analysis.pdu_delay", FT_RELATIVE_TIME
, BASE_NONE
,
1484 NULL
, 0x0, "The time between the last PDU and this PDU", HFILL
} },
1485 { &hf_analysis_last_pdu_num
,
1486 { "Last Data PDU in", "p_mul.analysis.last_pdu_in", FT_FRAMENUM
, BASE_NONE
,
1487 NULL
, 0x0, "The last Data PDU found in this frame", HFILL
} },
1488 { &hf_analysis_addr_pdu_num
,
1489 { "Address PDU in", "p_mul.analysis.addr_pdu_in", FT_FRAMENUM
, BASE_NONE
,
1490 NULL
, 0x0, "The Address PDU is found in this frame", HFILL
} },
1491 { &hf_analysis_acks_addr_pdu_num
,
1492 { "This is an Ack to the Address PDU in", "p_mul.analysis.acks_addr_pdu_in", FT_FRAMENUM
, BASE_NONE
,
1493 FRAMENUM_TYPE(FT_FRAMENUM_ACK
), 0x0, "The Address PDU is found in this frame", HFILL
} },
1494 { &hf_analysis_acks_acked_addr_pdu_num
,
1495 { "This is an Ack-Ack to the Address PDU in", "p_mul.analysis.acks_acked_addr_pdu_in", FT_FRAMENUM
, BASE_NONE
,
1496 FRAMENUM_TYPE(FT_FRAMENUM_DUP_ACK
), 0x0, "The Address PDU is found in this frame", HFILL
} },
1497 { &hf_analysis_prev_pdu_num
,
1498 { "Previous PDU in", "p_mul.analysis.prev_pdu_in", FT_FRAMENUM
, BASE_NONE
,
1499 NULL
, 0x0, "The previous PDU is found in this frame", HFILL
} },
1500 { &hf_analysis_ack_num
,
1501 { "Ack PDU in", "p_mul.analysis.ack_in", FT_FRAMENUM
, BASE_NONE
,
1502 NULL
, 0x0, "This packet has an Ack in this frame", HFILL
} },
1503 { &hf_analysis_ack_missing
,
1504 { "Ack PDU missing", "p_mul.analysis.ack_missing", FT_NONE
, BASE_NONE
,
1505 NULL
, 0x0, "The acknowledgement for this packet is missing", HFILL
} },
1506 { &hf_analysis_retrans_no
,
1507 { "Retransmission #", "p_mul.analysis.retrans_no", FT_UINT32
, BASE_DEC
,
1508 NULL
, 0x0, "Retransmission count", HFILL
} },
1509 { &hf_analysis_ack_dup_no
,
1510 { "Duplicate ACK #", "p_mul.analysis.dup_ack_no", FT_UINT32
, BASE_DEC
,
1511 NULL
, 0x0, "Duplicate Ack count", HFILL
} },
1512 { &hf_analysis_msg_resend_from
,
1513 { "Retransmission of Message in", "p_mul.analysis.msg_first_in",
1514 FT_FRAMENUM
, BASE_NONE
,
1515 NULL
, 0x0, "This Message was first sent in this frame", HFILL
} },
1516 { &hf_analysis_ack_resend_from
,
1517 { "Retransmission of Ack in", "p_mul.analysis.ack_first_in",
1518 FT_FRAMENUM
, BASE_NONE
,
1519 NULL
, 0x0, "This Ack was first sent in this frame", HFILL
} },
1520 { &hf_analysis_total_time
,
1521 { "Total Time", "p_mul.analysis.total_time", FT_RELATIVE_TIME
, BASE_NONE
,
1522 NULL
, 0x0, "The time between the first and the last Address PDU", HFILL
} },
1525 static int *ett
[] = {
1534 &ett_seq_ack_analysis
,
1538 static ei_register_info ei
[] = {
1539 { &ei_address_pdu_missing
, { "p_mul.analysis.addr_pdu_missing", PI_SEQUENCE
, PI_NOTE
, "Address PDU missing", EXPFILL
}},
1540 { &ei_analysis_ack_missing
, { "p_mul.analysis.ack_missing.expert", PI_SEQUENCE
, PI_NOTE
, "Ack PDU missing", EXPFILL
}},
1541 { &ei_analysis_ack_dup_no
, { "p_mul.analysis.dup_ack_no.expert", PI_SEQUENCE
, PI_NOTE
, "Dup ACK #", EXPFILL
}},
1542 { &ei_analysis_prev_pdu_missing
, { "p_mul.analysis.prev_pdu_missing", PI_SEQUENCE
, PI_NOTE
, "Previous PDU missing", EXPFILL
}},
1543 { &ei_analysis_retrans_no
, { "p_mul.analysis.retrans_no.expert", PI_SEQUENCE
, PI_NOTE
, "Retransmission #", EXPFILL
}},
1544 { &ei_message_discarded
, { "p_mul.message_discarded", PI_RESPONSE_CODE
, PI_NOTE
, "Message discarded", EXPFILL
}},
1545 { &ei_checksum_bad
, { "p_mul.checksum_bad.expert", PI_CHECKSUM
, PI_WARN
, "Bad checksum", EXPFILL
}},
1546 { &ei_ack_length
, { "p_mul.ack_length.invalid", PI_MALFORMED
, PI_WARN
, "Invalid ack info length", EXPFILL
}},
1547 { &ei_miss_seq_range
, { "p_mul.missing_seq_range.invalid", PI_UNDECODED
, PI_WARN
, "Invalid missing sequence range", EXPFILL
}},
1548 { &ei_miss_seq_no
, { "p_mul.missing_seq_no.invalid", PI_UNDECODED
, PI_WARN
, "Invalid missing seq number", EXPFILL
}},
1549 { &ei_tot_miss_seq_no
, { "p_mul.no_missing_seq_no.expert", PI_RESPONSE_CODE
, PI_NOTE
, "Missing seq numbers", EXPFILL
}},
1550 { &ei_illegal_seq_no
, { "p_mul.seq_no.illegal", PI_PROTOCOL
, PI_WARN
, "Illegal seq number", EXPFILL
}},
1551 { &ei_length
, { "p_mul.length.invalid", PI_MALFORMED
, PI_WARN
, "Incorrect length field", EXPFILL
}},
1552 { &ei_more_data
, { "p_mul.more_data", PI_MALFORMED
, PI_WARN
, "More data in packet", EXPFILL
}},
1555 module_t
*p_mul_module
;
1556 expert_module_t
* expert_p_mul
;
1558 proto_p_mul
= proto_register_protocol (PNAME
, PSNAME
, PFNAME
);
1560 p_mul_handle
= register_dissector(PFNAME
, dissect_p_mul
, proto_p_mul
);
1562 proto_register_field_array (proto_p_mul
, hf
, array_length (hf
));
1563 proto_register_subtree_array (ett
, array_length (ett
));
1564 expert_p_mul
= expert_register_protocol(proto_p_mul
);
1565 expert_register_field_array(expert_p_mul
, ei
, array_length(ei
));
1566 register_init_routine (&p_mul_init_routine
);
1567 reassembly_table_register (&p_mul_reassembly_table
,
1568 &addresses_reassembly_table_functions
);
1570 p_mul_id_hash_table
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), p_mul_id_hash
, p_mul_id_hash_equal
);
1572 /* Register our configuration options */
1573 p_mul_module
= prefs_register_protocol (proto_p_mul
, NULL
);
1575 prefs_register_obsolete_preference (p_mul_module
, "tport");
1576 prefs_register_obsolete_preference (p_mul_module
, "rport");
1577 prefs_register_obsolete_preference (p_mul_module
, "dport");
1578 prefs_register_obsolete_preference (p_mul_module
, "aport");
1580 prefs_register_bool_preference (p_mul_module
, "reassemble",
1581 "Reassemble fragmented P_Mul packets",
1582 "Reassemble fragmented P_Mul packets",
1584 prefs_register_bool_preference (p_mul_module
, "relative_msgid",
1585 "Use relative Message ID",
1586 "Make the P_Mul dissector use relative"
1587 " message id number instead of absolute"
1588 " ones", &use_relative_msgid
);
1589 prefs_register_bool_preference (p_mul_module
, "seq_ack_analysis",
1591 "Calculate sequence/acknowledgement analysis",
1592 &use_seq_ack_analysis
);
1593 prefs_register_enum_preference (p_mul_module
, "decode",
1594 "Decode Data PDU as",
1595 "Type of content in Data_PDU",
1596 &decode_option
, decode_options
, false);
1599 void proto_reg_handoff_p_mul (void)
1601 dissector_add_uint ("s5066sis.ctl.appid", S5066_CLIENT_S4406_ANNEX_E_TMI_1_P_MUL
, p_mul_handle
);
1602 dissector_add_uint_range_with_preference("udp.port", DEFAULT_P_MUL_PORT_RANGE
, p_mul_handle
);
1611 * indent-tabs-mode: nil
1614 * ex: set shiftwidth=2 tabstop=8 expandtab:
1615 * :indentSize=2:tabSize=8:noTabs=true: