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