/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 | | */ |