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