Coverage Report

Created: 2025-08-04 07:15

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