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
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 * Ref: http://jcs.dtic.mil/j6/cceb/acps/acp142/
34 * - Obtain dedicated UDP port numbers
35 * - SEQ/ACK analysis for Announce/Request/Reject/Release PDU
42 #include <epan/packet.h>
43 #include <epan/to_str.h>
44 #include <epan/prefs.h>
45 #include <epan/reassemble.h>
46 #include <epan/expert.h>
47 #include <epan/asn1.h>
50 #include "packet-cdt.h"
51 #include "packet-ber.h"
53 #define PNAME "P_Mul (ACP142)"
54 #define PSNAME "P_MUL"
55 #define PFNAME "p_mul"
57 /* Recommended UDP Port Numbers */
58 #define DEFAULT_P_MUL_PORT_RANGE ""
63 #define Address_PDU 0x02
64 #define Discard_Message_PDU 0x03
65 #define Announce_PDU 0x04
66 #define Request_PDU 0x05
67 #define Reject_PDU 0x06
68 #define Release_PDU 0x07
69 #define FEC_Address_PDU 0x08
70 #define Extra_Address_PDU 0x12
71 #define Extra_FEC_Address_PDU 0x18
72 #define Ack_Ack_PDU 0xFF /* Fake type to indicate Ack-Ack */
74 /* Type of content to decode from Data_PDU */
79 void proto_reg_handoff_p_mul (void);
81 static int proto_p_mul = -1;
83 static int hf_length = -1;
84 static int hf_priority = -1;
85 static int hf_map_first = -1;
86 static int hf_map_last = -1;
87 static int hf_map_unused = -1;
88 static int hf_pdu_type = -1;
89 static int hf_pdu_type_value = -1;
90 static int hf_no_pdus = -1;
91 static int hf_seq_no = -1;
92 static int hf_unused8 = -1;
93 static int hf_unused16 = -1;
94 static int hf_checksum = -1;
95 static int hf_checksum_good = -1;
96 static int hf_checksum_bad = -1;
97 static int hf_source_id_ack = -1;
98 static int hf_source_id = -1;
99 static int hf_message_id = -1;
100 static int hf_expiry_time = -1;
101 static int hf_mc_group = -1;
102 static int hf_ann_mc_group = -1;
103 static int hf_fec_len = -1;
104 static int hf_fec_id = -1;
105 static int hf_fec_parameters = -1;
106 static int hf_count_of_dest = -1;
107 static int hf_length_of_res = -1;
108 static int hf_ack_count = -1;
109 static int hf_ack_entry = -1;
110 static int hf_ack_length = -1;
111 static int hf_miss_seq_no = -1;
112 static int hf_miss_seq_range = -1;
113 static int hf_tot_miss_seq_no = -1;
114 static int hf_timestamp_option = -1;
115 static int hf_dest_entry = -1;
116 static int hf_dest_id = -1;
117 static int hf_msg_seq_no = -1;
118 static int hf_sym_key = -1;
119 static int hf_data_fragment = -1;
121 static int hf_msg_fragments = -1;
122 static int hf_msg_fragment = -1;
123 static int hf_msg_fragment_overlap = -1;
124 static int hf_msg_fragment_overlap_conflicts = -1;
125 static int hf_msg_fragment_multiple_tails = -1;
126 static int hf_msg_fragment_too_long_fragment = -1;
127 static int hf_msg_fragment_error = -1;
128 static int hf_msg_fragment_count = -1;
129 static int hf_msg_reassembled_in = -1;
130 static int hf_msg_reassembled_length = -1;
132 static int hf_analysis_ack_time = -1;
133 static int hf_analysis_trans_time = -1;
134 static int hf_analysis_retrans_time = -1;
135 static int hf_analysis_total_retrans_time = -1;
136 static int hf_analysis_last_pdu_num = -1;
137 static int hf_analysis_addr_pdu_num = -1;
138 static int hf_analysis_addr_pdu_time = -1;
139 static int hf_analysis_addr_pdu_missing = -1;
140 static int hf_analysis_prev_pdu_num = -1;
141 static int hf_analysis_prev_pdu_time = -1;
142 static int hf_analysis_prev_pdu_missing = -1;
143 static int hf_analysis_retrans_no = -1;
144 static int hf_analysis_ack_num = -1;
145 static int hf_analysis_ack_missing = -1;
146 static int hf_analysis_ack_dup_no = -1;
147 static int hf_analysis_msg_resend_from = -1;
148 static int hf_analysis_ack_resend_from = -1;
149 static int hf_analysis_total_time = -1;
151 static gint ett_p_mul = -1;
152 static gint ett_pdu_type = -1;
153 static gint ett_dest_entry = -1;
154 static gint ett_ack_entry = -1;
155 static gint ett_range_entry = -1;
156 static gint ett_checksum = -1;
157 static gint ett_seq_analysis = -1;
158 static gint ett_ack_analysis = -1;
159 static gint ett_seq_ack_analysis = -1;
160 static gint ett_msg_fragment = -1;
161 static gint ett_msg_fragments = -1;
163 static dissector_handle_t p_mul_handle = NULL;
164 static dissector_handle_t data_handle = NULL;
166 typedef struct _p_mul_id_key {
172 typedef struct _p_mul_seq_val {
173 gint msg_type; /* Message type */
174 guint32 prev_msg_id; /* Previous message package num */
175 nstime_t prev_msg_time; /* Previous message receive time */
176 guint32 addr_id; /* PDU package num for Address_PDU */
177 nstime_t addr_time; /* PDU received time for Address_PDU */
178 guint32 pdu_id; /* PDU package num */
179 nstime_t pdu_time; /* PDU receive time */
180 guint32 prev_pdu_id; /* Previous PDU package num */
181 nstime_t prev_pdu_time; /* Previous PDU receive time */
182 guint16 last_found_pdu; /* Last PDU num */
183 nstime_t first_msg_time; /* First message receive time */
184 guint32 msg_resend_count; /* Message resend counter */
185 GHashTable *ack_data;
188 typedef struct _p_mul_ack_data {
189 guint32 ack_id; /* Ack PDU package num */
190 guint32 ack_resend_count; /* Ack resend counter */
193 /* Hash table with current data for seq/ack analysis */
194 static GHashTable *p_mul_id_hash_table = NULL;
196 /* List of hash tables stored in each frame */
197 static GList *p_mul_package_data_list = NULL;
199 /* User definable values to use for dissection */
200 static range_t *global_p_mul_port_range;
201 static gboolean p_mul_reassemble = TRUE;
202 static gint decode_option = DECODE_NONE;
203 static gboolean use_relative_msgid = TRUE;
204 static gboolean use_seq_ack_analysis = TRUE;
206 static GHashTable *p_mul_fragment_table = NULL;
207 static GHashTable *p_mul_reassembled_table = NULL;
209 static guint32 message_id_offset = 0;
211 static const fragment_items p_mul_frag_items = {
212 /* Fragment subtrees */
215 /* Fragment fields */
218 &hf_msg_fragment_overlap,
219 &hf_msg_fragment_overlap_conflicts,
220 &hf_msg_fragment_multiple_tails,
221 &hf_msg_fragment_too_long_fragment,
222 &hf_msg_fragment_error,
223 &hf_msg_fragment_count,
224 /* Reassembled in field */
225 &hf_msg_reassembled_in,
226 /* Reassembled length field */
227 &hf_msg_reassembled_length,
232 static const value_string pdu_vals[] = {
233 { Data_PDU, "Data PDU" },
234 { Ack_PDU, "Ack PDU" },
235 { Address_PDU, "Address PDU" },
236 { Discard_Message_PDU, "Discard Message PDU" },
237 { Announce_PDU, "Announce PDU" },
238 { Request_PDU, "Request PDU" },
239 { Reject_PDU, "Reject PDU" },
240 { Release_PDU, "Release PDU" },
241 { FEC_Address_PDU, "FEC Address PDU" },
242 { Extra_Address_PDU, "Extra Address PDU" },
243 { Extra_FEC_Address_PDU, "Extra FEC Address PDU" },
244 { Ack_Ack_PDU, "Ack-Ack PDU" },
248 static enum_val_t decode_options[] = {
249 { "none", "No decoding", DECODE_NONE },
250 { "ber", "BER encoded ASN.1", DECODE_BER },
251 { "cdt", "Compressed Data Type", DECODE_CDT },
255 static const true_false_string no_yes = {
259 static const gchar *get_type (guint8 value)
261 return val_to_str (value, pdu_vals, "Unknown");
265 /*Function checksum, found in ACP142 annex B-3 */
266 static guint16 checksum (guint8 *buffer, gint len, gint offset)
268 guint16 c0 = 0, c1 = 0, ret, ctmp;
272 if (len < offset+2) {
273 /* Buffer to small */
278 buffer[offset+1] = 0;
279 ctmp = len - offset - 1;
285 if ((c0 += *hpp++) > 254) { c0 -= 255; }
286 if ((c1 += c0) > 254) { c1 -= 255; }
289 if ((cs = ((ctmp * c0) - c1) % 255) < 0) { cs += 255; }
291 if ((cs = (c1 - ((ctmp + 1L) * c0)) % 255) < 0) { cs += 255; }
297 static guint p_mul_id_hash (gconstpointer k)
299 p_mul_id_key *p_mul=(p_mul_id_key *)k;
303 static gint p_mul_id_hash_equal (gconstpointer k1, gconstpointer k2)
305 p_mul_id_key *p_mul1=(p_mul_id_key *)k1;
306 p_mul_id_key *p_mul2=(p_mul_id_key *)k2;
308 if (p_mul1->id != p_mul2->id)
311 if (p_mul1->seq != p_mul2->seq)
314 return (ADDRESSES_EQUAL (&p_mul1->addr, &p_mul2->addr));
317 static p_mul_seq_val *lookup_seq_val (guint32 message_id, guint16 seq_no,
320 p_mul_seq_val *pkg_data = NULL;
321 p_mul_id_key *p_mul_key = se_alloc (sizeof (p_mul_id_key));
323 p_mul_key->id = message_id;
324 p_mul_key->seq = seq_no;
325 SE_COPY_ADDRESS(&p_mul_key->addr, addr);
327 pkg_data = (p_mul_seq_val *) g_hash_table_lookup (p_mul_id_hash_table, p_mul_key);
332 static void p_mul_id_value_destroy (p_mul_seq_val *pkg_data)
334 if (pkg_data->ack_data) {
335 g_hash_table_destroy (pkg_data->ack_data);
340 static void p_mul_package_data_destroy (GHashTable *pkg_list, gpointer user_data _U_)
342 g_hash_table_destroy (pkg_list);
345 static void copy_hashtable_data (gpointer key, p_mul_ack_data *ack_data1, GHashTable *table)
347 p_mul_ack_data *ack_data2;
349 ack_data2 = se_alloc (sizeof (p_mul_ack_data));
350 ack_data2->ack_id = ack_data1->ack_id;
351 ack_data2->ack_resend_count = ack_data1->ack_resend_count;
353 g_hash_table_insert (table, key, ack_data2);
356 static p_mul_seq_val *register_p_mul_id (packet_info *pinfo, address *addr, guint32 dstIP,
357 guint8 pdu_type, guint32 message_id,
358 guint16 seq_no, gint no_missing)
360 p_mul_seq_val *p_mul_data = NULL, *pkg_data = NULL;
361 p_mul_id_key *p_mul_key = NULL;
362 p_mul_ack_data *ack_data = NULL;
363 nstime_t addr_time, prev_time;
364 guint addr_id = 0, prev_id = 0;
365 guint16 last_found_pdu = 0;
366 gboolean missing_pdu = FALSE, set_address = FALSE;
367 GHashTable *pkg_list = NULL;
369 if (pinfo->in_error_pkt) {
370 /* No analysis of error packets */
374 nstime_set_zero(&addr_time);
375 nstime_set_zero(&prev_time);
377 p_mul_key = se_alloc (sizeof (p_mul_id_key));
379 if (!pinfo->fd->flags.visited &&
380 (pdu_type == Address_PDU || pdu_type == Data_PDU || pdu_type == Discard_Message_PDU))
382 /* Try to match corresponding address PDU */
383 p_mul_key->id = message_id;
385 SE_COPY_ADDRESS(&p_mul_key->addr, addr);
388 p_mul_data = (p_mul_seq_val *) g_hash_table_lookup (p_mul_id_hash_table, p_mul_key);
391 /* Found address PDU */
392 last_found_pdu = p_mul_data->last_found_pdu;
393 p_mul_data->last_found_pdu = seq_no;
394 addr_id = p_mul_data->pdu_id;
395 addr_time = p_mul_data->pdu_time;
397 /* Save data for last found PDU */
398 p_mul_data->prev_pdu_id = pinfo->fd->num;
399 p_mul_data->prev_pdu_time = pinfo->fd->abs_ts;
401 if (pdu_type == Data_PDU && p_mul_data->msg_resend_count == 0 && last_found_pdu != seq_no - 1) {
402 /* Data_PDU and missing previous PDU */
406 if (last_found_pdu) {
407 /* Try to match previous data PDU */
408 p_mul_key->seq = last_found_pdu;
409 p_mul_data = (p_mul_seq_val *) g_hash_table_lookup (p_mul_id_hash_table, p_mul_key);
413 /* Found a previous PDU (Address or Data) */
414 if (p_mul_data->prev_msg_id > 0) {
415 prev_id = p_mul_data->prev_msg_id;
417 prev_id = p_mul_data->pdu_id;
419 prev_time = p_mul_data->pdu_time;
421 } else if (pdu_type == Address_PDU) {
422 addr_id = pinfo->fd->num;
423 addr_time = pinfo->fd->abs_ts;
427 pkg_list = p_get_proto_data (pinfo->fd, proto_p_mul);
429 /* Never saved list for this packet, create a new */
430 pkg_list = g_hash_table_new (NULL, NULL);
431 p_mul_package_data_list = g_list_append (p_mul_package_data_list, pkg_list);
432 p_add_proto_data (pinfo->fd, proto_p_mul, pkg_list);
435 if (!pinfo->fd->flags.visited) {
436 p_mul_key->id = message_id;
437 p_mul_key->seq = seq_no;
439 SE_COPY_ADDRESS(&p_mul_key->addr, addr);
441 p_mul_data = (p_mul_seq_val *) g_hash_table_lookup (p_mul_id_hash_table, p_mul_key);
444 if (pdu_type == Ack_PDU) {
445 /* Only save this data if positive ack */
446 if (no_missing == 0) {
447 ack_data = g_hash_table_lookup (p_mul_data->ack_data, GUINT_TO_POINTER(dstIP));
449 /* Only save reference to first ACK */
450 ack_data = se_alloc0 (sizeof (p_mul_ack_data));
451 ack_data->ack_id = pinfo->fd->num;
452 g_hash_table_insert (p_mul_data->ack_data, GUINT_TO_POINTER(dstIP), ack_data);
454 /* Only count when resending */
455 ack_data->ack_resend_count++;
460 p_mul_data->msg_resend_count++;
461 p_mul_data->prev_msg_id = pinfo->fd->num;
462 p_mul_data->prev_msg_time = p_mul_data->pdu_time;
463 p_mul_data->pdu_time = pinfo->fd->abs_ts;
465 if (pdu_type == Data_PDU) {
466 p_mul_data->prev_pdu_id = prev_id;
467 p_mul_data->prev_pdu_time = prev_time;
472 if (pdu_type == Ack_PDU) {
473 p_mul_data = se_alloc0 (sizeof (p_mul_seq_val));
475 p_mul_data = g_malloc0 (sizeof (p_mul_seq_val));
477 p_mul_data->msg_type = pdu_type;
478 if (pdu_type == Address_PDU || pdu_type == Ack_PDU) {
479 p_mul_data->ack_data = g_hash_table_new (NULL, NULL);
482 if (pdu_type == Ack_PDU) {
483 /* No matching message for this ack */
484 ack_data = se_alloc0 (sizeof (p_mul_ack_data));
485 ack_data->ack_id = pinfo->fd->num;
486 g_hash_table_insert (p_mul_data->ack_data, GUINT_TO_POINTER(dstIP), ack_data);
488 p_mul_data->pdu_id = pinfo->fd->num;
489 p_mul_data->pdu_time = pinfo->fd->abs_ts;
490 p_mul_data->addr_id = addr_id;
491 p_mul_data->addr_time = addr_time;
492 p_mul_data->first_msg_time = pinfo->fd->abs_ts;
494 if (pdu_type == Data_PDU && !missing_pdu) {
495 p_mul_data->prev_pdu_id = prev_id;
496 p_mul_data->prev_pdu_time = prev_time;
499 g_hash_table_insert (p_mul_id_hash_table, p_mul_key, p_mul_data);
503 /* Copy the current package data to the frame */
504 pkg_data = se_alloc (sizeof (p_mul_seq_val));
505 *pkg_data = *p_mul_data;
506 if (p_mul_data->ack_data) {
507 /* Copy the hash table for ack data */
508 pkg_data->ack_data = g_hash_table_new (NULL, NULL);
509 g_hash_table_foreach (p_mul_data->ack_data, (GHFunc) copy_hashtable_data, pkg_data->ack_data);
511 g_hash_table_insert (pkg_list, GUINT_TO_POINTER(message_id), pkg_data);
513 /* Fetch last values from data saved in packet */
514 pkg_data = g_hash_table_lookup (pkg_list, GUINT_TO_POINTER(message_id));
517 DISSECTOR_ASSERT (pkg_data);
521 static void add_ack_analysis (tvbuff_t *tvb, packet_info *pinfo, proto_tree *p_mul_tree,
522 gint offset, guint8 pdu_type, address *src, address *dst,
523 guint32 message_id, gint no_missing)
525 proto_tree *analysis_tree = NULL;
526 proto_item *sa = NULL, *en = NULL;
527 p_mul_seq_val *pkg_data = NULL;
528 p_mul_ack_data *ack_data = NULL;
529 gboolean item_added = FALSE;
533 if (pinfo->in_error_pkt) {
534 /* No analysis of error packets */
538 if (pdu_type == Address_PDU) {
539 sa = proto_tree_add_text (p_mul_tree, tvb, 0, 0, "ACK analysis");
540 PROTO_ITEM_SET_GENERATED (sa);
541 analysis_tree = proto_item_add_subtree (sa, ett_ack_analysis);
543 /* Fetch package data */
544 if ((pkg_data = lookup_seq_val (message_id, 0, src)) == NULL) {
545 /* No need for seq/ack analysis yet */
551 if (pkg_data->addr_id) {
552 en = proto_tree_add_uint (analysis_tree, hf_analysis_addr_pdu_num, tvb,
553 0, 0, pkg_data->addr_id);
554 PROTO_ITEM_SET_GENERATED (en);
556 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->addr_time);
557 en = proto_tree_add_time (analysis_tree, hf_analysis_total_time,
559 PROTO_ITEM_SET_GENERATED (en);
561 en = proto_tree_add_item (analysis_tree,
562 hf_analysis_addr_pdu_missing,
563 tvb, offset, 0, ENC_NA);
564 expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
565 "Address PDU missing");
566 PROTO_ITEM_SET_GENERATED (en);
570 memcpy((guint8 *)&dstIp, dst->data, 4);
571 if (pkg_data->ack_data) {
572 ack_data = g_hash_table_lookup (pkg_data->ack_data, GUINT_TO_POINTER(dstIp));
575 /* Add reference to Ack_PDU */
576 if (ack_data && ack_data->ack_id) {
577 en = proto_tree_add_uint (analysis_tree, hf_analysis_ack_num, tvb,
578 0, 0, ack_data->ack_id);
579 PROTO_ITEM_SET_GENERATED (en);
581 } else if (!pkg_data->msg_resend_count) {
582 en = proto_tree_add_item (analysis_tree,
583 hf_analysis_ack_missing,
584 tvb, offset, 0, ENC_NA);
585 if (pinfo->fd->flags.visited) {
586 /* We do not know this on first visit and we do not want to
587 add a entry in the "Expert Severity Info" for this note */
588 expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
590 PROTO_ITEM_SET_GENERATED (en);
597 PROTO_ITEM_SET_HIDDEN (sa);
599 } else if (pdu_type == Ack_PDU) {
600 sa = proto_tree_add_text (p_mul_tree, tvb, 0, 0, "SEQ/ACK analysis");
601 PROTO_ITEM_SET_GENERATED (sa);
602 analysis_tree = proto_item_add_subtree (sa, ett_seq_ack_analysis);
604 /* Fetch package data */
605 memcpy((guint8 *)&dstIp, dst->data, 4);
606 if ((pkg_data = register_p_mul_id (pinfo, src, dstIp, pdu_type, message_id, 0, no_missing)) == NULL) {
607 /* No need for seq/ack analysis yet */
610 if (pkg_data->ack_data) {
611 ack_data = g_hash_table_lookup (pkg_data->ack_data, GUINT_TO_POINTER(dstIp));
614 /* Add reference to Address_PDU */
615 if (pkg_data->msg_type != Ack_PDU) {
616 en = proto_tree_add_uint (analysis_tree, hf_analysis_addr_pdu_num, tvb,
617 0, 0, pkg_data->pdu_id);
618 PROTO_ITEM_SET_GENERATED (en);
620 if (no_missing == 0) {
621 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->first_msg_time);
622 en = proto_tree_add_time (analysis_tree, hf_analysis_trans_time,
624 PROTO_ITEM_SET_GENERATED (en);
627 en = proto_tree_add_item (analysis_tree,
628 hf_analysis_addr_pdu_missing,
629 tvb, offset, 0, ENC_NA);
630 expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
631 "Address PDU missing");
632 PROTO_ITEM_SET_GENERATED (en);
635 if (pkg_data->msg_type != Ack_PDU && pkg_data->prev_pdu_id) {
636 /* Add reference to previous PDU */
637 en = proto_tree_add_uint (analysis_tree, hf_analysis_last_pdu_num,
638 tvb, 0, 0, pkg_data->prev_pdu_id);
639 PROTO_ITEM_SET_GENERATED (en);
641 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->prev_pdu_time);
642 en = proto_tree_add_time (analysis_tree, hf_analysis_ack_time,
644 PROTO_ITEM_SET_GENERATED (en);
647 if (ack_data && ack_data->ack_resend_count) {
648 /* Add resend statistics */
649 en = proto_tree_add_uint (analysis_tree, hf_analysis_ack_dup_no,
650 tvb, 0, 0, ack_data->ack_resend_count);
651 PROTO_ITEM_SET_GENERATED (en);
653 expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
654 "Dup ACK #%d", ack_data->ack_resend_count);
656 en = proto_tree_add_uint (analysis_tree, hf_analysis_ack_resend_from,
657 tvb, 0, 0, ack_data->ack_id);
658 PROTO_ITEM_SET_GENERATED (en);
660 col_append_fstr (pinfo->cinfo, COL_INFO, "[Dup ACK %d#%d] ",
661 ack_data->ack_id, ack_data->ack_resend_count);
666 static p_mul_seq_val *add_seq_analysis (tvbuff_t *tvb, packet_info *pinfo,
667 proto_tree *p_mul_tree, address *src,
669 guint8 pdu_type, guint32 message_id,
670 guint16 seq_no, gint no_missing)
672 p_mul_seq_val *pkg_data = NULL;
673 proto_tree *analysis_tree = NULL;
674 proto_item *sa = NULL, *en = NULL, *eh = NULL;
675 gboolean item_added = FALSE;
678 pkg_data = register_p_mul_id (pinfo, src, 0, pdu_type, message_id, seq_no,
682 /* No need for seq/ack analysis */
686 sa = proto_tree_add_text (p_mul_tree, tvb, 0, 0, "SEQ analysis");
687 PROTO_ITEM_SET_GENERATED (sa);
688 analysis_tree = proto_item_add_subtree (sa, ett_seq_analysis);
690 if (pdu_type == Data_PDU || pdu_type == Discard_Message_PDU) {
691 /* Add reference to Address_PDU */
692 if (pkg_data->addr_id) {
693 en = proto_tree_add_uint (analysis_tree, hf_analysis_addr_pdu_num, tvb,
694 0, 0, pkg_data->addr_id);
695 PROTO_ITEM_SET_GENERATED (en);
697 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->addr_time);
698 en = proto_tree_add_time (analysis_tree, hf_analysis_addr_pdu_time,
700 PROTO_ITEM_SET_GENERATED (en);
702 if (pkg_data->prev_pdu_id == pkg_data->addr_id) {
703 /* Previous pdu time is the same as time since address pdu */
704 en = proto_tree_add_time (analysis_tree, hf_analysis_prev_pdu_time,
706 PROTO_ITEM_SET_GENERATED (en);
709 } else if (!pkg_data->msg_resend_count) {
710 en = proto_tree_add_item (analysis_tree,
711 hf_analysis_addr_pdu_missing,
712 tvb, offset, 0, ENC_NA);
713 expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
714 "Address PDU missing");
715 PROTO_ITEM_SET_GENERATED (en);
720 if ((pdu_type == Data_PDU) && (pkg_data->prev_pdu_id != pkg_data->addr_id)) {
721 /* Add reference to previous Data_PDU */
722 if (pkg_data->prev_pdu_id) {
723 en = proto_tree_add_uint (analysis_tree, hf_analysis_prev_pdu_num, tvb,
724 0, 0, pkg_data->prev_pdu_id);
725 PROTO_ITEM_SET_GENERATED (en);
727 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->prev_pdu_time);
728 en = proto_tree_add_time (analysis_tree, hf_analysis_prev_pdu_time,
730 PROTO_ITEM_SET_GENERATED (en);
732 } else if (!pkg_data->msg_resend_count) {
733 en = proto_tree_add_item (analysis_tree,
734 hf_analysis_prev_pdu_missing,
735 tvb, offset, 0, ENC_NA);
736 expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
737 "Previous PDU missing");
738 PROTO_ITEM_SET_GENERATED (en);
743 if ((pdu_type == Address_PDU) || (pdu_type == Data_PDU) ||
744 (pdu_type == Discard_Message_PDU)) {
745 /* Add resend statistics */
746 if (pkg_data->msg_resend_count) {
747 en = proto_tree_add_uint (analysis_tree, hf_analysis_retrans_no,
748 tvb, 0, 0, pkg_data->msg_resend_count);
749 PROTO_ITEM_SET_GENERATED (en);
751 en = proto_tree_add_uint (analysis_tree, hf_analysis_msg_resend_from,
752 tvb, 0, 0, pkg_data->pdu_id);
753 PROTO_ITEM_SET_GENERATED (en);
755 expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
756 "Retransmission #%d",
757 pkg_data->msg_resend_count);
759 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->prev_msg_time);
760 en = proto_tree_add_time (analysis_tree, hf_analysis_retrans_time,
762 PROTO_ITEM_SET_GENERATED (en);
764 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->first_msg_time);
765 eh = proto_tree_add_time (analysis_tree, hf_analysis_total_retrans_time,
767 PROTO_ITEM_SET_GENERATED (eh);
769 if (pkg_data->first_msg_time.secs == pkg_data->prev_msg_time.secs &&
770 pkg_data->first_msg_time.nsecs == pkg_data->prev_msg_time.nsecs) {
771 /* Time values does not differ, hide the total time */
772 PROTO_ITEM_SET_HIDDEN (eh);
776 col_append_fstr (pinfo->cinfo, COL_INFO, "[Retrans %d#%d] ",
777 pkg_data->pdu_id, pkg_data->msg_resend_count);
782 PROTO_ITEM_SET_HIDDEN (sa);
789 static void dissect_reassembled_data (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
791 if (tvb == NULL || tree == NULL) {
795 switch (decode_option) {
797 dissect_unknown_ber (pinfo, tvb, 0, tree);
800 dissect_cdt (tvb, pinfo, tree);
803 call_dissector (data_handle, tvb, pinfo, tree);
808 static void dissect_p_mul (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
810 proto_tree *p_mul_tree = NULL, *field_tree = NULL, *checksum_tree = NULL;
811 proto_item *ti = NULL, *en = NULL, *len_en = NULL;
812 gboolean save_fragmented;
813 fragment_data *frag_msg = NULL;
814 guint32 message_id = 0, ip;
815 guint16 no_dest = 0, count = 0, len = 0, data_len = 0;
816 guint16 checksum1, checksum2, pdu_length = 0, no_pdus = 0, seq_no = 0;
817 guint8 pdu_type = 0, *value = NULL, map = 0, fec_len;
818 gint i, tot_no_missing = 0, no_missing = 0, offset = 0;
820 emem_strbuf_t *message_id_list = NULL;
823 col_set_str (pinfo->cinfo, COL_PROTOCOL, "P_MUL");
824 col_clear (pinfo->cinfo, COL_INFO);
826 /* First fetch PDU Type */
827 pdu_type = tvb_get_guint8 (tvb, offset + 3) & 0x3F;
829 ti = proto_tree_add_item (tree, proto_p_mul, tvb, offset, -1, ENC_BIG_ENDIAN);
830 proto_item_append_text (ti, ", %s", get_type (pdu_type));
831 p_mul_tree = proto_item_add_subtree (ti, ett_p_mul);
834 pdu_length = tvb_get_ntohs (tvb, offset);
835 len_en = proto_tree_add_item (p_mul_tree, hf_length, tvb, offset, 2, ENC_BIG_ENDIAN);
843 case Discard_Message_PDU:
844 case Extra_Address_PDU:
845 case FEC_Address_PDU:
846 case Extra_FEC_Address_PDU:
848 proto_tree_add_item (p_mul_tree, hf_priority, tvb, offset, 1, ENC_BIG_ENDIAN);
853 proto_tree_add_item (p_mul_tree, hf_unused8, tvb, offset, 1, ENC_BIG_ENDIAN);
858 en = proto_tree_add_uint_format (p_mul_tree, hf_pdu_type, tvb, offset, 1,
859 pdu_type, "PDU Type: %s (0x%02x)",
860 get_type (pdu_type), pdu_type);
861 field_tree = proto_item_add_subtree (en, ett_pdu_type);
863 if (pdu_type == Discard_Message_PDU) {
864 expert_add_info_format (pinfo, en, PI_RESPONSE_CODE, PI_NOTE,
865 "Message discarded");
872 case Extra_Address_PDU:
873 case FEC_Address_PDU:
874 case Extra_FEC_Address_PDU:
875 map = tvb_get_guint8 (tvb, offset);
876 proto_tree_add_item (field_tree, hf_map_first, tvb, offset, 1, ENC_BIG_ENDIAN);
877 proto_tree_add_item (field_tree, hf_map_last, tvb, offset, 1, ENC_BIG_ENDIAN);
878 if ((map & 0x80) || (map & 0x40)) {
879 proto_item_append_text (en, ", %s / %s",
880 (map & 0x80) ? "Not first" : "First",
881 (map & 0x40) ? "Not last" : "Last");
883 proto_item_append_text (en, ", Only one PDU");
888 proto_tree_add_item (field_tree, hf_map_unused, tvb, offset, 1, ENC_BIG_ENDIAN);
891 proto_tree_add_item (field_tree, hf_pdu_type_value, tvb, offset, 1, ENC_BIG_ENDIAN);
897 case Extra_Address_PDU:
898 case FEC_Address_PDU:
899 case Extra_FEC_Address_PDU:
900 /* Total Number of PDUs */
901 no_pdus = tvb_get_ntohs (tvb, offset);
903 proto_tree_add_item (p_mul_tree, hf_no_pdus, tvb, offset, 2, ENC_BIG_ENDIAN);
904 proto_item_append_text (ti, ", No PDUs: %u", no_pdus);
908 /* Sequence Number of PDUs */
909 seq_no = tvb_get_ntohs (tvb, offset);
910 proto_tree_add_item (p_mul_tree, hf_seq_no, tvb, offset, 2, ENC_BIG_ENDIAN);
911 proto_item_append_text (ti, ", Seq no: %u", seq_no);
915 /* Count of Destination Entries */
916 count = tvb_get_ntohs (tvb, offset);
917 proto_tree_add_item (p_mul_tree, hf_count_of_dest, tvb, offset, 2, ENC_BIG_ENDIAN);
922 proto_tree_add_item (p_mul_tree, hf_unused16, tvb, offset, 2, ENC_BIG_ENDIAN);
928 en = proto_tree_add_item (p_mul_tree, hf_checksum, tvb, offset, 2, ENC_BIG_ENDIAN);
929 checksum_tree = proto_item_add_subtree (en, ett_checksum);
930 len = tvb_length (tvb);
931 value = tvb_get_ephemeral_string (tvb, 0, len);
932 checksum1 = checksum (value, len, offset);
933 checksum2 = tvb_get_ntohs (tvb, offset);
934 if (checksum1 == checksum2) {
935 proto_item_append_text (en, " (correct)");
936 en = proto_tree_add_boolean (checksum_tree, hf_checksum_good, tvb,
938 PROTO_ITEM_SET_GENERATED (en);
939 en = proto_tree_add_boolean (checksum_tree, hf_checksum_bad, tvb,
941 PROTO_ITEM_SET_GENERATED (en);
943 proto_item_append_text (en, " (incorrect, should be 0x%04x)", checksum1);
944 expert_add_info_format (pinfo, en, PI_CHECKSUM, PI_WARN, "Bad checksum");
945 en = proto_tree_add_boolean (checksum_tree, hf_checksum_good, tvb,
947 PROTO_ITEM_SET_GENERATED (en);
948 en = proto_tree_add_boolean (checksum_tree, hf_checksum_bad, tvb,
950 PROTO_ITEM_SET_GENERATED (en);
954 if (pdu_type == Ack_PDU) {
955 /* Source ID of Ack Sender */
956 ip = tvb_get_ipv4 (tvb, offset);
957 SET_ADDRESS (&dst, AT_IPv4, sizeof(ip), ep_memdup (&ip, 4));
958 proto_tree_add_item (p_mul_tree, hf_source_id_ack, tvb, offset, 4, ENC_BIG_ENDIAN);
961 /* Count of Ack Info Entries */
962 count = tvb_get_ntohs (tvb, offset);
963 proto_tree_add_item (p_mul_tree, hf_ack_count, tvb, offset, 2, ENC_BIG_ENDIAN);
967 ip = tvb_get_ipv4 (tvb, offset);
968 SET_ADDRESS (&src, AT_IPv4, sizeof(ip), ep_memdup (&ip, 4));
969 proto_tree_add_item (p_mul_tree, hf_source_id, tvb, offset, 4, ENC_BIG_ENDIAN);
973 message_id = tvb_get_ntohl (tvb, offset);
974 if (use_relative_msgid) {
975 if (message_id_offset == 0) {
976 /* First P_Mul package - initialize message_id_offset */
977 message_id_offset = message_id;
979 message_id -= message_id_offset;
980 proto_tree_add_uint_format (p_mul_tree, hf_message_id, tvb, offset, 4,
981 message_id, "Message ID (MSID): %u"
982 " (relative message id)", message_id);
984 proto_tree_add_item (p_mul_tree, hf_message_id, tvb, offset, 4, ENC_BIG_ENDIAN);
988 proto_item_append_text (ti, ", MSID: %u", message_id);
991 if (pdu_type == Address_PDU || pdu_type == Announce_PDU ||
992 pdu_type == Extra_Address_PDU || pdu_type == FEC_Address_PDU ||
993 pdu_type == Extra_FEC_Address_PDU) {
995 ts.secs = tvb_get_ntohl (tvb, offset);
997 proto_tree_add_time (p_mul_tree, hf_expiry_time, tvb, offset, 4, &ts);
1001 if (pdu_type == FEC_Address_PDU || pdu_type == Extra_FEC_Address_PDU) {
1002 /* FEC Parameters Length */
1003 fec_len = tvb_get_guint8 (tvb, offset);
1004 proto_tree_add_item (p_mul_tree, hf_fec_len, tvb, offset, 1, ENC_BIG_ENDIAN);
1008 proto_tree_add_item (p_mul_tree, hf_fec_id, tvb, offset, 1, ENC_BIG_ENDIAN);
1012 /* FEC Parameters */
1013 proto_tree_add_none_format (p_mul_tree, hf_fec_parameters, tvb, offset,
1014 fec_len, "FEC Parameters (%d byte%s)",
1015 fec_len, plurality (fec_len, "", "s"));
1023 case Extra_Address_PDU:
1024 case FEC_Address_PDU:
1025 case Extra_FEC_Address_PDU:
1026 /* Count of Destination Entries */
1027 no_dest = tvb_get_ntohs (tvb, offset);
1028 proto_tree_add_item (p_mul_tree, hf_count_of_dest, tvb, offset, 2, ENC_BIG_ENDIAN);
1031 /* Length of Reserved Field */
1032 len = tvb_get_ntohs (tvb, offset);
1033 proto_tree_add_item (p_mul_tree, hf_length_of_res, tvb, offset, 2, ENC_BIG_ENDIAN);
1036 for (i = 0; i < no_dest; i++) {
1037 /* Destination Entry */
1038 en = proto_tree_add_none_format (p_mul_tree, hf_dest_entry, tvb,
1040 "Destination Entry #%d", i + 1);
1041 field_tree = proto_item_add_subtree (en, ett_dest_entry);
1043 /* Destination Id */
1044 ip = tvb_get_ipv4 (tvb, offset);
1045 SET_ADDRESS (&dst, AT_IPv4, sizeof(ip), ep_memdup(&ip, 4));
1046 proto_tree_add_item (field_tree, hf_dest_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1049 /* Message Sequence Number */
1050 proto_tree_add_item (field_tree, hf_msg_seq_no, tvb, offset, 4, ENC_BIG_ENDIAN);
1054 /* Reserved Field (variable length) */
1055 proto_tree_add_none_format (field_tree, hf_sym_key, tvb, offset,
1056 len, "Symmetric Key (%d byte%s)",
1057 len, plurality (len, "", "s"));
1061 if (use_seq_ack_analysis) {
1062 add_ack_analysis (tvb, pinfo, field_tree, offset, pdu_type, &src, &dst,
1066 if (no_dest == 0 && use_seq_ack_analysis) {
1067 /* Add Ack-Ack analysis */
1068 add_ack_analysis (tvb, pinfo, p_mul_tree, offset, pdu_type, &src, NULL,
1072 proto_item_append_text (ti, ", Count of Dest: %u", no_dest);
1076 /* Fragment of Data (variable length) */
1077 data_len = tvb_length_remaining (tvb, offset);
1078 proto_tree_add_none_format (p_mul_tree, hf_data_fragment, tvb, offset,
1079 data_len, "Fragment %d of Data (%d byte%s)",
1081 plurality (data_len, "", "s"));
1085 if (check_col (pinfo->cinfo, COL_INFO)) {
1086 message_id_list = ep_strbuf_new_label("");
1088 for (i = 0; i < count; i++) {
1089 /* Ack Info Entry */
1090 len = tvb_get_ntohs (tvb, offset);
1092 en = proto_tree_add_none_format (p_mul_tree, hf_ack_entry, tvb,
1094 "Ack Info Entry #%d", i + 1);
1095 field_tree = proto_item_add_subtree (en, ett_ack_entry);
1097 /* Length of Ack Info Entry */
1098 en = proto_tree_add_item (field_tree, hf_ack_length, tvb, offset, 2, ENC_BIG_ENDIAN);
1102 proto_item_append_text (en, " (invalid length)");
1103 expert_add_info_format (pinfo, en, PI_MALFORMED, PI_WARN,
1104 "Invalid ack info length");
1108 ip = tvb_get_ipv4 (tvb, offset);
1109 SET_ADDRESS (&src, AT_IPv4, sizeof(ip), ep_memdup (&ip, 4));
1110 proto_tree_add_item (field_tree, hf_source_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1114 message_id = tvb_get_ntohl (tvb, offset);
1115 if (use_relative_msgid) {
1116 if (message_id_offset == 0) {
1117 /* First P_Mul package - initialize message_id_offset */
1118 message_id_offset = message_id;
1120 message_id -= message_id_offset;
1121 proto_tree_add_uint_format (field_tree, hf_message_id, tvb, offset, 4,
1122 message_id, "Message ID (MSID): %u"
1123 " (relative message id)", message_id);
1125 proto_tree_add_item (field_tree, hf_message_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1129 if (check_col (pinfo->cinfo, COL_INFO)) {
1131 ep_strbuf_printf (message_id_list, "%u", message_id);
1133 ep_strbuf_append_printf (message_id_list, ",%u", message_id);
1138 gint num_seq_no = (len - 10) / 2;
1139 guint16 ack_seq_no, prev_ack_seq_no = 0;
1140 for (no_missing = 0; no_missing < num_seq_no; no_missing++) {
1141 /* Missing Data PDU Seq Number */
1142 ack_seq_no = tvb_get_ntohs (tvb, offset);
1143 if ((ack_seq_no != 0) && (no_missing < num_seq_no - 2) && tvb_get_ntohs (tvb, offset + 2) == 0) {
1144 /* We are handling a range */
1145 guint16 end_seq_no = tvb_get_ntohs (tvb, offset + 4);
1147 en = proto_tree_add_bytes_format (field_tree, hf_miss_seq_range,
1148 tvb, offset, 6, NULL,
1149 "Missing Data PDU Seq Range: %d - %d",
1150 ack_seq_no, end_seq_no);
1151 if (ack_seq_no >= end_seq_no) {
1152 proto_item_append_text (en, " (invalid)");
1153 expert_add_info_format (pinfo, en, PI_UNDECODED, PI_WARN,
1154 "Invalid missing sequence range");
1156 proto_tree *missing_tree;
1159 missing_tree = proto_item_add_subtree (en, ett_range_entry);
1161 for (sno = ack_seq_no; sno <= end_seq_no; sno++) {
1162 en = proto_tree_add_uint_format (missing_tree, hf_miss_seq_no,
1163 tvb, offset, 6, sno,
1164 "Missing Data PDU Seq Number: %d", sno);
1165 PROTO_ITEM_SET_GENERATED (en);
1167 tot_no_missing += (end_seq_no - ack_seq_no + 1);
1171 no_missing += 2; /* Skip the next two */
1172 prev_ack_seq_no = end_seq_no;
1174 /* No range, handle one seq no */
1175 en = proto_tree_add_item (field_tree, hf_miss_seq_no, tvb,offset, 2, ENC_BIG_ENDIAN);
1178 if (ack_seq_no == 0) {
1179 proto_item_append_text (en, " (invalid)");
1180 expert_add_info_format (pinfo, en, PI_UNDECODED, PI_WARN,
1181 "Invalid missing seq number");
1182 } else if (ack_seq_no <= prev_ack_seq_no) {
1183 proto_item_append_text (en, " (end of list indicator)");
1187 prev_ack_seq_no = ack_seq_no;
1192 if (use_seq_ack_analysis) {
1193 add_ack_analysis (tvb, pinfo, field_tree, offset, pdu_type, &src, &dst,
1194 message_id, no_missing);
1197 proto_item_append_text (ti, ", Count of Ack: %u", count);
1199 if (tvb_length_remaining (tvb, offset) >= 8) {
1200 /* Timestamp Option (in units of 100ms) */
1203 timestamp = tvb_get_ntoh64 (tvb, offset);
1204 proto_tree_add_uint64_format (p_mul_tree, hf_timestamp_option, tvb,
1205 offset, 8, timestamp,
1206 "Timestamp: %" G_GINT64_MODIFIER "d.%d second%s (%" G_GINT64_MODIFIER "u)",
1207 timestamp / 10, (int) timestamp % 10,
1208 (timestamp == 10) ? "" : "s", timestamp);
1212 if (tot_no_missing) {
1213 proto_item_append_text (ti, ", Missing seq numbers: %u", tot_no_missing);
1214 en = proto_tree_add_uint (p_mul_tree, hf_tot_miss_seq_no, tvb, 0, 0,
1216 PROTO_ITEM_SET_GENERATED (en);
1217 expert_add_info_format (pinfo, en, PI_RESPONSE_CODE, PI_NOTE,
1218 "Missing seq numbers: %d", tot_no_missing);
1222 case Discard_Message_PDU:
1223 seq_no = G_MAXUINT16; /* To make the seq_no uniq */
1227 /* Announced Multicast Group */
1228 proto_tree_add_item (p_mul_tree, hf_ann_mc_group, tvb, offset, 4, ENC_BIG_ENDIAN);
1231 for (i = 0; i < count; i++) {
1232 /* Destination Id */
1233 proto_tree_add_item (p_mul_tree, hf_dest_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1241 /* Multicast Group */
1242 proto_tree_add_item (p_mul_tree, hf_mc_group, tvb, offset, 4, ENC_BIG_ENDIAN);
1251 /* Add SEQ/ACK analysis entry */
1252 if (use_seq_ack_analysis && (pdu_type <= Discard_Message_PDU) &&
1253 (pdu_type != Ack_PDU) && (pdu_type != Address_PDU || no_dest != 0))
1255 add_seq_analysis (tvb, pinfo, p_mul_tree, &src, offset, pdu_type,
1256 message_id, seq_no, tot_no_missing);
1259 if (check_col (pinfo->cinfo, COL_INFO)) {
1260 /* Check if printing Ack-Ack */
1261 if (pdu_type == Address_PDU && no_dest == 0) {
1262 col_append_str (pinfo->cinfo, COL_INFO, get_type (Ack_Ack_PDU));
1264 col_append_str (pinfo->cinfo, COL_INFO, get_type (pdu_type));
1266 if (pdu_type == Address_PDU || pdu_type == Extra_Address_PDU ||
1267 pdu_type == FEC_Address_PDU || pdu_type == Extra_FEC_Address_PDU) {
1268 col_append_fstr (pinfo->cinfo, COL_INFO, ", No PDUs: %u", no_pdus);
1269 } else if (pdu_type == Data_PDU) {
1270 col_append_fstr (pinfo->cinfo, COL_INFO, ", Seq no: %u", seq_no);
1272 if (pdu_type == Address_PDU || pdu_type == Extra_Address_PDU ||
1273 pdu_type == FEC_Address_PDU || pdu_type == Extra_FEC_Address_PDU) {
1275 col_append_fstr (pinfo->cinfo, COL_INFO, ", Count of Dest: %u", no_dest);
1277 } else if (pdu_type == Ack_PDU) {
1278 if (tot_no_missing) {
1279 col_append_fstr (pinfo->cinfo, COL_INFO, ", Missing seq numbers: %u",
1282 col_append_fstr (pinfo->cinfo, COL_INFO, ", Count of Ack: %u", count);
1284 if (pdu_type != Ack_PDU) {
1285 col_append_fstr (pinfo->cinfo, COL_INFO, ", MSID: %u", message_id);
1287 if (message_id_list && message_id_list->len > 0) {
1288 col_append_fstr (pinfo->cinfo, COL_INFO, ", MSID: %s", message_id_list->str);
1293 if (p_mul_reassemble) {
1294 save_fragmented = pinfo->fragmented;
1296 if (pdu_type == Address_PDU && no_pdus > 0) {
1297 /* Start fragment table */
1298 fragment_start_seq_check (pinfo, message_id, p_mul_fragment_table,
1300 } else if (pdu_type == Data_PDU) {
1301 tvbuff_t *new_tvb = NULL;
1303 pinfo->fragmented = TRUE;
1305 /* Add fragment to fragment table */
1306 frag_msg = fragment_add_seq_check (tvb, offset, pinfo, message_id,
1307 p_mul_fragment_table,
1308 p_mul_reassembled_table, seq_no - 1,
1310 new_tvb = process_reassembled_data (tvb, offset, pinfo,
1311 "Reassembled P_MUL", frag_msg,
1312 &p_mul_frag_items, NULL, tree);
1315 col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembled)");
1318 dissect_reassembled_data (new_tvb, pinfo, tree);
1322 pinfo->fragmented = save_fragmented;
1325 /* Update length of P_Mul packet and check length values */
1326 proto_item_set_len (ti, offset);
1327 if (pdu_length != (offset + data_len)) {
1328 proto_item_append_text (len_en, " (incorrect, should be: %d)",
1330 expert_add_info_format (pinfo, len_en, PI_MALFORMED, PI_WARN,
1331 "Incorrect length field");
1332 } else if ((len = tvb_length_remaining (tvb, pdu_length)) > 0) {
1333 proto_item_append_text (len_en, " (more data in packet: %d)", len);
1334 expert_add_info_format (pinfo, len_en, PI_MALFORMED, PI_WARN,
1335 "More data in packet");
1339 static void p_mul_init_routine (void)
1341 fragment_table_init (&p_mul_fragment_table);
1342 reassembled_table_init (&p_mul_reassembled_table);
1343 message_id_offset = 0;
1345 if (p_mul_id_hash_table) {
1346 g_hash_table_destroy (p_mul_id_hash_table);
1349 if (p_mul_package_data_list) {
1350 g_list_foreach (p_mul_package_data_list, (GFunc)p_mul_package_data_destroy, NULL);
1351 g_list_free (p_mul_package_data_list);
1354 p_mul_id_hash_table = g_hash_table_new_full (p_mul_id_hash, p_mul_id_hash_equal, NULL, (GDestroyNotify)p_mul_id_value_destroy);
1355 p_mul_package_data_list = NULL;
1358 void proto_register_p_mul (void)
1360 static hf_register_info hf[] = {
1362 { "Length of PDU", "p_mul.length", FT_UINT16, BASE_DEC,
1363 NULL, 0x0, NULL, HFILL } },
1365 { "Priority", "p_mul.priority", FT_UINT8, BASE_DEC,
1366 NULL, 0x0, NULL, HFILL } },
1368 { "First", "p_mul.first", FT_BOOLEAN, 8,
1369 TFS (&no_yes), 0x80, NULL, HFILL } },
1371 { "Last", "p_mul.last", FT_BOOLEAN, 8,
1372 TFS (&no_yes), 0x40, NULL, HFILL } },
1374 { "MAP unused", "p_mul.unused", FT_UINT8, BASE_DEC,
1375 NULL, 0xC0, NULL, HFILL } },
1377 { "PDU Type", "p_mul.pdu_type", FT_UINT8, BASE_DEC,
1378 VALS (pdu_vals), 0x3F, NULL, HFILL } },
1379 { &hf_pdu_type_value,
1380 { "PDU Type", "p_mul.pdu_type_value", FT_UINT8, BASE_DEC,
1381 VALS (pdu_vals), 0x3F, NULL, HFILL } },
1383 { "Total Number of PDUs", "p_mul.no_pdus", FT_UINT16, BASE_DEC,
1384 NULL, 0x0, NULL, HFILL } },
1386 { "Sequence Number of PDUs", "p_mul.seq_no", FT_UINT16, BASE_DEC,
1387 NULL, 0x0, NULL, HFILL } },
1389 { "Unused", "p_mul.unused", FT_UINT8, BASE_DEC,
1390 NULL, 0x0, NULL, HFILL } },
1392 { "Unused", "p_mul.unused", FT_UINT16, BASE_DEC,
1393 NULL, 0x0, NULL, HFILL } },
1395 { "Checksum", "p_mul.checksum", FT_UINT16, BASE_HEX,
1396 NULL, 0x0, NULL, HFILL } },
1397 { &hf_checksum_good,
1398 { "Good", "p_mul.checksum_good", FT_BOOLEAN, BASE_NONE,
1399 NULL, 0x0, "True: checksum matches packet content; False: doesn't match content or not checked", HFILL } },
1401 { "Bad", "p_mul.checksum_bad", FT_BOOLEAN, BASE_NONE,
1402 NULL, 0x0, "True: checksum doesn't match packet content; False: matches content or not checked", HFILL } },
1403 { &hf_source_id_ack,
1404 { "Source ID of Ack Sender", "p_mul.source_id_ack", FT_IPv4, BASE_NONE,
1405 NULL, 0x0, NULL, HFILL } },
1407 { "Source ID", "p_mul.source_id", FT_IPv4, BASE_NONE,
1408 NULL, 0x0, NULL, HFILL } },
1410 { "Message ID (MSID)", "p_mul.message_id", FT_UINT32, BASE_DEC,
1411 NULL, 0x0, "Message ID", HFILL } },
1413 { "Expiry Time", "p_mul.expiry_time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1414 NULL, 0x0, NULL, HFILL } },
1416 { "Multicast Group", "p_mul.mc_group", FT_UINT32, BASE_DEC,
1417 NULL, 0x0, NULL, HFILL } },
1419 { "Announced Multicast Group", "p_mul.ann_mc_group", FT_UINT32, BASE_DEC,
1420 NULL, 0x0, NULL, HFILL } },
1422 { "FEC Parameter Length", "p_mul.fec.length", FT_UINT8, BASE_DEC,
1423 NULL, 0x0, "Forward Error Correction Parameter Length", HFILL } },
1425 { "FEC ID", "p_mul.fec.id", FT_UINT8, BASE_HEX,
1426 NULL, 0x0, "Forward Error Correction ID", HFILL } },
1427 { &hf_fec_parameters,
1428 { "FEC Parameters", "p_mul.fec.parameters", FT_NONE, BASE_NONE,
1429 NULL, 0x0, "Forward Error Correction Parameters", HFILL } },
1430 { &hf_count_of_dest,
1431 { "Count of Destination Entries", "p_mul.dest_count", FT_UINT16,BASE_DEC,
1432 NULL, 0x0, NULL, HFILL } },
1433 { &hf_length_of_res,
1434 { "Length of Reserved Field", "p_mul.reserved_length",FT_UINT16,BASE_DEC,
1435 NULL, 0x0, NULL, HFILL } },
1437 { "Count of Ack Info Entries", "p_mul.ack_count", FT_UINT16, BASE_DEC,
1438 NULL, 0x0, NULL, HFILL } },
1440 { "Ack Info Entry", "p_mul.ack_info_entry", FT_NONE, BASE_NONE,
1441 NULL, 0x0, NULL, HFILL } },
1443 { "Length of Ack Info Entry", "p_mul.ack_length", FT_UINT16, BASE_DEC,
1444 NULL, 0x0, NULL, HFILL } },
1446 { "Missing Data PDU Seq Number", "p_mul.missing_seq_no", FT_UINT16,
1447 BASE_DEC, NULL, 0x0, NULL, HFILL } },
1448 { &hf_miss_seq_range,
1449 { "Missing Data PDU Seq Range", "p_mul.missing_seq_range", FT_BYTES,
1450 BASE_NONE, NULL, 0x0, NULL, HFILL } },
1451 { &hf_tot_miss_seq_no,
1452 { "Total Number of Missing Data PDU Sequence Numbers",
1453 "p_mul.no_missing_seq_no", FT_UINT16, BASE_DEC, NULL, 0x0,
1455 { &hf_timestamp_option,
1456 { "Timestamp Option", "p_mul.timestamp", FT_UINT64, BASE_DEC,
1457 NULL, 0x0, "Timestamp Option (in units of 100ms)", HFILL } },
1459 { "Destination Entry", "p_mul.dest_entry", FT_NONE, BASE_NONE,
1460 NULL, 0x0, NULL, HFILL } },
1462 { "Destination ID", "p_mul.dest_id", FT_IPv4, BASE_NONE,
1463 NULL, 0x0, NULL, HFILL } },
1465 { "Message Sequence Number", "p_mul.msg_seq_no", FT_UINT16, BASE_DEC,
1466 NULL, 0x0, NULL, HFILL } },
1468 { "Symmetric Key", "p_mul.sym_key", FT_NONE, BASE_NONE,
1469 NULL, 0x0, NULL, HFILL } },
1470 { &hf_data_fragment,
1471 { "Fragment of Data", "p_mul.data_fragment", FT_NONE, BASE_NONE,
1472 NULL, 0x0, NULL, HFILL } },
1474 /* Fragment entries */
1475 { &hf_msg_fragments,
1476 { "Message fragments", "p_mul.fragments", FT_NONE, BASE_NONE,
1477 NULL, 0x00, NULL, HFILL } },
1479 { "Message fragment", "p_mul.fragment", FT_FRAMENUM, BASE_NONE,
1480 NULL, 0x00, NULL, HFILL } },
1481 { &hf_msg_fragment_overlap,
1482 { "Message fragment overlap", "p_mul.fragment.overlap", FT_BOOLEAN,
1483 BASE_NONE, NULL, 0x0, NULL, HFILL } },
1484 { &hf_msg_fragment_overlap_conflicts,
1485 { "Message fragment overlapping with conflicting data",
1486 "p_mul.fragment.overlap.conflicts", FT_BOOLEAN, BASE_NONE, NULL,
1487 0x0, NULL, HFILL } },
1488 { &hf_msg_fragment_multiple_tails,
1489 { "Message has multiple tail fragments",
1490 "p_mul.fragment.multiple_tails", FT_BOOLEAN, BASE_NONE,
1491 NULL, 0x0, NULL, HFILL } },
1492 { &hf_msg_fragment_too_long_fragment,
1493 { "Message fragment too long", "p_mul.fragment.too_long_fragment",
1494 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL,
1496 { &hf_msg_fragment_error,
1497 { "Message defragmentation error", "p_mul.fragment.error", FT_FRAMENUM,
1498 BASE_NONE, NULL, 0x00, NULL, HFILL } },
1499 { &hf_msg_fragment_count,
1500 { "Message fragment count", "p_mul.fragment.count", FT_UINT32, BASE_DEC,
1501 NULL, 0x00, NULL, HFILL } },
1502 { &hf_msg_reassembled_in,
1503 { "Reassembled in", "p_mul.reassembled.in", FT_FRAMENUM, BASE_NONE,
1504 NULL, 0x00, NULL, HFILL } },
1505 { &hf_msg_reassembled_length,
1506 { "Reassembled P_MUL length", "p_mul.reassembled.length", FT_UINT32, BASE_DEC,
1507 NULL, 0x00, NULL, HFILL } },
1510 ** Ack matching / Resend
1512 { &hf_analysis_ack_time,
1513 { "Ack Time", "p_mul.analysis.ack_time", FT_RELATIVE_TIME, BASE_NONE,
1514 NULL, 0x0, "The time between the Last PDU and the Ack", HFILL } },
1515 { &hf_analysis_trans_time,
1516 { "Transfer Time", "p_mul.analysis.trans_time", FT_RELATIVE_TIME, BASE_NONE,
1517 NULL, 0x0, "The time between the first Address PDU and the Ack", HFILL } },
1518 { &hf_analysis_retrans_time,
1519 { "Retransmission Time", "p_mul.analysis.retrans_time", FT_RELATIVE_TIME, BASE_NONE,
1520 NULL, 0x0, "The time between the last PDU and this PDU", HFILL } },
1521 { &hf_analysis_total_retrans_time,
1522 { "Total Retransmission Time", "p_mul.analysis.total_retrans_time", FT_RELATIVE_TIME, BASE_NONE,
1523 NULL, 0x0, "The time between the first PDU and this PDU", HFILL } },
1524 { &hf_analysis_addr_pdu_time,
1525 { "Time since Address PDU", "p_mul.analysis.elapsed_time", FT_RELATIVE_TIME, BASE_NONE,
1526 NULL, 0x0, "The time between the Address PDU and this PDU", HFILL } },
1527 { &hf_analysis_prev_pdu_time,
1528 { "PDU Delay", "p_mul.analysis.pdu_delay", FT_RELATIVE_TIME, BASE_NONE,
1529 NULL, 0x0, "The time between the last PDU and this PDU", HFILL } },
1530 { &hf_analysis_last_pdu_num,
1531 { "Last Data PDU in", "p_mul.analysis.last_pdu_in", FT_FRAMENUM, BASE_NONE,
1532 NULL, 0x0, "The last Data PDU found in this frame", HFILL } },
1533 { &hf_analysis_addr_pdu_num,
1534 { "Address PDU in", "p_mul.analysis.addr_pdu_in", FT_FRAMENUM, BASE_NONE,
1535 NULL, 0x0, "The Address PDU is found in this frame", HFILL } },
1536 { &hf_analysis_prev_pdu_num,
1537 { "Previous PDU in", "p_mul.analysis.prev_pdu_in", FT_FRAMENUM, BASE_NONE,
1538 NULL, 0x0, "The previous PDU is found in this frame", HFILL } },
1539 { &hf_analysis_ack_num,
1540 { "Ack PDU in", "p_mul.analysis.ack_in", FT_FRAMENUM, BASE_NONE,
1541 NULL, 0x0, "This packet has an Ack in this frame", HFILL } },
1542 { &hf_analysis_addr_pdu_missing,
1543 { "Address PDU missing", "p_mul.analysis.addr_pdu_missing", FT_NONE, BASE_NONE,
1544 NULL, 0x0, "The Address PDU for this packet is missing", HFILL } },
1545 { &hf_analysis_prev_pdu_missing,
1546 { "Previous PDU missing", "p_mul.analysis.prev_pdu_missing", FT_NONE, BASE_NONE,
1547 NULL, 0x0, "The previous PDU for this packet is missing", HFILL } },
1548 { &hf_analysis_ack_missing,
1549 { "Ack PDU missing", "p_mul.analysis.ack_missing", FT_NONE, BASE_NONE,
1550 NULL, 0x0, "The acknowledgement for this packet is missing", HFILL } },
1551 { &hf_analysis_retrans_no,
1552 { "Retransmission #", "p_mul.analysis.retrans_no", FT_UINT32, BASE_DEC,
1553 NULL, 0x0, "Retransmission count", HFILL } },
1554 { &hf_analysis_ack_dup_no,
1555 { "Duplicate ACK #", "p_mul.analysis.dup_ack_no", FT_UINT32, BASE_DEC,
1556 NULL, 0x0, "Duplicate Ack count", HFILL } },
1557 { &hf_analysis_msg_resend_from,
1558 { "Retransmission of Message in", "p_mul.analysis.msg_first_in",
1559 FT_FRAMENUM, BASE_NONE,
1560 NULL, 0x0, "This Message was first sent in this frame", HFILL } },
1561 { &hf_analysis_ack_resend_from,
1562 { "Retransmission of Ack in", "p_mul.analysis.ack_first_in",
1563 FT_FRAMENUM, BASE_NONE,
1564 NULL, 0x0, "This Ack was first sent in this frame", HFILL } },
1565 { &hf_analysis_total_time,
1566 { "Total Time", "p_mul.analysis.total_time", FT_RELATIVE_TIME, BASE_NONE,
1567 NULL, 0x0, "The time between the first and the last Address PDU", HFILL } },
1570 static gint *ett[] = {
1579 &ett_seq_ack_analysis,
1584 module_t *p_mul_module;
1586 proto_p_mul = proto_register_protocol (PNAME, PSNAME, PFNAME);
1587 register_dissector(PFNAME, dissect_p_mul, proto_p_mul);
1589 proto_register_field_array (proto_p_mul, hf, array_length (hf));
1590 proto_register_subtree_array (ett, array_length (ett));
1591 register_init_routine (&p_mul_init_routine);
1593 /* Set default UDP ports */
1594 range_convert_str (&global_p_mul_port_range, DEFAULT_P_MUL_PORT_RANGE,
1597 /* Register our configuration options */
1598 p_mul_module = prefs_register_protocol (proto_p_mul,
1599 proto_reg_handoff_p_mul);
1601 prefs_register_obsolete_preference (p_mul_module, "tport");
1602 prefs_register_obsolete_preference (p_mul_module, "rport");
1603 prefs_register_obsolete_preference (p_mul_module, "dport");
1604 prefs_register_obsolete_preference (p_mul_module, "aport");
1606 prefs_register_range_preference (p_mul_module, "udp_ports",
1607 "P_Mul port numbers",
1608 "Port numbers used for P_Mul traffic",
1609 &global_p_mul_port_range, MAX_UDP_PORT);
1610 prefs_register_bool_preference (p_mul_module, "reassemble",
1611 "Reassemble fragmented P_Mul packets",
1612 "Reassemble fragmented P_Mul packets",
1614 prefs_register_bool_preference (p_mul_module, "relative_msgid",
1615 "Use relative Message ID",
1616 "Make the P_Mul dissector use relative"
1617 " message id number instead of absolute"
1618 " ones", &use_relative_msgid);
1619 prefs_register_bool_preference (p_mul_module, "seq_ack_analysis",
1621 "Calculate sequence/acknowledgement analysis",
1622 &use_seq_ack_analysis);
1623 prefs_register_enum_preference (p_mul_module, "decode",
1624 "Decode Data PDU as",
1625 "Type of content in Data_PDU",
1626 &decode_option, decode_options, FALSE);
1629 static void range_delete_callback (guint32 port)
1631 dissector_delete_uint ("udp.port", port, p_mul_handle);
1634 static void range_add_callback (guint32 port)
1636 dissector_add_uint ("udp.port", port, p_mul_handle);
1639 void proto_reg_handoff_p_mul (void)
1641 static gboolean p_mul_prefs_initialized = FALSE;
1642 static range_t *p_mul_port_range;
1644 if (!p_mul_prefs_initialized) {
1645 p_mul_handle = find_dissector(PFNAME);
1646 p_mul_prefs_initialized = TRUE;
1647 data_handle = find_dissector ("data");
1649 range_foreach (p_mul_port_range, range_delete_callback);
1650 g_free (p_mul_port_range);
1653 /* Save port number for later deletion */
1654 p_mul_port_range = range_copy (global_p_mul_port_range);
1656 range_foreach (p_mul_port_range, range_add_callback);
1665 * indent-tabs-mode: nil
1668 * ex: set shiftwidth=2 tabstop=8 expandtab:
1669 * :indentSize=2:tabSize=8:noTabs=true: