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