MSWSP: add two more Property Sets
[wireshark-wip.git] / epan / dissectors / packet-p_mul.c
blobb49009126ed48e057db22a9e01b61364169cce14
1 /* packet-p_mul.c
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 * $Id$
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/
33 * TODO:
34 * - Obtain dedicated UDP port numbers
35 * - SEQ/ACK analysis for Announce/Request/Reject/Release PDU
38 #include "config.h"
40 #include <epan/packet.h>
41 #include <epan/to_str.h>
42 #include <epan/prefs.h>
43 #include <epan/reassemble.h>
44 #include <epan/expert.h>
45 #include <epan/asn1.h>
46 #include <epan/wmem/wmem.h>
47 #include <string.h>
49 #include "packet-cdt.h"
50 #include "packet-ber.h"
52 #define PNAME "P_Mul (ACP142)"
53 #define PSNAME "P_MUL"
54 #define PFNAME "p_mul"
56 /* Recommended UDP Port Numbers */
57 #define DEFAULT_P_MUL_PORT_RANGE ""
59 /* PDU Types */
60 #define Data_PDU 0x00
61 #define Ack_PDU 0x01
62 #define Address_PDU 0x02
63 #define Discard_Message_PDU 0x03
64 #define Announce_PDU 0x04
65 #define Request_PDU 0x05
66 #define Reject_PDU 0x06
67 #define Release_PDU 0x07
68 #define FEC_Address_PDU 0x08
69 #define Extra_Address_PDU 0x12
70 #define Extra_FEC_Address_PDU 0x18
71 #define Ack_Ack_PDU 0xFF /* Fake type to indicate Ack-Ack */
73 /* Type of content to decode from Data_PDU */
74 #define DECODE_NONE 0
75 #define DECODE_BER 1
76 #define DECODE_CDT 2
78 void proto_reg_handoff_p_mul (void);
80 static int proto_p_mul = -1;
82 static int hf_length = -1;
83 static int hf_priority = -1;
84 static int hf_map_first = -1;
85 static int hf_map_last = -1;
86 static int hf_map_unused = -1;
87 static int hf_pdu_type = -1;
88 static int hf_pdu_type_value = -1;
89 static int hf_no_pdus = -1;
90 static int hf_seq_no = -1;
91 static int hf_unused8 = -1;
92 static int hf_unused16 = -1;
93 static int hf_checksum = -1;
94 static int hf_checksum_good = -1;
95 static int hf_checksum_bad = -1;
96 static int hf_source_id_ack = -1;
97 static int hf_source_id = -1;
98 static int hf_message_id = -1;
99 static int hf_expiry_time = -1;
100 static int hf_mc_group = -1;
101 static int hf_ann_mc_group = -1;
102 static int hf_fec_len = -1;
103 static int hf_fec_id = -1;
104 static int hf_fec_parameters = -1;
105 static int hf_count_of_dest = -1;
106 static int hf_length_of_res = -1;
107 static int hf_ack_count = -1;
108 static int hf_ack_entry = -1;
109 static int hf_ack_length = -1;
110 static int hf_miss_seq_no = -1;
111 static int hf_miss_seq_range = -1;
112 static int hf_tot_miss_seq_no = -1;
113 static int hf_timestamp_option = -1;
114 static int hf_dest_entry = -1;
115 static int hf_dest_id = -1;
116 static int hf_msg_seq_no = -1;
117 static int hf_sym_key = -1;
118 static int hf_data_fragment = -1;
120 static int hf_msg_fragments = -1;
121 static int hf_msg_fragment = -1;
122 static int hf_msg_fragment_overlap = -1;
123 static int hf_msg_fragment_overlap_conflicts = -1;
124 static int hf_msg_fragment_multiple_tails = -1;
125 static int hf_msg_fragment_too_long_fragment = -1;
126 static int hf_msg_fragment_error = -1;
127 static int hf_msg_fragment_count = -1;
128 static int hf_msg_reassembled_in = -1;
129 static int hf_msg_reassembled_length = -1;
131 static int hf_analysis_ack_time = -1;
132 static int hf_analysis_trans_time = -1;
133 static int hf_analysis_retrans_time = -1;
134 static int hf_analysis_total_retrans_time = -1;
135 static int hf_analysis_last_pdu_num = -1;
136 static int hf_analysis_addr_pdu_num = -1;
137 static int hf_analysis_addr_pdu_time = -1;
138 static int hf_analysis_prev_pdu_num = -1;
139 static int hf_analysis_prev_pdu_time = -1;
140 static int hf_analysis_retrans_no = -1;
141 static int hf_analysis_ack_num = -1;
142 static int hf_analysis_ack_missing = -1;
143 static int hf_analysis_ack_dup_no = -1;
144 static int hf_analysis_msg_resend_from = -1;
145 static int hf_analysis_ack_resend_from = -1;
146 static int hf_analysis_total_time = -1;
148 static gint ett_p_mul = -1;
149 static gint ett_pdu_type = -1;
150 static gint ett_dest_entry = -1;
151 static gint ett_ack_entry = -1;
152 static gint ett_range_entry = -1;
153 static gint ett_checksum = -1;
154 static gint ett_seq_analysis = -1;
155 static gint ett_ack_analysis = -1;
156 static gint ett_seq_ack_analysis = -1;
157 static gint ett_msg_fragment = -1;
158 static gint ett_msg_fragments = -1;
160 static expert_field ei_more_data = EI_INIT;
161 static expert_field ei_checksum_bad = EI_INIT;
162 static expert_field ei_tot_miss_seq_no = EI_INIT;
163 static expert_field ei_miss_seq_no = EI_INIT;
164 static expert_field ei_analysis_ack_missing = EI_INIT;
165 static expert_field ei_miss_seq_range = EI_INIT;
166 static expert_field ei_address_pdu_missing = EI_INIT;
167 static expert_field ei_analysis_ack_dup_no = EI_INIT;
168 static expert_field ei_length = EI_INIT;
169 static expert_field ei_analysis_prev_pdu_missing = EI_INIT;
170 static expert_field ei_message_discarded = EI_INIT;
171 static expert_field ei_ack_length = EI_INIT;
172 static expert_field ei_analysis_retrans_no = EI_INIT;
174 static dissector_handle_t p_mul_handle = NULL;
176 static dissector_handle_t data_handle = NULL;
178 typedef struct _p_mul_id_key {
179 guint32 id;
180 guint16 seq;
181 address addr;
182 } p_mul_id_key;
184 typedef struct _p_mul_seq_val {
185 gint msg_type; /* Message type */
186 guint32 prev_msg_id; /* Previous message package num */
187 nstime_t prev_msg_time; /* Previous message receive time */
188 guint32 addr_id; /* PDU package num for Address_PDU */
189 nstime_t addr_time; /* PDU received time for Address_PDU */
190 guint32 pdu_id; /* PDU package num */
191 nstime_t pdu_time; /* PDU receive time */
192 guint32 prev_pdu_id; /* Previous PDU package num */
193 nstime_t prev_pdu_time; /* Previous PDU receive time */
194 guint16 last_found_pdu; /* Last PDU num */
195 nstime_t first_msg_time; /* First message receive time */
196 guint32 msg_resend_count; /* Message resend counter */
197 GHashTable *ack_data;
198 } p_mul_seq_val;
200 typedef struct _p_mul_ack_data {
201 guint32 ack_id; /* Ack PDU package num */
202 guint32 ack_resend_count; /* Ack resend counter */
203 } p_mul_ack_data;
205 /* Hash table with current data for seq/ack analysis */
206 static GHashTable *p_mul_id_hash_table = NULL;
208 /* List of hash tables stored in each frame */
209 static GList *p_mul_package_data_list = NULL;
211 /* User definable values to use for dissection */
212 static range_t *global_p_mul_port_range;
213 static gboolean p_mul_reassemble = TRUE;
214 static gint decode_option = DECODE_NONE;
215 static gboolean use_relative_msgid = TRUE;
216 static gboolean use_seq_ack_analysis = TRUE;
218 static reassembly_table p_mul_reassembly_table;
220 static guint32 message_id_offset = 0;
222 static const fragment_items p_mul_frag_items = {
223 /* Fragment subtrees */
224 &ett_msg_fragment,
225 &ett_msg_fragments,
226 /* Fragment fields */
227 &hf_msg_fragments,
228 &hf_msg_fragment,
229 &hf_msg_fragment_overlap,
230 &hf_msg_fragment_overlap_conflicts,
231 &hf_msg_fragment_multiple_tails,
232 &hf_msg_fragment_too_long_fragment,
233 &hf_msg_fragment_error,
234 &hf_msg_fragment_count,
235 /* Reassembled in field */
236 &hf_msg_reassembled_in,
237 /* Reassembled length field */
238 &hf_msg_reassembled_length,
239 /* Reassembled data field */
240 NULL,
241 /* Tag */
242 "Message fragments"
245 static const value_string pdu_vals[] = {
246 { Data_PDU, "Data PDU" },
247 { Ack_PDU, "Ack PDU" },
248 { Address_PDU, "Address PDU" },
249 { Discard_Message_PDU, "Discard Message PDU" },
250 { Announce_PDU, "Announce PDU" },
251 { Request_PDU, "Request PDU" },
252 { Reject_PDU, "Reject PDU" },
253 { Release_PDU, "Release PDU" },
254 { FEC_Address_PDU, "FEC Address PDU" },
255 { Extra_Address_PDU, "Extra Address PDU" },
256 { Extra_FEC_Address_PDU, "Extra FEC Address PDU" },
257 { Ack_Ack_PDU, "Ack-Ack PDU" },
258 { 0, NULL }
261 static const enum_val_t decode_options[] = {
262 { "none", "No decoding", DECODE_NONE },
263 { "ber", "BER encoded ASN.1", DECODE_BER },
264 { "cdt", "Compressed Data Type", DECODE_CDT },
265 { NULL, NULL, 0 }
268 static const true_false_string no_yes = {
269 "No", "Yes"
272 static const gchar *get_type (guint8 value)
274 return val_to_str_const (value, pdu_vals, "Unknown");
278 /*Function checksum, found in ACP142 annex B-3 */
279 static guint16 checksum (guint8 *buffer, gint len, gint offset)
281 guint16 c0 = 0, c1 = 0, ret, ctmp;
282 gint16 cs;
283 guint8 *hpp, *pls;
285 if (len < offset+2) {
286 /* Buffer to small */
287 return 0;
290 buffer[offset] = 0;
291 buffer[offset+1] = 0;
292 ctmp = len - offset - 1;
294 pls = buffer + len;
295 hpp = buffer;
297 while (hpp < pls) {
298 if ((c0 += *hpp++) > 254) { c0 -= 255; }
299 if ((c1 += c0) > 254) { c1 -= 255; }
302 if ((cs = ((ctmp * c0) - c1) % 255) < 0) { cs += 255; }
303 ret = cs << 8;
304 if ((cs = (c1 - ((ctmp + 1L) * c0)) % 255) < 0) { cs += 255; }
305 ret |= cs;
307 return ret;
310 static guint p_mul_id_hash (gconstpointer k)
312 const p_mul_id_key *p_mul = (const p_mul_id_key *)k;
313 return p_mul->id;
316 static gint p_mul_id_hash_equal (gconstpointer k1, gconstpointer k2)
318 const p_mul_id_key *p_mul1 = (const p_mul_id_key *)k1;
319 const p_mul_id_key *p_mul2 = (const p_mul_id_key *)k2;
321 if (p_mul1->id != p_mul2->id)
322 return 0;
324 if (p_mul1->seq != p_mul2->seq)
325 return 0;
327 return (ADDRESSES_EQUAL (&p_mul1->addr, &p_mul2->addr));
330 static p_mul_seq_val *lookup_seq_val (guint32 message_id, guint16 seq_no,
331 address *addr)
333 p_mul_seq_val *pkg_data;
334 p_mul_id_key *p_mul_key = wmem_new(wmem_file_scope(), p_mul_id_key);
336 p_mul_key->id = message_id;
337 p_mul_key->seq = seq_no;
338 SE_COPY_ADDRESS(&p_mul_key->addr, addr);
340 pkg_data = (p_mul_seq_val *) g_hash_table_lookup (p_mul_id_hash_table, p_mul_key);
342 return pkg_data;
345 static void p_mul_id_value_destroy (p_mul_seq_val *pkg_data)
347 if (pkg_data->ack_data) {
348 g_hash_table_destroy (pkg_data->ack_data);
350 g_free (pkg_data);
353 static void p_mul_package_data_destroy (GHashTable *pkg_list, gpointer user_data _U_)
355 g_hash_table_destroy (pkg_list);
358 static void copy_hashtable_data (gpointer key, p_mul_ack_data *ack_data1, GHashTable *table)
360 p_mul_ack_data *ack_data2;
362 ack_data2 = wmem_new(wmem_file_scope(), p_mul_ack_data);
363 ack_data2->ack_id = ack_data1->ack_id;
364 ack_data2->ack_resend_count = ack_data1->ack_resend_count;
366 g_hash_table_insert (table, key, ack_data2);
369 static p_mul_seq_val *register_p_mul_id (packet_info *pinfo, address *addr, guint32 dstIP,
370 guint8 pdu_type, guint32 message_id,
371 guint16 seq_no, gint no_missing)
373 p_mul_seq_val *p_mul_data = NULL, *pkg_data = NULL;
374 p_mul_id_key *p_mul_key;
375 p_mul_ack_data *ack_data = NULL;
376 nstime_t addr_time, prev_time;
377 guint addr_id = 0, prev_id = 0;
378 guint16 last_found_pdu = 0;
379 gboolean missing_pdu = FALSE, need_set_address = FALSE;
380 GHashTable *pkg_list;
382 if (pinfo->flags.in_error_pkt) {
383 /* No analysis of error packets */
384 return NULL;
387 nstime_set_zero(&addr_time);
388 nstime_set_zero(&prev_time);
390 p_mul_key = wmem_new(wmem_file_scope(), p_mul_id_key);
392 if (!pinfo->fd->flags.visited &&
393 (pdu_type == Address_PDU || pdu_type == Data_PDU || pdu_type == Discard_Message_PDU))
395 /* Try to match corresponding address PDU */
396 p_mul_key->id = message_id;
397 p_mul_key->seq = 0;
398 SE_COPY_ADDRESS(&p_mul_key->addr, addr);
399 need_set_address = TRUE;
401 p_mul_data = (p_mul_seq_val *) g_hash_table_lookup (p_mul_id_hash_table, p_mul_key);
403 if (p_mul_data) {
404 /* Found address PDU */
405 last_found_pdu = p_mul_data->last_found_pdu;
406 p_mul_data->last_found_pdu = seq_no;
407 addr_id = p_mul_data->pdu_id;
408 addr_time = p_mul_data->pdu_time;
410 /* Save data for last found PDU */
411 p_mul_data->prev_pdu_id = pinfo->fd->num;
412 p_mul_data->prev_pdu_time = pinfo->fd->abs_ts;
414 if (pdu_type == Data_PDU && p_mul_data->msg_resend_count == 0 && last_found_pdu != seq_no - 1) {
415 /* Data_PDU and missing previous PDU */
416 missing_pdu = TRUE;
419 if (last_found_pdu) {
420 /* Try to match previous data PDU */
421 p_mul_key->seq = last_found_pdu;
422 p_mul_data = (p_mul_seq_val *) g_hash_table_lookup (p_mul_id_hash_table, p_mul_key);
425 if (p_mul_data) {
426 /* Found a previous PDU (Address or Data) */
427 if (p_mul_data->prev_msg_id > 0) {
428 prev_id = p_mul_data->prev_msg_id;
429 } else {
430 prev_id = p_mul_data->pdu_id;
432 prev_time = p_mul_data->pdu_time;
434 } else if (pdu_type == Address_PDU) {
435 addr_id = pinfo->fd->num;
436 addr_time = pinfo->fd->abs_ts;
440 pkg_list = (GHashTable *)p_get_proto_data(pinfo->fd, proto_p_mul, 0);
441 if (!pkg_list) {
442 /* Never saved list for this packet, create a new */
443 pkg_list = g_hash_table_new (NULL, NULL);
444 p_mul_package_data_list = g_list_append (p_mul_package_data_list, pkg_list);
445 p_add_proto_data (pinfo->fd, proto_p_mul, 0, pkg_list);
448 if (!pinfo->fd->flags.visited) {
449 p_mul_key->id = message_id;
450 p_mul_key->seq = seq_no;
451 if (!need_set_address) {
452 SE_COPY_ADDRESS(&p_mul_key->addr, addr);
454 p_mul_data = (p_mul_seq_val *) g_hash_table_lookup (p_mul_id_hash_table, p_mul_key);
456 if (p_mul_data) {
457 if (pdu_type == Ack_PDU) {
458 /* Only save this data if positive ack */
459 if (no_missing == 0) {
460 ack_data = (p_mul_ack_data *)g_hash_table_lookup (p_mul_data->ack_data, GUINT_TO_POINTER(dstIP));
461 if (!ack_data) {
462 /* Only save reference to first ACK */
463 ack_data = wmem_new0(wmem_file_scope(), p_mul_ack_data);
464 ack_data->ack_id = pinfo->fd->num;
465 g_hash_table_insert (p_mul_data->ack_data, GUINT_TO_POINTER(dstIP), ack_data);
466 } else {
467 /* Only count when resending */
468 ack_data->ack_resend_count++;
471 } else {
472 /* Message resent */
473 p_mul_data->msg_resend_count++;
474 p_mul_data->prev_msg_id = pinfo->fd->num;
475 p_mul_data->prev_msg_time = p_mul_data->pdu_time;
476 p_mul_data->pdu_time = pinfo->fd->abs_ts;
478 if (pdu_type == Data_PDU) {
479 p_mul_data->prev_pdu_id = prev_id;
480 p_mul_data->prev_pdu_time = prev_time;
483 } else {
484 /* New message */
485 if (pdu_type == Ack_PDU) {
486 p_mul_data = wmem_new0(wmem_file_scope(), p_mul_seq_val);
487 } else {
488 p_mul_data = (p_mul_seq_val *)g_malloc0(sizeof (p_mul_seq_val));
490 p_mul_data->msg_type = pdu_type;
491 if (pdu_type == Address_PDU || pdu_type == Ack_PDU) {
492 p_mul_data->ack_data = g_hash_table_new (NULL, NULL);
495 if (pdu_type == Ack_PDU) {
496 /* No matching message for this ack */
497 ack_data = wmem_new0(wmem_file_scope(), p_mul_ack_data);
498 ack_data->ack_id = pinfo->fd->num;
499 g_hash_table_insert (p_mul_data->ack_data, GUINT_TO_POINTER(dstIP), ack_data);
500 } else {
501 p_mul_data->pdu_id = pinfo->fd->num;
502 p_mul_data->pdu_time = pinfo->fd->abs_ts;
503 p_mul_data->addr_id = addr_id;
504 p_mul_data->addr_time = addr_time;
505 p_mul_data->first_msg_time = pinfo->fd->abs_ts;
507 if (pdu_type == Data_PDU && !missing_pdu) {
508 p_mul_data->prev_pdu_id = prev_id;
509 p_mul_data->prev_pdu_time = prev_time;
512 g_hash_table_insert (p_mul_id_hash_table, p_mul_key, p_mul_data);
516 /* Copy the current package data to the frame */
517 pkg_data = wmem_new(wmem_file_scope(), p_mul_seq_val);
518 *pkg_data = *p_mul_data;
519 if (p_mul_data->ack_data) {
520 /* Copy the hash table for ack data */
521 pkg_data->ack_data = g_hash_table_new (NULL, NULL);
522 g_hash_table_foreach (p_mul_data->ack_data, (GHFunc) copy_hashtable_data, pkg_data->ack_data);
524 g_hash_table_insert (pkg_list, GUINT_TO_POINTER(message_id), pkg_data);
525 } else {
526 /* Fetch last values from data saved in packet */
527 pkg_data = (p_mul_seq_val *)g_hash_table_lookup (pkg_list, GUINT_TO_POINTER(message_id));
530 DISSECTOR_ASSERT (pkg_data);
531 return pkg_data;
534 static void add_ack_analysis (tvbuff_t *tvb, packet_info *pinfo, proto_tree *p_mul_tree,
535 gint offset, guint8 pdu_type, address *src, address *dst,
536 guint32 message_id, gint no_missing)
538 proto_tree *analysis_tree = NULL;
539 proto_item *sa = NULL;
540 proto_item *en = NULL;
541 p_mul_seq_val *pkg_data = NULL;
542 p_mul_ack_data *ack_data = NULL;
543 gboolean item_added = FALSE;
544 guint32 dstIp;
545 nstime_t ns;
547 if (pinfo->flags.in_error_pkt) {
548 /* No analysis of error packets */
549 return;
552 if (pdu_type == Address_PDU) {
553 sa = proto_tree_add_text (p_mul_tree, tvb, 0, 0, "ACK analysis");
554 PROTO_ITEM_SET_GENERATED (sa);
555 analysis_tree = proto_item_add_subtree (sa, ett_ack_analysis);
557 /* Fetch package data */
558 if ((pkg_data = lookup_seq_val (message_id, 0, src)) == NULL) {
559 /* No need for seq/ack analysis yet */
560 return;
563 if (dst == NULL) {
564 /* Ack-Ack */
565 if (pkg_data->addr_id) {
566 en = proto_tree_add_uint (analysis_tree, hf_analysis_addr_pdu_num, tvb,
567 0, 0, pkg_data->addr_id);
568 PROTO_ITEM_SET_GENERATED (en);
570 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->addr_time);
571 en = proto_tree_add_time (analysis_tree, hf_analysis_total_time,
572 tvb, 0, 0, &ns);
573 PROTO_ITEM_SET_GENERATED (en);
574 } else {
575 proto_tree_add_expert(analysis_tree, pinfo, &ei_address_pdu_missing, tvb, offset, 0);
577 item_added = TRUE;
578 } else {
579 memcpy((guint8 *)&dstIp, dst->data, 4);
580 if (pkg_data->ack_data) {
581 ack_data = (p_mul_ack_data *)g_hash_table_lookup (pkg_data->ack_data, GUINT_TO_POINTER(dstIp));
584 /* Add reference to Ack_PDU */
585 if (ack_data && ack_data->ack_id) {
586 en = proto_tree_add_uint (analysis_tree, hf_analysis_ack_num, tvb,
587 0, 0, ack_data->ack_id);
588 PROTO_ITEM_SET_GENERATED (en);
589 item_added = TRUE;
590 } else if (!pkg_data->msg_resend_count) {
591 en = proto_tree_add_item (analysis_tree,
592 hf_analysis_ack_missing,
593 tvb, offset, 0, ENC_NA);
594 if (pinfo->fd->flags.visited) {
595 /* We do not know this on first visit and we do not want to
596 add a entry in the "Expert Severity Info" for this note */
597 expert_add_info(pinfo, en, &ei_analysis_ack_missing);
598 PROTO_ITEM_SET_GENERATED (en);
600 item_added = TRUE;
604 if (!item_added) {
605 PROTO_ITEM_SET_HIDDEN (sa);
607 } else if (pdu_type == Ack_PDU) {
608 sa = proto_tree_add_text (p_mul_tree, tvb, 0, 0, "SEQ/ACK analysis");
609 PROTO_ITEM_SET_GENERATED (sa);
610 analysis_tree = proto_item_add_subtree (sa, ett_seq_ack_analysis);
612 /* Fetch package data */
613 memcpy((guint8 *)&dstIp, dst->data, 4);
614 if ((pkg_data = register_p_mul_id (pinfo, src, dstIp, pdu_type, message_id, 0, no_missing)) == NULL) {
615 /* No need for seq/ack analysis yet */
616 return;
618 if (pkg_data->ack_data) {
619 ack_data = (p_mul_ack_data *)g_hash_table_lookup (pkg_data->ack_data, GUINT_TO_POINTER(dstIp));
622 /* Add reference to Address_PDU */
623 if (pkg_data->msg_type != Ack_PDU) {
624 en = proto_tree_add_uint (analysis_tree, hf_analysis_addr_pdu_num, tvb,
625 0, 0, pkg_data->pdu_id);
626 PROTO_ITEM_SET_GENERATED (en);
628 if (no_missing == 0) {
629 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->first_msg_time);
630 en = proto_tree_add_time (analysis_tree, hf_analysis_trans_time,
631 tvb, 0, 0, &ns);
632 PROTO_ITEM_SET_GENERATED (en);
634 } else {
635 proto_tree_add_expert(analysis_tree, pinfo, &ei_address_pdu_missing, tvb, offset, 0);
638 if (pkg_data->msg_type != Ack_PDU && pkg_data->prev_pdu_id) {
639 /* Add reference to previous PDU */
640 en = proto_tree_add_uint (analysis_tree, hf_analysis_last_pdu_num,
641 tvb, 0, 0, pkg_data->prev_pdu_id);
642 PROTO_ITEM_SET_GENERATED (en);
644 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->prev_pdu_time);
645 en = proto_tree_add_time (analysis_tree, hf_analysis_ack_time,
646 tvb, 0, 0, &ns);
647 PROTO_ITEM_SET_GENERATED (en);
650 if (ack_data && ack_data->ack_resend_count) {
651 /* Add resend statistics */
652 en = proto_tree_add_uint (analysis_tree, hf_analysis_ack_dup_no,
653 tvb, 0, 0, ack_data->ack_resend_count);
654 PROTO_ITEM_SET_GENERATED (en);
656 expert_add_info_format(pinfo, en, &ei_analysis_ack_dup_no, "Dup ACK #%d", ack_data->ack_resend_count);
658 en = proto_tree_add_uint (analysis_tree, hf_analysis_ack_resend_from,
659 tvb, 0, 0, ack_data->ack_id);
660 PROTO_ITEM_SET_GENERATED (en);
662 col_append_fstr (pinfo->cinfo, COL_INFO, "[Dup ACK %d#%d] ",
663 ack_data->ack_id, ack_data->ack_resend_count);
668 static p_mul_seq_val *add_seq_analysis (tvbuff_t *tvb, packet_info *pinfo,
669 proto_tree *p_mul_tree, address *src,
670 gint offset,
671 guint8 pdu_type, guint32 message_id,
672 guint16 seq_no, gint no_missing)
674 p_mul_seq_val *pkg_data;
675 proto_tree *analysis_tree;
676 proto_item *sa, *en = NULL, *eh = NULL;
677 gboolean item_added = FALSE;
678 nstime_t ns;
680 pkg_data = register_p_mul_id (pinfo, src, 0, pdu_type, message_id, seq_no,
681 no_missing);
683 if (!pkg_data) {
684 /* No need for seq/ack analysis */
685 return NULL;
688 sa = proto_tree_add_text (p_mul_tree, tvb, 0, 0, "SEQ analysis");
689 PROTO_ITEM_SET_GENERATED (sa);
690 analysis_tree = proto_item_add_subtree (sa, ett_seq_analysis);
692 if (pdu_type == Data_PDU || pdu_type == Discard_Message_PDU) {
693 /* Add reference to Address_PDU */
694 if (pkg_data->addr_id) {
695 en = proto_tree_add_uint (analysis_tree, hf_analysis_addr_pdu_num, tvb,
696 0, 0, pkg_data->addr_id);
697 PROTO_ITEM_SET_GENERATED (en);
699 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->addr_time);
700 en = proto_tree_add_time (analysis_tree, hf_analysis_addr_pdu_time,
701 tvb, 0, 0, &ns);
702 PROTO_ITEM_SET_GENERATED (en);
704 if (pkg_data->prev_pdu_id == pkg_data->addr_id) {
705 /* Previous pdu time is the same as time since address pdu */
706 en = proto_tree_add_time (analysis_tree, hf_analysis_prev_pdu_time,
707 tvb, 0, 0, &ns);
708 PROTO_ITEM_SET_GENERATED (en);
710 item_added = TRUE;
711 } else if (!pkg_data->msg_resend_count) {
712 proto_tree_add_expert(analysis_tree, pinfo, &ei_address_pdu_missing, tvb, offset, 0);
713 item_added = TRUE;
717 if ((pdu_type == Data_PDU) && (pkg_data->prev_pdu_id != pkg_data->addr_id)) {
718 /* Add reference to previous Data_PDU */
719 if (pkg_data->prev_pdu_id) {
720 en = proto_tree_add_uint (analysis_tree, hf_analysis_prev_pdu_num, tvb,
721 0, 0, pkg_data->prev_pdu_id);
722 PROTO_ITEM_SET_GENERATED (en);
724 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->prev_pdu_time);
725 en = proto_tree_add_time (analysis_tree, hf_analysis_prev_pdu_time,
726 tvb, 0, 0, &ns);
727 PROTO_ITEM_SET_GENERATED (en);
728 item_added = TRUE;
729 } else if (!pkg_data->msg_resend_count) {
730 proto_tree_add_expert(analysis_tree, pinfo, &ei_analysis_prev_pdu_missing, tvb, offset, 0);
731 item_added = TRUE;
735 if ((pdu_type == Address_PDU) || (pdu_type == Data_PDU) ||
736 (pdu_type == Discard_Message_PDU)) {
737 /* Add resend statistics */
738 if (pkg_data->msg_resend_count) {
739 en = proto_tree_add_uint (analysis_tree, hf_analysis_retrans_no,
740 tvb, 0, 0, pkg_data->msg_resend_count);
741 PROTO_ITEM_SET_GENERATED (en);
743 en = proto_tree_add_uint (analysis_tree, hf_analysis_msg_resend_from,
744 tvb, 0, 0, pkg_data->pdu_id);
745 PROTO_ITEM_SET_GENERATED (en);
747 expert_add_info_format(pinfo, en, &ei_analysis_retrans_no, "Retransmission #%d", pkg_data->msg_resend_count);
749 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->prev_msg_time);
750 en = proto_tree_add_time (analysis_tree, hf_analysis_retrans_time,
751 tvb, 0, 0, &ns);
752 PROTO_ITEM_SET_GENERATED (en);
754 nstime_delta (&ns, &pinfo->fd->abs_ts, &pkg_data->first_msg_time);
755 eh = proto_tree_add_time (analysis_tree, hf_analysis_total_retrans_time,
756 tvb, 0, 0, &ns);
757 PROTO_ITEM_SET_GENERATED (eh);
759 if (pkg_data->first_msg_time.secs == pkg_data->prev_msg_time.secs &&
760 pkg_data->first_msg_time.nsecs == pkg_data->prev_msg_time.nsecs) {
761 /* Time values does not differ, hide the total time */
762 PROTO_ITEM_SET_HIDDEN (eh);
764 item_added = TRUE;
766 col_append_fstr (pinfo->cinfo, COL_INFO, "[Retrans %d#%d] ",
767 pkg_data->pdu_id, pkg_data->msg_resend_count);
771 if (!item_added) {
772 PROTO_ITEM_SET_HIDDEN (sa);
775 return pkg_data;
779 static void dissect_reassembled_data (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
781 DISSECTOR_ASSERT(tvb != NULL);
783 switch (decode_option) {
784 case DECODE_BER:
785 dissect_unknown_ber (pinfo, tvb, 0, tree);
786 break;
787 case DECODE_CDT:
788 dissect_cdt (tvb, pinfo, tree);
789 break;
790 default:
791 call_dissector (data_handle, tvb, pinfo, tree);
792 break;
796 static void dissect_p_mul (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
798 proto_tree *p_mul_tree, *field_tree, *checksum_tree;
799 proto_item *ti, *en, *len_en;
800 gboolean save_fragmented;
801 guint32 message_id = 0, ip;
802 guint16 no_dest = 0, count = 0, len, data_len = 0;
803 guint16 checksum1, checksum2;
804 guint16 pdu_length, no_pdus = 0, seq_no = 0;
805 guint8 pdu_type, *value, map = 0, fec_len;
806 gint i, tot_no_missing = 0, no_missing = 0, offset = 0;
807 address src, dst;
808 wmem_strbuf_t *message_id_list = NULL;
809 nstime_t ts;
811 col_set_str (pinfo->cinfo, COL_PROTOCOL, "P_MUL");
812 col_clear (pinfo->cinfo, COL_INFO);
814 /* First fetch PDU Type */
815 pdu_type = tvb_get_guint8 (tvb, offset + 3) & 0x3F;
817 ti = proto_tree_add_item (tree, proto_p_mul, tvb, offset, -1, ENC_NA);
818 proto_item_append_text (ti, ", %s", get_type (pdu_type));
819 p_mul_tree = proto_item_add_subtree (ti, ett_p_mul);
821 /* Length of PDU */
822 pdu_length = tvb_get_ntohs (tvb, offset);
823 len_en = proto_tree_add_item (p_mul_tree, hf_length, tvb, offset, 2, ENC_BIG_ENDIAN);
824 offset += 2;
826 switch (pdu_type) {
828 case Data_PDU:
829 case Ack_PDU:
830 case Address_PDU:
831 case Discard_Message_PDU:
832 case Extra_Address_PDU:
833 case FEC_Address_PDU:
834 case Extra_FEC_Address_PDU:
835 /* Priority */
836 proto_tree_add_item (p_mul_tree, hf_priority, tvb, offset, 1, ENC_BIG_ENDIAN);
837 break;
839 default:
840 /* Unused */
841 proto_tree_add_item (p_mul_tree, hf_unused8, tvb, offset, 1, ENC_BIG_ENDIAN);
843 offset += 1;
845 /* MAP / PDU_Type */
846 en = proto_tree_add_uint_format_value(p_mul_tree, hf_pdu_type, tvb, offset, 1,
847 pdu_type, "%s (0x%02x)",
848 get_type (pdu_type), pdu_type);
849 field_tree = proto_item_add_subtree (en, ett_pdu_type);
851 if (pdu_type == Discard_Message_PDU) {
852 expert_add_info(pinfo, en, &ei_message_discarded);
855 switch (pdu_type) {
857 case Address_PDU:
858 case Announce_PDU:
859 case Extra_Address_PDU:
860 case FEC_Address_PDU:
861 case Extra_FEC_Address_PDU:
862 map = tvb_get_guint8 (tvb, offset);
863 proto_tree_add_item (field_tree, hf_map_first, tvb, offset, 1, ENC_BIG_ENDIAN);
864 proto_tree_add_item (field_tree, hf_map_last, tvb, offset, 1, ENC_BIG_ENDIAN);
865 if ((map & 0x80) || (map & 0x40)) {
866 proto_item_append_text (en, ", %s / %s",
867 (map & 0x80) ? "Not first" : "First",
868 (map & 0x40) ? "Not last" : "Last");
869 } else {
870 proto_item_append_text (en, ", Only one PDU");
872 break;
874 default:
875 proto_tree_add_item (field_tree, hf_map_unused, tvb, offset, 1, ENC_BIG_ENDIAN);
876 break;
878 proto_tree_add_item (field_tree, hf_pdu_type_value, tvb, offset, 1, ENC_BIG_ENDIAN);
879 offset += 1;
881 switch (pdu_type) {
883 case Address_PDU:
884 case Extra_Address_PDU:
885 case FEC_Address_PDU:
886 case Extra_FEC_Address_PDU:
887 /* Total Number of PDUs */
888 no_pdus = tvb_get_ntohs (tvb, offset);
889 seq_no = 0;
890 proto_tree_add_item (p_mul_tree, hf_no_pdus, tvb, offset, 2, ENC_BIG_ENDIAN);
891 proto_item_append_text (ti, ", No PDUs: %u", no_pdus);
892 break;
894 case Data_PDU:
895 /* Sequence Number of PDUs */
896 seq_no = tvb_get_ntohs (tvb, offset);
897 proto_tree_add_item (p_mul_tree, hf_seq_no, tvb, offset, 2, ENC_BIG_ENDIAN);
898 proto_item_append_text (ti, ", Seq no: %u", seq_no);
899 break;
901 case Announce_PDU:
902 /* Count of Destination Entries */
903 count = tvb_get_ntohs (tvb, offset);
904 proto_tree_add_item (p_mul_tree, hf_count_of_dest, tvb, offset, 2, ENC_BIG_ENDIAN);
905 break;
907 default:
908 /* Unused */
909 proto_tree_add_item (p_mul_tree, hf_unused16, tvb, offset, 2, ENC_BIG_ENDIAN);
910 break;
912 offset += 2;
914 /* Checksum */
915 en = proto_tree_add_item (p_mul_tree, hf_checksum, tvb, offset, 2, ENC_BIG_ENDIAN);
916 checksum_tree = proto_item_add_subtree (en, ett_checksum);
917 len = tvb_length (tvb);
918 value = tvb_get_string (wmem_packet_scope(), tvb, 0, len);
919 checksum1 = checksum (value, len, offset);
920 checksum2 = tvb_get_ntohs (tvb, offset);
921 if (checksum1 == checksum2) {
922 proto_item_append_text (en, " (correct)");
923 en = proto_tree_add_boolean (checksum_tree, hf_checksum_good, tvb,
924 offset, 2, TRUE);
925 PROTO_ITEM_SET_GENERATED (en);
926 en = proto_tree_add_boolean (checksum_tree, hf_checksum_bad, tvb,
927 offset, 2, FALSE);
928 PROTO_ITEM_SET_GENERATED (en);
929 } else {
930 proto_item_append_text (en, " (incorrect, should be 0x%04x)", checksum1);
931 expert_add_info(pinfo, en, &ei_checksum_bad);
932 en = proto_tree_add_boolean (checksum_tree, hf_checksum_good, tvb,
933 offset, 2, FALSE);
934 PROTO_ITEM_SET_GENERATED (en);
935 en = proto_tree_add_boolean (checksum_tree, hf_checksum_bad, tvb,
936 offset, 2, TRUE);
937 PROTO_ITEM_SET_GENERATED (en);
939 offset += 2;
941 if (pdu_type == Ack_PDU) {
942 /* Source ID of Ack Sender */
943 ip = tvb_get_ipv4 (tvb, offset);
944 SET_ADDRESS (&dst, AT_IPv4, sizeof(ip), wmem_memdup (wmem_packet_scope(), &ip, 4));
945 proto_tree_add_item (p_mul_tree, hf_source_id_ack, tvb, offset, 4, ENC_BIG_ENDIAN);
946 offset += 4;
948 /* Count of Ack Info Entries */
949 count = tvb_get_ntohs (tvb, offset);
950 proto_tree_add_item (p_mul_tree, hf_ack_count, tvb, offset, 2, ENC_BIG_ENDIAN);
951 offset += 2;
952 } else {
953 /* Source Id */
954 ip = tvb_get_ipv4 (tvb, offset);
955 SET_ADDRESS (&src, AT_IPv4, sizeof(ip), wmem_memdup (wmem_packet_scope(), &ip, 4));
956 proto_tree_add_item (p_mul_tree, hf_source_id, tvb, offset, 4, ENC_BIG_ENDIAN);
957 offset += 4;
959 /* Message Id */
960 message_id = tvb_get_ntohl (tvb, offset);
961 if (use_relative_msgid) {
962 if (message_id_offset == 0) {
963 /* First P_Mul package - initialize message_id_offset */
964 message_id_offset = message_id;
966 message_id -= message_id_offset;
967 proto_tree_add_uint_format_value(p_mul_tree, hf_message_id, tvb, offset, 4,
968 message_id, "%u (relative message id)", message_id);
969 } else {
970 proto_tree_add_item (p_mul_tree, hf_message_id, tvb, offset, 4, ENC_BIG_ENDIAN);
972 offset += 4;
974 proto_item_append_text (ti, ", MSID: %u", message_id);
977 if (pdu_type == Address_PDU || pdu_type == Announce_PDU ||
978 pdu_type == Extra_Address_PDU || pdu_type == FEC_Address_PDU ||
979 pdu_type == Extra_FEC_Address_PDU) {
980 /* Expiry Time */
981 ts.secs = tvb_get_ntohl (tvb, offset);
982 ts.nsecs = 0;
983 proto_tree_add_time (p_mul_tree, hf_expiry_time, tvb, offset, 4, &ts);
984 offset += 4;
987 if (pdu_type == FEC_Address_PDU || pdu_type == Extra_FEC_Address_PDU) {
988 /* FEC Parameters Length */
989 fec_len = tvb_get_guint8 (tvb, offset);
990 proto_tree_add_item (p_mul_tree, hf_fec_len, tvb, offset, 1, ENC_BIG_ENDIAN);
991 offset += 1;
993 /* FEC ID */
994 proto_tree_add_item (p_mul_tree, hf_fec_id, tvb, offset, 1, ENC_BIG_ENDIAN);
995 offset += 1;
997 if (fec_len > 0) {
998 /* FEC Parameters */
999 proto_tree_add_none_format (p_mul_tree, hf_fec_parameters, tvb, offset,
1000 fec_len, "FEC Parameters (%d byte%s)",
1001 fec_len, plurality (fec_len, "", "s"));
1002 offset += fec_len;
1006 switch (pdu_type) {
1008 case Address_PDU:
1009 case Extra_Address_PDU:
1010 case FEC_Address_PDU:
1011 case Extra_FEC_Address_PDU:
1012 /* Count of Destination Entries */
1013 no_dest = tvb_get_ntohs (tvb, offset);
1014 proto_tree_add_item (p_mul_tree, hf_count_of_dest, tvb, offset, 2, ENC_BIG_ENDIAN);
1015 offset += 2;
1017 /* Length of Reserved Field */
1018 len = tvb_get_ntohs (tvb, offset);
1019 proto_tree_add_item (p_mul_tree, hf_length_of_res, tvb, offset, 2, ENC_BIG_ENDIAN);
1020 offset += 2;
1022 for (i = 0; i < no_dest; i++) {
1023 /* Destination Entry */
1024 en = proto_tree_add_none_format (p_mul_tree, hf_dest_entry, tvb,
1025 offset, 8 + len,
1026 "Destination Entry #%d", i + 1);
1027 field_tree = proto_item_add_subtree (en, ett_dest_entry);
1029 /* Destination Id */
1030 ip = tvb_get_ipv4 (tvb, offset);
1031 SET_ADDRESS (&dst, AT_IPv4, sizeof(ip), wmem_memdup(wmem_packet_scope(), &ip, 4));
1032 proto_tree_add_item (field_tree, hf_dest_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1033 offset += 4;
1035 /* Message Sequence Number */
1036 proto_tree_add_item (field_tree, hf_msg_seq_no, tvb, offset, 4, ENC_BIG_ENDIAN);
1037 offset += 4;
1039 if (len > 0) {
1040 /* Reserved Field (variable length) */
1041 proto_tree_add_none_format (field_tree, hf_sym_key, tvb, offset,
1042 len, "Symmetric Key (%d byte%s)",
1043 len, plurality (len, "", "s"));
1044 offset += len;
1047 if (use_seq_ack_analysis) {
1048 add_ack_analysis (tvb, pinfo, field_tree, offset, pdu_type, &src, &dst,
1049 message_id, 0);
1052 if (no_dest == 0 && use_seq_ack_analysis) {
1053 /* Add Ack-Ack analysis */
1054 add_ack_analysis (tvb, pinfo, p_mul_tree, offset, pdu_type, &src, NULL,
1055 message_id, 0);
1058 proto_item_append_text (ti, ", Count of Dest: %u", no_dest);
1059 break;
1061 case Data_PDU:
1062 /* Fragment of Data (variable length) */
1063 data_len = tvb_length_remaining (tvb, offset);
1064 proto_tree_add_none_format (p_mul_tree, hf_data_fragment, tvb, offset,
1065 data_len, "Fragment %d of Data (%d byte%s)",
1066 seq_no, data_len,
1067 plurality (data_len, "", "s"));
1068 break;
1070 case Ack_PDU:
1071 message_id_list = wmem_strbuf_new_label(wmem_packet_scope());
1073 for (i = 0; i < count; i++) {
1074 /* Ack Info Entry */
1075 len = tvb_get_ntohs (tvb, offset);
1077 en = proto_tree_add_none_format (p_mul_tree, hf_ack_entry, tvb,
1078 offset, len,
1079 "Ack Info Entry #%d", i + 1);
1080 field_tree = proto_item_add_subtree (en, ett_ack_entry);
1082 /* Length of Ack Info Entry */
1083 en = proto_tree_add_item (field_tree, hf_ack_length, tvb, offset, 2, ENC_BIG_ENDIAN);
1084 offset += 2;
1086 if (len < 10) {
1087 proto_item_append_text (en, " (invalid length)");
1088 expert_add_info(pinfo, en, &ei_ack_length);
1091 /* Source Id */
1092 ip = tvb_get_ipv4 (tvb, offset);
1093 SET_ADDRESS (&src, AT_IPv4, sizeof(ip), wmem_memdup (wmem_packet_scope(), &ip, 4));
1094 proto_tree_add_item (field_tree, hf_source_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1095 offset += 4;
1097 /* Message Id */
1098 message_id = tvb_get_ntohl (tvb, offset);
1099 if (use_relative_msgid) {
1100 if (message_id_offset == 0) {
1101 /* First P_Mul package - initialize message_id_offset */
1102 message_id_offset = message_id;
1104 message_id -= message_id_offset;
1105 proto_tree_add_uint_format_value(field_tree, hf_message_id, tvb, offset, 4,
1106 message_id, "%u (relative message id)", message_id);
1107 } else {
1108 proto_tree_add_item (field_tree, hf_message_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1110 offset += 4;
1112 if (i == 0) {
1113 wmem_strbuf_append_printf (message_id_list, "%u", message_id);
1114 } else {
1115 wmem_strbuf_append_printf (message_id_list, ",%u", message_id);
1118 if (len > 10) {
1119 gint num_seq_no = (len - 10) / 2;
1120 guint16 ack_seq_no, prev_ack_seq_no = 0;
1121 for (no_missing = 0; no_missing < num_seq_no; no_missing++) {
1122 /* Missing Data PDU Seq Number */
1123 ack_seq_no = tvb_get_ntohs (tvb, offset);
1124 if ((ack_seq_no != 0) && (no_missing < num_seq_no - 2) && tvb_get_ntohs (tvb, offset + 2) == 0) {
1125 /* We are handling a range */
1126 guint16 end_seq_no = tvb_get_ntohs (tvb, offset + 4);
1128 en = proto_tree_add_bytes_format_value(field_tree, hf_miss_seq_range,
1129 tvb, offset, 6, NULL,
1130 "%d - %d",
1131 ack_seq_no, end_seq_no);
1132 if (ack_seq_no >= end_seq_no) {
1133 proto_item_append_text (en, " (invalid)");
1134 expert_add_info(pinfo, en, &ei_miss_seq_range);
1135 } else {
1136 proto_tree *missing_tree;
1137 guint16 sno;
1139 missing_tree = proto_item_add_subtree (en, ett_range_entry);
1141 for (sno = ack_seq_no; sno <= end_seq_no; sno++) {
1142 en = proto_tree_add_uint_format_value(missing_tree, hf_miss_seq_no,
1143 tvb, offset, 6, sno,
1144 "%d", sno);
1145 PROTO_ITEM_SET_GENERATED (en);
1147 tot_no_missing += (end_seq_no - ack_seq_no + 1);
1150 offset += 6;
1151 no_missing += 2; /* Skip the next two */
1152 prev_ack_seq_no = end_seq_no;
1153 } else {
1154 /* No range, handle one seq no */
1155 en = proto_tree_add_item (field_tree, hf_miss_seq_no, tvb,offset, 2, ENC_BIG_ENDIAN);
1156 offset += 2;
1158 if (ack_seq_no == 0) {
1159 proto_item_append_text (en, " (invalid)");
1160 expert_add_info(pinfo, en, &ei_miss_seq_no);
1161 } else if (ack_seq_no <= prev_ack_seq_no) {
1162 proto_item_append_text (en, " (end of list indicator)");
1163 } else {
1164 tot_no_missing++;
1166 prev_ack_seq_no = ack_seq_no;
1171 if (use_seq_ack_analysis) {
1172 add_ack_analysis (tvb, pinfo, field_tree, offset, pdu_type, &src, &dst,
1173 message_id, no_missing);
1176 proto_item_append_text (ti, ", Count of Ack: %u", count);
1178 if (tvb_length_remaining (tvb, offset) >= 8) {
1179 /* Timestamp Option (in units of 100ms) */
1180 guint64 timestamp;
1182 timestamp = tvb_get_ntoh64 (tvb, offset);
1183 proto_tree_add_uint64_format_value(p_mul_tree, hf_timestamp_option, tvb,
1184 offset, 8, timestamp,
1185 "%" G_GINT64_MODIFIER "d.%d second%s (%" G_GINT64_MODIFIER "u)",
1186 timestamp / 10, (int) timestamp % 10,
1187 (timestamp == 10) ? "" : "s", timestamp);
1188 offset += 8;
1191 if (tot_no_missing) {
1192 proto_item_append_text (ti, ", Missing seq numbers: %u", tot_no_missing);
1193 en = proto_tree_add_uint (p_mul_tree, hf_tot_miss_seq_no, tvb, 0, 0,
1194 tot_no_missing);
1195 PROTO_ITEM_SET_GENERATED (en);
1196 expert_add_info_format(pinfo, en, &ei_tot_miss_seq_no, "Missing seq numbers: %d", tot_no_missing);
1198 break;
1200 case Discard_Message_PDU:
1201 seq_no = G_MAXUINT16; /* To make the seq_no uniq */
1202 break;
1204 case Announce_PDU:
1205 /* Announced Multicast Group */
1206 proto_tree_add_item (p_mul_tree, hf_ann_mc_group, tvb, offset, 4, ENC_BIG_ENDIAN);
1207 offset += 4;
1209 for (i = 0; i < count; i++) {
1210 /* Destination Id */
1211 proto_tree_add_item (p_mul_tree, hf_dest_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1212 offset += 4;
1214 break;
1216 case Request_PDU:
1217 case Reject_PDU:
1218 case Release_PDU:
1219 /* Multicast Group */
1220 proto_tree_add_item (p_mul_tree, hf_mc_group, tvb, offset, 4, ENC_BIG_ENDIAN);
1221 offset += 4;
1222 break;
1224 default:
1225 /* Nothing */
1226 break;
1229 /* Add SEQ/ACK analysis entry */
1230 if (use_seq_ack_analysis && (pdu_type <= Discard_Message_PDU) &&
1231 (pdu_type != Ack_PDU) && (pdu_type != Address_PDU || no_dest != 0))
1233 add_seq_analysis (tvb, pinfo, p_mul_tree, &src, offset, pdu_type,
1234 message_id, seq_no, tot_no_missing);
1237 /* Check if printing Ack-Ack */
1238 if (pdu_type == Address_PDU && no_dest == 0) {
1239 col_append_str (pinfo->cinfo, COL_INFO, get_type (Ack_Ack_PDU));
1240 } else {
1241 col_append_str (pinfo->cinfo, COL_INFO, get_type (pdu_type));
1243 if (pdu_type == Address_PDU || pdu_type == Extra_Address_PDU ||
1244 pdu_type == FEC_Address_PDU || pdu_type == Extra_FEC_Address_PDU) {
1245 col_append_fstr (pinfo->cinfo, COL_INFO, ", No PDUs: %u", no_pdus);
1246 } else if (pdu_type == Data_PDU) {
1247 col_append_fstr (pinfo->cinfo, COL_INFO, ", Seq no: %u", seq_no);
1249 if (pdu_type == Address_PDU || pdu_type == Extra_Address_PDU ||
1250 pdu_type == FEC_Address_PDU || pdu_type == Extra_FEC_Address_PDU) {
1251 if (no_dest > 0) {
1252 col_append_fstr (pinfo->cinfo, COL_INFO, ", Count of Dest: %u", no_dest);
1254 } else if (pdu_type == Ack_PDU) {
1255 if (tot_no_missing) {
1256 col_append_fstr (pinfo->cinfo, COL_INFO, ", Missing seq numbers: %u",
1257 tot_no_missing);
1259 col_append_fstr (pinfo->cinfo, COL_INFO, ", Count of Ack: %u", count);
1261 if (pdu_type != Ack_PDU) {
1262 col_append_fstr (pinfo->cinfo, COL_INFO, ", MSID: %u", message_id);
1263 } else {
1264 if (message_id_list && wmem_strbuf_get_len(message_id_list) > 0) {
1265 col_append_fstr (pinfo->cinfo, COL_INFO, ", MSID: %s", wmem_strbuf_get_str(message_id_list));
1269 if (p_mul_reassemble) {
1270 save_fragmented = pinfo->fragmented;
1272 if (pdu_type == Address_PDU && no_pdus > 0) {
1273 /* Start fragment table */
1274 fragment_start_seq_check (&p_mul_reassembly_table,
1275 pinfo, message_id, NULL, no_pdus - 1);
1276 } else if (pdu_type == Data_PDU) {
1277 fragment_head *frag_msg;
1278 tvbuff_t *new_tvb;
1280 pinfo->fragmented = TRUE;
1282 /* Add fragment to fragment table */
1283 frag_msg = fragment_add_seq_check (&p_mul_reassembly_table,
1284 tvb, offset, pinfo, message_id, NULL,
1285 seq_no - 1, data_len, TRUE);
1286 new_tvb = process_reassembled_data (tvb, offset, pinfo,
1287 "Reassembled P_MUL", frag_msg,
1288 &p_mul_frag_items, NULL, tree);
1290 if (frag_msg)
1291 col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembled)");
1293 if (new_tvb) {
1294 dissect_reassembled_data (new_tvb, pinfo, tree);
1298 pinfo->fragmented = save_fragmented;
1301 /* Update length of P_Mul packet and check length values */
1302 proto_item_set_len (ti, offset);
1303 if (pdu_length != (offset + data_len)) {
1304 proto_item_append_text (len_en, " (incorrect, should be: %d)",
1305 offset + data_len);
1306 expert_add_info(pinfo, len_en, &ei_length);
1307 } else if ((len = tvb_length_remaining (tvb, pdu_length)) > 0) {
1308 proto_item_append_text (len_en, " (more data in packet: %d)", len);
1309 expert_add_info(pinfo, len_en, &ei_more_data);
1313 static void p_mul_init_routine (void)
1315 reassembly_table_init (&p_mul_reassembly_table,
1316 &addresses_reassembly_table_functions);
1317 message_id_offset = 0;
1319 if (p_mul_id_hash_table) {
1320 g_hash_table_destroy (p_mul_id_hash_table);
1323 if (p_mul_package_data_list) {
1324 g_list_foreach (p_mul_package_data_list, (GFunc)p_mul_package_data_destroy, NULL);
1325 g_list_free (p_mul_package_data_list);
1328 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);
1329 p_mul_package_data_list = NULL;
1332 void proto_register_p_mul (void)
1334 static hf_register_info hf[] = {
1335 { &hf_length,
1336 { "Length of PDU", "p_mul.length", FT_UINT16, BASE_DEC,
1337 NULL, 0x0, NULL, HFILL } },
1338 { &hf_priority,
1339 { "Priority", "p_mul.priority", FT_UINT8, BASE_DEC,
1340 NULL, 0x0, NULL, HFILL } },
1341 { &hf_map_first,
1342 { "First", "p_mul.first", FT_BOOLEAN, 8,
1343 TFS (&no_yes), 0x80, NULL, HFILL } },
1344 { &hf_map_last,
1345 { "Last", "p_mul.last", FT_BOOLEAN, 8,
1346 TFS (&no_yes), 0x40, NULL, HFILL } },
1347 { &hf_map_unused,
1348 { "MAP unused", "p_mul.unused", FT_UINT8, BASE_DEC,
1349 NULL, 0xC0, NULL, HFILL } },
1350 { &hf_pdu_type,
1351 { "PDU Type", "p_mul.pdu_type", FT_UINT8, BASE_DEC,
1352 VALS (pdu_vals), 0x3F, NULL, HFILL } },
1353 { &hf_pdu_type_value,
1354 { "PDU Type", "p_mul.pdu_type_value", FT_UINT8, BASE_DEC,
1355 VALS (pdu_vals), 0x3F, NULL, HFILL } },
1356 { &hf_no_pdus,
1357 { "Total Number of PDUs", "p_mul.no_pdus", FT_UINT16, BASE_DEC,
1358 NULL, 0x0, NULL, HFILL } },
1359 { &hf_seq_no,
1360 { "Sequence Number of PDUs", "p_mul.seq_no", FT_UINT16, BASE_DEC,
1361 NULL, 0x0, NULL, HFILL } },
1362 { &hf_unused8,
1363 { "Unused", "p_mul.unused", FT_UINT8, BASE_DEC,
1364 NULL, 0x0, NULL, HFILL } },
1365 { &hf_unused16,
1366 { "Unused", "p_mul.unused", FT_UINT16, BASE_DEC,
1367 NULL, 0x0, NULL, HFILL } },
1368 { &hf_checksum,
1369 { "Checksum", "p_mul.checksum", FT_UINT16, BASE_HEX,
1370 NULL, 0x0, NULL, HFILL } },
1371 { &hf_checksum_good,
1372 { "Good", "p_mul.checksum_good", FT_BOOLEAN, BASE_NONE,
1373 NULL, 0x0, "True: checksum matches packet content; False: doesn't match content or not checked", HFILL } },
1374 { &hf_checksum_bad,
1375 { "Bad", "p_mul.checksum_bad", FT_BOOLEAN, BASE_NONE,
1376 NULL, 0x0, "True: checksum doesn't match packet content; False: matches content or not checked", HFILL } },
1377 { &hf_source_id_ack,
1378 { "Source ID of Ack Sender", "p_mul.source_id_ack", FT_IPv4, BASE_NONE,
1379 NULL, 0x0, NULL, HFILL } },
1380 { &hf_source_id,
1381 { "Source ID", "p_mul.source_id", FT_IPv4, BASE_NONE,
1382 NULL, 0x0, NULL, HFILL } },
1383 { &hf_message_id,
1384 { "Message ID (MSID)", "p_mul.message_id", FT_UINT32, BASE_DEC,
1385 NULL, 0x0, "Message ID", HFILL } },
1386 { &hf_expiry_time,
1387 { "Expiry Time", "p_mul.expiry_time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1388 NULL, 0x0, NULL, HFILL } },
1389 { &hf_mc_group,
1390 { "Multicast Group", "p_mul.mc_group", FT_UINT32, BASE_DEC,
1391 NULL, 0x0, NULL, HFILL } },
1392 { &hf_ann_mc_group,
1393 { "Announced Multicast Group", "p_mul.ann_mc_group", FT_UINT32, BASE_DEC,
1394 NULL, 0x0, NULL, HFILL } },
1395 { &hf_fec_len,
1396 { "FEC Parameter Length", "p_mul.fec.length", FT_UINT8, BASE_DEC,
1397 NULL, 0x0, "Forward Error Correction Parameter Length", HFILL } },
1398 { &hf_fec_id,
1399 { "FEC ID", "p_mul.fec.id", FT_UINT8, BASE_HEX,
1400 NULL, 0x0, "Forward Error Correction ID", HFILL } },
1401 { &hf_fec_parameters,
1402 { "FEC Parameters", "p_mul.fec.parameters", FT_NONE, BASE_NONE,
1403 NULL, 0x0, "Forward Error Correction Parameters", HFILL } },
1404 { &hf_count_of_dest,
1405 { "Count of Destination Entries", "p_mul.dest_count", FT_UINT16,BASE_DEC,
1406 NULL, 0x0, NULL, HFILL } },
1407 { &hf_length_of_res,
1408 { "Length of Reserved Field", "p_mul.reserved_length",FT_UINT16,BASE_DEC,
1409 NULL, 0x0, NULL, HFILL } },
1410 { &hf_ack_count,
1411 { "Count of Ack Info Entries", "p_mul.ack_count", FT_UINT16, BASE_DEC,
1412 NULL, 0x0, NULL, HFILL } },
1413 { &hf_ack_entry,
1414 { "Ack Info Entry", "p_mul.ack_info_entry", FT_NONE, BASE_NONE,
1415 NULL, 0x0, NULL, HFILL } },
1416 { &hf_ack_length,
1417 { "Length of Ack Info Entry", "p_mul.ack_length", FT_UINT16, BASE_DEC,
1418 NULL, 0x0, NULL, HFILL } },
1419 { &hf_miss_seq_no,
1420 { "Missing Data PDU Seq Number", "p_mul.missing_seq_no", FT_UINT16,
1421 BASE_DEC, NULL, 0x0, NULL, HFILL } },
1422 { &hf_miss_seq_range,
1423 { "Missing Data PDU Seq Range", "p_mul.missing_seq_range", FT_BYTES,
1424 BASE_NONE, NULL, 0x0, NULL, HFILL } },
1425 { &hf_tot_miss_seq_no,
1426 { "Total Number of Missing Data PDU Sequence Numbers",
1427 "p_mul.no_missing_seq_no", FT_UINT16, BASE_DEC, NULL, 0x0,
1428 NULL, HFILL } },
1429 { &hf_timestamp_option,
1430 { "Timestamp", "p_mul.timestamp", FT_UINT64, BASE_DEC,
1431 NULL, 0x0, "Timestamp Option (in units of 100ms)", HFILL } },
1432 { &hf_dest_entry,
1433 { "Destination Entry", "p_mul.dest_entry", FT_NONE, BASE_NONE,
1434 NULL, 0x0, NULL, HFILL } },
1435 { &hf_dest_id,
1436 { "Destination ID", "p_mul.dest_id", FT_IPv4, BASE_NONE,
1437 NULL, 0x0, NULL, HFILL } },
1438 { &hf_msg_seq_no,
1439 { "Message Sequence Number", "p_mul.msg_seq_no", FT_UINT16, BASE_DEC,
1440 NULL, 0x0, NULL, HFILL } },
1441 { &hf_sym_key,
1442 { "Symmetric Key", "p_mul.sym_key", FT_NONE, BASE_NONE,
1443 NULL, 0x0, NULL, HFILL } },
1444 { &hf_data_fragment,
1445 { "Fragment of Data", "p_mul.data_fragment", FT_NONE, BASE_NONE,
1446 NULL, 0x0, NULL, HFILL } },
1448 /* Fragment entries */
1449 { &hf_msg_fragments,
1450 { "Message fragments", "p_mul.fragments", FT_NONE, BASE_NONE,
1451 NULL, 0x00, NULL, HFILL } },
1452 { &hf_msg_fragment,
1453 { "Message fragment", "p_mul.fragment", FT_FRAMENUM, BASE_NONE,
1454 NULL, 0x00, NULL, HFILL } },
1455 { &hf_msg_fragment_overlap,
1456 { "Message fragment overlap", "p_mul.fragment.overlap", FT_BOOLEAN,
1457 BASE_NONE, NULL, 0x0, NULL, HFILL } },
1458 { &hf_msg_fragment_overlap_conflicts,
1459 { "Message fragment overlapping with conflicting data",
1460 "p_mul.fragment.overlap.conflicts", FT_BOOLEAN, BASE_NONE, NULL,
1461 0x0, NULL, HFILL } },
1462 { &hf_msg_fragment_multiple_tails,
1463 { "Message has multiple tail fragments",
1464 "p_mul.fragment.multiple_tails", FT_BOOLEAN, BASE_NONE,
1465 NULL, 0x0, NULL, HFILL } },
1466 { &hf_msg_fragment_too_long_fragment,
1467 { "Message fragment too long", "p_mul.fragment.too_long_fragment",
1468 FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL,
1469 HFILL } },
1470 { &hf_msg_fragment_error,
1471 { "Message defragmentation error", "p_mul.fragment.error", FT_FRAMENUM,
1472 BASE_NONE, NULL, 0x00, NULL, HFILL } },
1473 { &hf_msg_fragment_count,
1474 { "Message fragment count", "p_mul.fragment.count", FT_UINT32, BASE_DEC,
1475 NULL, 0x00, NULL, HFILL } },
1476 { &hf_msg_reassembled_in,
1477 { "Reassembled in", "p_mul.reassembled.in", FT_FRAMENUM, BASE_NONE,
1478 NULL, 0x00, NULL, HFILL } },
1479 { &hf_msg_reassembled_length,
1480 { "Reassembled P_MUL length", "p_mul.reassembled.length", FT_UINT32, BASE_DEC,
1481 NULL, 0x00, NULL, HFILL } },
1484 ** Ack matching / Resend
1486 { &hf_analysis_ack_time,
1487 { "Ack Time", "p_mul.analysis.ack_time", FT_RELATIVE_TIME, BASE_NONE,
1488 NULL, 0x0, "The time between the Last PDU and the Ack", HFILL } },
1489 { &hf_analysis_trans_time,
1490 { "Transfer Time", "p_mul.analysis.trans_time", FT_RELATIVE_TIME, BASE_NONE,
1491 NULL, 0x0, "The time between the first Address PDU and the Ack", HFILL } },
1492 { &hf_analysis_retrans_time,
1493 { "Retransmission Time", "p_mul.analysis.retrans_time", FT_RELATIVE_TIME, BASE_NONE,
1494 NULL, 0x0, "The time between the last PDU and this PDU", HFILL } },
1495 { &hf_analysis_total_retrans_time,
1496 { "Total Retransmission Time", "p_mul.analysis.total_retrans_time", FT_RELATIVE_TIME, BASE_NONE,
1497 NULL, 0x0, "The time between the first PDU and this PDU", HFILL } },
1498 { &hf_analysis_addr_pdu_time,
1499 { "Time since Address PDU", "p_mul.analysis.elapsed_time", FT_RELATIVE_TIME, BASE_NONE,
1500 NULL, 0x0, "The time between the Address PDU and this PDU", HFILL } },
1501 { &hf_analysis_prev_pdu_time,
1502 { "PDU Delay", "p_mul.analysis.pdu_delay", FT_RELATIVE_TIME, BASE_NONE,
1503 NULL, 0x0, "The time between the last PDU and this PDU", HFILL } },
1504 { &hf_analysis_last_pdu_num,
1505 { "Last Data PDU in", "p_mul.analysis.last_pdu_in", FT_FRAMENUM, BASE_NONE,
1506 NULL, 0x0, "The last Data PDU found in this frame", HFILL } },
1507 { &hf_analysis_addr_pdu_num,
1508 { "Address PDU in", "p_mul.analysis.addr_pdu_in", FT_FRAMENUM, BASE_NONE,
1509 NULL, 0x0, "The Address PDU is found in this frame", HFILL } },
1510 { &hf_analysis_prev_pdu_num,
1511 { "Previous PDU in", "p_mul.analysis.prev_pdu_in", FT_FRAMENUM, BASE_NONE,
1512 NULL, 0x0, "The previous PDU is found in this frame", HFILL } },
1513 { &hf_analysis_ack_num,
1514 { "Ack PDU in", "p_mul.analysis.ack_in", FT_FRAMENUM, BASE_NONE,
1515 NULL, 0x0, "This packet has an Ack in this frame", HFILL } },
1516 { &hf_analysis_ack_missing,
1517 { "Ack PDU missing", "p_mul.analysis.ack_missing", FT_NONE, BASE_NONE,
1518 NULL, 0x0, "The acknowledgement for this packet is missing", HFILL } },
1519 { &hf_analysis_retrans_no,
1520 { "Retransmission #", "p_mul.analysis.retrans_no", FT_UINT32, BASE_DEC,
1521 NULL, 0x0, "Retransmission count", HFILL } },
1522 { &hf_analysis_ack_dup_no,
1523 { "Duplicate ACK #", "p_mul.analysis.dup_ack_no", FT_UINT32, BASE_DEC,
1524 NULL, 0x0, "Duplicate Ack count", HFILL } },
1525 { &hf_analysis_msg_resend_from,
1526 { "Retransmission of Message in", "p_mul.analysis.msg_first_in",
1527 FT_FRAMENUM, BASE_NONE,
1528 NULL, 0x0, "This Message was first sent in this frame", HFILL } },
1529 { &hf_analysis_ack_resend_from,
1530 { "Retransmission of Ack in", "p_mul.analysis.ack_first_in",
1531 FT_FRAMENUM, BASE_NONE,
1532 NULL, 0x0, "This Ack was first sent in this frame", HFILL } },
1533 { &hf_analysis_total_time,
1534 { "Total Time", "p_mul.analysis.total_time", FT_RELATIVE_TIME, BASE_NONE,
1535 NULL, 0x0, "The time between the first and the last Address PDU", HFILL } },
1538 static gint *ett[] = {
1539 &ett_p_mul,
1540 &ett_pdu_type,
1541 &ett_dest_entry,
1542 &ett_ack_entry,
1543 &ett_range_entry,
1544 &ett_checksum,
1545 &ett_seq_analysis,
1546 &ett_ack_analysis,
1547 &ett_seq_ack_analysis,
1548 &ett_msg_fragment,
1549 &ett_msg_fragments
1551 static ei_register_info ei[] = {
1552 { &ei_address_pdu_missing, { "p_mul.analysis.addr_pdu_missing", PI_SEQUENCE, PI_NOTE, "Address PDU missing", EXPFILL }},
1553 { &ei_analysis_ack_missing, { "p_mul.analysis.ack_missing.expert", PI_SEQUENCE, PI_NOTE, "Ack PDU missing", EXPFILL }},
1554 { &ei_analysis_ack_dup_no, { "p_mul.analysis.dup_ack_no.expert", PI_SEQUENCE, PI_NOTE, "Dup ACK #", EXPFILL }},
1555 { &ei_analysis_prev_pdu_missing, { "p_mul.analysis.prev_pdu_missing", PI_SEQUENCE, PI_NOTE, "Previous PDU missing", EXPFILL }},
1556 { &ei_analysis_retrans_no, { "p_mul.analysis.retrans_no.expert", PI_SEQUENCE, PI_NOTE, "Retransmission #", EXPFILL }},
1557 { &ei_message_discarded, { "p_mul.message_discarded", PI_RESPONSE_CODE, PI_NOTE, "Message discarded", EXPFILL }},
1558 { &ei_checksum_bad, { "p_mul.checksum_bad.expert", PI_CHECKSUM, PI_WARN, "Bad checksum", EXPFILL }},
1559 { &ei_ack_length, { "p_mul.ack_length.invalid", PI_MALFORMED, PI_WARN, "Invalid ack info length", EXPFILL }},
1560 { &ei_miss_seq_range, { "p_mul.missing_seq_range.invalid", PI_UNDECODED, PI_WARN, "Invalid missing sequence range", EXPFILL }},
1561 { &ei_miss_seq_no, { "p_mul.missing_seq_no.invalid", PI_UNDECODED, PI_WARN, "Invalid missing seq number", EXPFILL }},
1562 { &ei_tot_miss_seq_no, { "p_mul.no_missing_seq_no.expert", PI_RESPONSE_CODE, PI_NOTE, "Missing seq numbers", EXPFILL }},
1563 { &ei_length, { "p_mul.length.invalid", PI_MALFORMED, PI_WARN, "Incorrect length field", EXPFILL }},
1564 { &ei_more_data, { "p_mul.more_data", PI_MALFORMED, PI_WARN, "More data in packet", EXPFILL }},
1567 module_t *p_mul_module;
1568 expert_module_t* expert_p_mul;
1570 proto_p_mul = proto_register_protocol (PNAME, PSNAME, PFNAME);
1572 p_mul_handle = register_dissector(PFNAME, dissect_p_mul, proto_p_mul);
1574 proto_register_field_array (proto_p_mul, hf, array_length (hf));
1575 proto_register_subtree_array (ett, array_length (ett));
1576 expert_p_mul = expert_register_protocol(proto_p_mul);
1577 expert_register_field_array(expert_p_mul, ei, array_length(ei));
1578 register_init_routine (&p_mul_init_routine);
1580 /* Set default UDP ports */
1581 range_convert_str (&global_p_mul_port_range, DEFAULT_P_MUL_PORT_RANGE,
1582 MAX_UDP_PORT);
1584 /* Register our configuration options */
1585 p_mul_module = prefs_register_protocol (proto_p_mul,
1586 proto_reg_handoff_p_mul);
1588 prefs_register_obsolete_preference (p_mul_module, "tport");
1589 prefs_register_obsolete_preference (p_mul_module, "rport");
1590 prefs_register_obsolete_preference (p_mul_module, "dport");
1591 prefs_register_obsolete_preference (p_mul_module, "aport");
1593 prefs_register_range_preference (p_mul_module, "udp_ports",
1594 "P_Mul port numbers",
1595 "Port numbers used for P_Mul traffic",
1596 &global_p_mul_port_range, MAX_UDP_PORT);
1597 prefs_register_bool_preference (p_mul_module, "reassemble",
1598 "Reassemble fragmented P_Mul packets",
1599 "Reassemble fragmented P_Mul packets",
1600 &p_mul_reassemble);
1601 prefs_register_bool_preference (p_mul_module, "relative_msgid",
1602 "Use relative Message ID",
1603 "Make the P_Mul dissector use relative"
1604 " message id number instead of absolute"
1605 " ones", &use_relative_msgid);
1606 prefs_register_bool_preference (p_mul_module, "seq_ack_analysis",
1607 "SEQ/ACK Analysis",
1608 "Calculate sequence/acknowledgement analysis",
1609 &use_seq_ack_analysis);
1610 prefs_register_enum_preference (p_mul_module, "decode",
1611 "Decode Data PDU as",
1612 "Type of content in Data_PDU",
1613 &decode_option, decode_options, FALSE);
1616 void proto_reg_handoff_p_mul (void)
1618 static gboolean p_mul_prefs_initialized = FALSE;
1619 static range_t *p_mul_port_range;
1621 if (!p_mul_prefs_initialized) {
1622 p_mul_prefs_initialized = TRUE;
1623 data_handle = find_dissector ("data");
1624 } else {
1625 dissector_delete_uint_range ("udp.port", p_mul_port_range, p_mul_handle);
1626 g_free (p_mul_port_range);
1629 /* Save port number for later deletion */
1630 p_mul_port_range = range_copy (global_p_mul_port_range);
1632 dissector_add_uint_range ("udp.port", p_mul_port_range, p_mul_handle);
1636 * Editor modelines
1638 * Local Variables:
1639 * c-basic-offset: 2
1640 * tab-width: 8
1641 * indent-tabs-mode: nil
1642 * End:
1644 * ex: set shiftwidth=2 tabstop=8 expandtab:
1645 * :indentSize=2:tabSize=8:noTabs=true: