Coverage Report

Created: 2026-11-12 07:01

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