/src/wireshark/epan/dissectors/packet-mtp2.c
Line | Count | Source |
1 | | /* packet-mtp2.c |
2 | | * Routines for MTP2 dissection |
3 | | * It is hopefully (needs testing) compliant to |
4 | | * ITU-T Q.703 and Q.703 Annex A. |
5 | | * |
6 | | * Copyright 2001, 2004 Michael Tuexen <tuexen [AT] fh-muenster.de> |
7 | | * |
8 | | * Wireshark - Network traffic analyzer |
9 | | * By Gerald Combs <gerald@wireshark.org> |
10 | | * Copyright 1998 Gerald Combs |
11 | | * |
12 | | * Copied from packet-m2pa.c |
13 | | * |
14 | | * SPDX-License-Identifier: GPL-2.0-or-later |
15 | | */ |
16 | | |
17 | | #include "config.h" |
18 | 0 | #define WS_LOG_DOMAIN "packet-mtp2" |
19 | | #include <wireshark.h> |
20 | | |
21 | | #include <epan/packet.h> |
22 | | #include <epan/prefs.h> |
23 | | #include <epan/crc16-tvb.h> |
24 | | #include <epan/expert.h> |
25 | | #include <wiretap/wtap.h> |
26 | | #include <epan/conversation.h> |
27 | | #include <epan/proto_data.h> |
28 | | #include <epan/reassemble.h> |
29 | | |
30 | | void proto_register_mtp2(void); |
31 | | void proto_reg_handoff_mtp2(void); |
32 | | |
33 | | static dissector_handle_t mtp2_handle; |
34 | | static dissector_handle_t mtp2_with_phdr_handle; |
35 | | static dissector_handle_t mtp2_bitstream_handle; |
36 | | static dissector_handle_t mtp3_handle; |
37 | | |
38 | | /* possible packet states */ |
39 | | enum packet_direction_state_mtp2 {FORWARD, BACKWARD}; |
40 | | |
41 | | /* structure for telling the bitstream dissector if it shall use a mtp2_flag_search value from the prev. packet */ |
42 | | typedef struct mtp2_flag_search { |
43 | | bool set; /* shows if the mtp2_flag_search value is valid, needed to be set in the dissect function */ |
44 | | uint8_t mtp2_flag_search; /* mtp2_flag_search value itself */ |
45 | | } mtp2_mtp2_flag_search_t; |
46 | | |
47 | | /* Possible states of the state machine for decoding the MTP2 bitstream */ |
48 | | enum mtp2_bitstream_states {OUT_OF_SYNC, FLAGS, DATA}; |
49 | | |
50 | | /* data type for chained list of found MTP2 packets in RTP stream */ |
51 | | typedef struct mtp2_recognized_packet { |
52 | | tvbuff_t *data; /* data of the actual packet */ |
53 | | uint8_t unalignment_offset; /* !=0 signals if this packet was not a multiple of 8 bits in the stream */ |
54 | | } mtp2_recognized_packet_t; |
55 | | |
56 | | /* structure used in mtp2_dissect_tvb_res |
57 | | this contains the tvb's before the first and after last header */ |
58 | | typedef struct mtp2_remain_data { |
59 | | tvbuff_t *before_first_flag; /* data found before the first flag */ |
60 | | tvbuff_t *after_last_flag; /* data found after the last flag */ |
61 | | uint8_t before_fh_unalignment_offset; /* !=0 signals if the before_fh data was not a multiple of 8 bits in the stream */ |
62 | | bool before_fh_frame_reset; /* signals if there was a frame reset in the data before the 1st flag */ |
63 | | } mtp2_remain_data_t; |
64 | | |
65 | | |
66 | | /* structure to store the result of dissect_mtp2_tvb function */ |
67 | | typedef struct mtp2_dissect_tvb_res { |
68 | | mtp2_remain_data_t mtp2_remain_data; /* stores the tvbuffs found before 1st and after last flags in the packet */ |
69 | | mtp2_mtp2_flag_search_t mtp2_flag_search; /* this contains the mtp2_flag_search's value at the end of the packet dissection */ |
70 | | wmem_list_t *found_packets; /* contains the packets found in tvbuff */ |
71 | | uint8_t data_buff; /* to store the data_buff value */ |
72 | | uint8_t data_buff_offset; /* to store the data_buff_offset value */ |
73 | | uint8_t last_flag_beginning_offset_for_align_check; /* the offset of the last flag's beginning have to be stored */ |
74 | | bool flag_found; /* boolean value to sign if there was a flag in the RTP packet or not */ |
75 | | enum mtp2_bitstream_states state; /* to store the value of the state of the dissection after finish */ |
76 | | } mtp2_dissect_tvb_res_t; |
77 | | |
78 | | /* mtp2 per-packet data */ |
79 | | typedef struct mtp2_ppd { |
80 | | mtp2_mtp2_flag_search_t mtp2_flag_search; /* flag search needed to pass to dissect_mtp2_tvb - it was derived from the prev. packet in the same direction */ |
81 | | uint8_t data_buff; /* data buff needed to pass to dissect_mtp2_tvb - it was derived from the prev. packet in the same direction */ |
82 | | uint8_t data_buff_offset; /* data buff offset needed to pass to dissect_mtp2_tvb - it was derived from the prev. packet in the same direction */ |
83 | | uint8_t last_flag_beginning_offset_for_align_check; /* variable for align check, stores the last flag's beginning's offset */ |
84 | | uint32_t reass_seq_num_for_reass_check_before_fh; /* this is the id (reass_seq_num) which should be used for looking up reassembled data found before the first flag */ |
85 | | uint32_t reass_seq_num_for_reass_check_after_lh; /* this is the id (reass_seq_num) which should be used for looking up reassembled data found after the last flag */ |
86 | | enum mtp2_bitstream_states state; /* state needed to pass to dissect_mtp2_tvb - it was derived from the prev. packet in the same direction */ |
87 | | } mtp2_ppd_t; |
88 | | |
89 | | /* conversation data about the previous packet in the conversation (in one direction) */ |
90 | | typedef struct mtp2_convo_data_prev_packet { |
91 | | mtp2_mtp2_flag_search_t mtp2_flag_search; /* storing the prev. packet's flag search */ |
92 | | uint8_t data_buff; /* storing the prev. packet's data buffer */ |
93 | | uint8_t data_buff_offset; /* storing the prev. packet's data buffer offset */ |
94 | | uint8_t last_flag_beginning_offset_for_align_check; /* storing the prev. packet's last flag's offset */ |
95 | | uint32_t reass_seq_num; /* storing the prev. packet's reassemble seq. num */ |
96 | | enum mtp2_bitstream_states state; /* storing the prev. packet's state in the forward direction */ |
97 | | } mtp2_convo_data_prev_packet_t; |
98 | | |
99 | | /* conversation data for MTP2 dissection from RTP payload */ |
100 | | typedef struct mtp2_convo_data { |
101 | | address addr_a; /* storing the first packet's originating address */ |
102 | | address addr_b; /* storing the first packet's terminating address */ |
103 | | uint32_t port_a; /* storing the first packet's originating port */ |
104 | | uint32_t port_b; /* storing the first packet's terminating port */ |
105 | | mtp2_convo_data_prev_packet_t *forward; /* storing needed info about the prev. packet's in forward direction */ |
106 | | mtp2_convo_data_prev_packet_t *backward; /* storing needed info about the prev. packet's in backward direction */ |
107 | | } mtp2_convo_data_t; |
108 | | |
109 | | /* Initialize the protocol and registered fields */ |
110 | | static int proto_mtp2; |
111 | | static int hf_mtp2_bsn; |
112 | | static int hf_mtp2_ext_bsn; |
113 | | static int hf_mtp2_ext_res; |
114 | | static int hf_mtp2_bib; |
115 | | static int hf_mtp2_ext_bib; |
116 | | static int hf_mtp2_fsn; |
117 | | static int hf_mtp2_ext_fsn; |
118 | | static int hf_mtp2_fib; |
119 | | static int hf_mtp2_ext_fib; |
120 | | static int hf_mtp2_li; |
121 | | static int hf_mtp2_ext_li; |
122 | | static int hf_mtp2_spare; |
123 | | static int hf_mtp2_ext_spare; |
124 | | static int hf_mtp2_sf; |
125 | | static int hf_mtp2_sf_extra; |
126 | | static int hf_mtp2_fcs_16; |
127 | | static int hf_mtp2_fcs_16_status; |
128 | | static int hf_mtp2_unexpect_end; |
129 | | static int hf_mtp2_frame_reset; |
130 | | |
131 | | /* reassemble variables */ |
132 | | static int hf_mtp2_fragments; |
133 | | static int hf_mtp2_fragment; |
134 | | static int hf_mtp2_fragment_overlap; |
135 | | static int hf_mtp2_fragment_overlap_conflicts; |
136 | | static int hf_mtp2_fragment_multiple_tails; |
137 | | static int hf_mtp2_fragment_too_long_fragment; |
138 | | static int hf_mtp2_fragment_error; |
139 | | static int hf_mtp2_fragment_count; |
140 | | static int hf_mtp2_reassembled_in; |
141 | | static int hf_mtp2_reassembled_length; |
142 | | static int ett_mtp2_fragment; |
143 | | static int ett_mtp2_fragments; |
144 | | |
145 | | /* local static const needed for reassembly */ |
146 | | static const fragment_items mtp2_frag_items = { |
147 | | &ett_mtp2_fragment, |
148 | | &ett_mtp2_fragments, |
149 | | &hf_mtp2_fragments, |
150 | | &hf_mtp2_fragment, |
151 | | &hf_mtp2_fragment_overlap, |
152 | | &hf_mtp2_fragment_overlap_conflicts, |
153 | | &hf_mtp2_fragment_multiple_tails, |
154 | | &hf_mtp2_fragment_too_long_fragment, |
155 | | &hf_mtp2_fragment_error, |
156 | | &hf_mtp2_fragment_count, |
157 | | &hf_mtp2_reassembled_in, |
158 | | &hf_mtp2_reassembled_length, |
159 | | NULL, |
160 | | "MTP2 Message fragments" |
161 | | }; |
162 | | |
163 | | /* needed for packet reassembly */ |
164 | | static reassembly_table mtp2_reassembly_table; |
165 | | |
166 | | /* variables needed for property registration to wireshark menu */ |
167 | | static bool reverse_bit_order_mtp2; |
168 | | |
169 | | static expert_field ei_mtp2_checksum_error; |
170 | | static expert_field ei_mtp2_li_bad; |
171 | | |
172 | | /* Initialize the subtree pointers */ |
173 | | static int ett_mtp2; |
174 | | |
175 | | static bool use_extended_sequence_numbers_default; |
176 | | static bool capture_contains_fcs_crc_default; |
177 | | |
178 | | /* sequence number of the actual packet to be reassembled |
179 | | * this is needed because the reassemble handler uses a key based on the |
180 | | * source and destination IP addresses |
181 | | * therefore if there are multiple streams between 2 IP end-points |
182 | | * the reassemble sequence numbers can conflict if they are based on conversations */ |
183 | | static uint32_t mtp2_absolute_reass_seq_num; |
184 | | |
185 | 0 | #define BSN_BIB_LENGTH 1 |
186 | 0 | #define FSN_FIB_LENGTH 1 |
187 | 0 | #define LI_LENGTH 1 |
188 | 0 | #define HEADER_LENGTH (BSN_BIB_LENGTH + FSN_FIB_LENGTH + LI_LENGTH) |
189 | | |
190 | 0 | #define EXTENDED_BSN_BIB_LENGTH 2 |
191 | 0 | #define EXTENDED_FSN_FIB_LENGTH 2 |
192 | 0 | #define EXTENDED_LI_LENGTH 2 |
193 | 0 | #define EXTENDED_HEADER_LENGTH (EXTENDED_BSN_BIB_LENGTH + EXTENDED_FSN_FIB_LENGTH + EXTENDED_LI_LENGTH) |
194 | | |
195 | 0 | #define BSN_BIB_OFFSET 0 |
196 | 0 | #define FSN_FIB_OFFSET (BSN_BIB_OFFSET + BSN_BIB_LENGTH) |
197 | 0 | #define LI_OFFSET (FSN_FIB_OFFSET + FSN_FIB_LENGTH) |
198 | 0 | #define SIO_OFFSET (LI_OFFSET + LI_LENGTH) |
199 | | |
200 | 0 | #define EXTENDED_BSN_BIB_OFFSET 0 |
201 | 0 | #define EXTENDED_FSN_FIB_OFFSET (EXTENDED_BSN_BIB_OFFSET + EXTENDED_BSN_BIB_LENGTH) |
202 | 0 | #define EXTENDED_LI_OFFSET (EXTENDED_FSN_FIB_OFFSET + EXTENDED_FSN_FIB_LENGTH) |
203 | 0 | #define EXTENDED_SIO_OFFSET (EXTENDED_LI_OFFSET + EXTENDED_LI_LENGTH) |
204 | | |
205 | 16 | #define BSN_MASK 0x7f |
206 | 16 | #define BIB_MASK 0x80 |
207 | 16 | #define FSN_MASK 0x7f |
208 | 16 | #define FIB_MASK 0x80 |
209 | 16 | #define LI_MASK 0x3f |
210 | 16 | #define SPARE_MASK 0xc0 |
211 | | |
212 | 16 | #define EXTENDED_BSN_MASK 0x0fff |
213 | 16 | #define EXTENDED_RES_MASK 0x7000 |
214 | 16 | #define EXTENDED_BIB_MASK 0x8000 |
215 | 16 | #define EXTENDED_FSN_MASK 0x0fff |
216 | 16 | #define EXTENDED_FIB_MASK 0x8000 |
217 | 16 | #define EXTENDED_LI_MASK 0x01ff |
218 | 16 | #define EXTENDED_SPARE_MASK 0xfe00 |
219 | | |
220 | | /* remove comment to enable debugging of bitstream dissector |
221 | | * if enabled this produces printout to stderr like this for every packet: |
222 | | |
223 | | start_dissect_bitstream_packet: 2120 |
224 | | 11010010 SKIPPED ZEROS: 3. |
225 | | 10000000 |
226 | | 01100001 |
227 | | 01101111 |
228 | | 10011111 SKIPPED ZEROS: 2. |
229 | | 10011001 FLAG FOUND |
230 | | 11110100 SKIPPED ZEROS: 5. |
231 | | 10100000 |
232 | | 00011000 |
233 | | * under the development it can be very helpful to see RTP packet content like this |
234 | | * to identify and solve problems regarding bitstream parsing*/ |
235 | | /*#define MTP2_BITSTREAM_DEBUG 1*/ |
236 | | |
237 | | static void |
238 | | dissect_mtp2_header(tvbuff_t *su_tvb, packet_info *pinfo, proto_item *mtp2_tree, bool use_extended_sequence_numbers, bool validate_crc, uint32_t *li) |
239 | 0 | { |
240 | 0 | unsigned reported_len; |
241 | 0 | proto_item *li_item; |
242 | |
|
243 | 0 | if (use_extended_sequence_numbers) { |
244 | 0 | reported_len = tvb_reported_length_remaining(su_tvb, EXTENDED_HEADER_LENGTH); |
245 | 0 | if (validate_crc) { |
246 | 0 | reported_len = reported_len < 2 ? 0 : (reported_len - 2); |
247 | 0 | } |
248 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_ext_bsn, su_tvb, EXTENDED_BSN_BIB_OFFSET, EXTENDED_BSN_BIB_LENGTH, ENC_LITTLE_ENDIAN); |
249 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_ext_res, su_tvb, EXTENDED_BSN_BIB_OFFSET, EXTENDED_BSN_BIB_LENGTH, ENC_LITTLE_ENDIAN); |
250 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_ext_bib, su_tvb, EXTENDED_BSN_BIB_OFFSET, EXTENDED_BSN_BIB_LENGTH, ENC_LITTLE_ENDIAN); |
251 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_ext_fsn, su_tvb, EXTENDED_FSN_FIB_OFFSET, EXTENDED_FSN_FIB_LENGTH, ENC_LITTLE_ENDIAN); |
252 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_ext_res, su_tvb, EXTENDED_FSN_FIB_OFFSET, EXTENDED_FSN_FIB_LENGTH, ENC_LITTLE_ENDIAN); |
253 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_ext_fib, su_tvb, EXTENDED_FSN_FIB_OFFSET, EXTENDED_FSN_FIB_LENGTH, ENC_LITTLE_ENDIAN); |
254 | 0 | li_item = proto_tree_add_item_ret_uint(mtp2_tree, hf_mtp2_ext_li, su_tvb, EXTENDED_LI_OFFSET, EXTENDED_LI_LENGTH, ENC_LITTLE_ENDIAN, li); |
255 | 0 | if (*li != reported_len) { |
256 | | /* ITU-T Q.703 A.2.3.3 When the extended sequence numbers are used, |
257 | | * the field is large enough to contain all legal values. 0-273. |
258 | | * Thus the check in the other case doesn't apply. */ |
259 | 0 | proto_item_append_text(li_item, " [expected payload length %u]", reported_len); |
260 | 0 | expert_add_info_format(pinfo, li_item, &ei_mtp2_li_bad, "Bad length value %u != payload length ", *li); |
261 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " [BAD MTP2 LI %u != PAYLOAD LENGTH]", *li); |
262 | 0 | } |
263 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_ext_spare, su_tvb, EXTENDED_LI_OFFSET, EXTENDED_LI_LENGTH, ENC_LITTLE_ENDIAN); |
264 | 0 | } else { |
265 | 0 | reported_len = tvb_reported_length_remaining(su_tvb, HEADER_LENGTH); |
266 | 0 | if (validate_crc) { |
267 | 0 | reported_len = reported_len < 2 ? 0 : (reported_len - 2); |
268 | 0 | } |
269 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_bsn, su_tvb, BSN_BIB_OFFSET, BSN_BIB_LENGTH, ENC_LITTLE_ENDIAN); |
270 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_bib, su_tvb, BSN_BIB_OFFSET, BSN_BIB_LENGTH, ENC_LITTLE_ENDIAN); |
271 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_fsn, su_tvb, FSN_FIB_OFFSET, FSN_FIB_LENGTH, ENC_LITTLE_ENDIAN); |
272 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_fib, su_tvb, FSN_FIB_OFFSET, FSN_FIB_LENGTH, ENC_LITTLE_ENDIAN); |
273 | 0 | li_item = proto_tree_add_item_ret_uint(mtp2_tree, hf_mtp2_li, su_tvb, LI_OFFSET, LI_LENGTH, ENC_LITTLE_ENDIAN, li); |
274 | | /* ITU-T Q.703 2.3.3: In the case that the payload is more than the |
275 | | * li field allows, should be set to the max, i.e. the mask 63 */ |
276 | 0 | if (reported_len > LI_MASK) { |
277 | 0 | if (*li != LI_MASK) { |
278 | 0 | proto_item_append_text(li_item, " [payload length %u, expected max value %u]", reported_len, LI_MASK); |
279 | 0 | expert_add_info_format(pinfo, li_item, &ei_mtp2_li_bad, "Bad length value %u != max value ", *li); |
280 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " [BAD MTP2 LI %u != MAX VALUE]", *li); |
281 | 0 | } |
282 | 0 | } else if (*li != reported_len ) { |
283 | 0 | proto_item_append_text(li_item, " [expected payload length %u]", reported_len); |
284 | 0 | expert_add_info_format(pinfo, li_item, &ei_mtp2_li_bad, "Bad length value %u != payload length ", *li); |
285 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " [BAD MTP2 LI %u != PAYLOAD LENGTH]", *li); |
286 | 0 | } |
287 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_spare, su_tvb, LI_OFFSET, LI_LENGTH, ENC_LITTLE_ENDIAN); |
288 | 0 | } |
289 | 0 | } |
290 | | /* |
291 | | ******************************************************************************* |
292 | | * DETAILS : Calculate a new FCS-16 given the current FCS-16 and the new data. |
293 | | ******************************************************************************* |
294 | | */ |
295 | | static uint16_t |
296 | | mtp2_fcs16(tvbuff_t * tvbuff) |
297 | 0 | { |
298 | 0 | unsigned len = tvb_reported_length(tvbuff)-2; |
299 | | |
300 | | /* Check for Invalid Length */ |
301 | 0 | if (len == 0) |
302 | 0 | return (0x0000); |
303 | 0 | return crc16_ccitt_tvb(tvbuff, len); |
304 | 0 | } |
305 | | |
306 | | /* |
307 | | * This function for CRC16 only is based on the decode_fcs of packet_ppp.c |
308 | | */ |
309 | | static tvbuff_t * |
310 | | mtp2_decode_crc16(tvbuff_t *tvb, proto_tree *fh_tree, packet_info *pinfo) |
311 | 0 | { |
312 | 0 | tvbuff_t *next_tvb; |
313 | 0 | int len, reported_len; |
314 | 0 | int proto_offset=0; |
315 | | |
316 | | /* |
317 | | * Do we have the entire packet, and does it include a 2-byte FCS? |
318 | | */ |
319 | 0 | len = tvb_captured_length_remaining(tvb, proto_offset); |
320 | 0 | reported_len = tvb_reported_length_remaining(tvb, proto_offset); |
321 | 0 | if (reported_len < 2 || len < 0) { |
322 | | /* |
323 | | * The packet is claimed not to even have enough data for a 2-byte FCS, |
324 | | * or we're already past the end of the captured data. |
325 | | * Don't slice anything off. |
326 | | */ |
327 | 0 | next_tvb = tvb_new_subset_remaining(tvb, proto_offset); |
328 | 0 | } else if (len < reported_len) { |
329 | | /* |
330 | | * The packet is claimed to have enough data for a 2-byte FCS, but |
331 | | * we didn't capture all of the packet. |
332 | | * Slice off the 2-byte FCS from the reported length, and trim the |
333 | | * captured length so it's no more than the reported length; that |
334 | | * will slice off what of the FCS, if any, is in the captured |
335 | | * length. |
336 | | */ |
337 | 0 | reported_len -= 2; |
338 | 0 | next_tvb = tvb_new_subset_length(tvb, proto_offset, reported_len); |
339 | 0 | } else { |
340 | | /* |
341 | | * We have the entire packet, and it includes a 2-byte FCS. |
342 | | * Slice it off. |
343 | | */ |
344 | 0 | len -= 2; |
345 | 0 | reported_len -= 2; |
346 | 0 | next_tvb = tvb_new_subset_length(tvb, proto_offset, reported_len); |
347 | | |
348 | | /* |
349 | | * Compute the FCS and put it into the tree. |
350 | | */ |
351 | 0 | proto_tree_add_checksum(fh_tree, tvb, proto_offset + len, hf_mtp2_fcs_16, hf_mtp2_fcs_16_status, &ei_mtp2_checksum_error, pinfo, mtp2_fcs16(tvb), |
352 | 0 | ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY); |
353 | 0 | } |
354 | 0 | return next_tvb; |
355 | 0 | } |
356 | | |
357 | | |
358 | | static void |
359 | | dissect_mtp2_fisu(packet_info *pinfo) |
360 | 0 | { |
361 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "FISU "); |
362 | 0 | } |
363 | | |
364 | | static const value_string status_field_vals[] = { |
365 | | { 0x0, "Status Indication O" }, |
366 | | { 0x1, "Status Indication N" }, |
367 | | { 0x2, "Status Indication E" }, |
368 | | { 0x3, "Status Indication OS" }, |
369 | | { 0x4, "Status Indication PO" }, |
370 | | { 0x5, "Status Indication B" }, |
371 | | { 0, NULL} |
372 | | }; |
373 | | |
374 | | /* Same as above but in acronym form (for the Info column) */ |
375 | | static const value_string status_field_acro_vals[] = { |
376 | | { 0x0, "SIO" }, |
377 | | { 0x1, "SIN" }, |
378 | | { 0x2, "SIE" }, |
379 | | { 0x3, "SIOS" }, |
380 | | { 0x4, "SIPO" }, |
381 | | { 0x5, "SIB" }, |
382 | | { 0, NULL} |
383 | | }; |
384 | | |
385 | 0 | #define SF_OFFSET (LI_OFFSET + LI_LENGTH) |
386 | 0 | #define EXTENDED_SF_OFFSET (EXTENDED_LI_OFFSET + EXTENDED_LI_LENGTH) |
387 | | |
388 | 0 | #define SF_LENGTH 1 |
389 | 0 | #define SF_EXTRA_OFFSET (SF_OFFSET + SF_LENGTH) |
390 | 0 | #define EXTENDED_SF_EXTRA_OFFSET (EXTENDED_SF_OFFSET + SF_LENGTH) |
391 | 0 | #define SF_EXTRA_LENGTH 1 |
392 | | |
393 | | static void |
394 | | dissect_mtp2_lssu(tvbuff_t *su_tvb, packet_info *pinfo, proto_item *mtp2_tree, |
395 | | bool use_extended_sequence_numbers, uint32_t li) |
396 | 0 | { |
397 | 0 | uint8_t sf = 0xFF; |
398 | 0 | uint8_t sf_offset, sf_extra_offset; |
399 | |
|
400 | 0 | if (use_extended_sequence_numbers) { |
401 | 0 | sf_offset = EXTENDED_SF_OFFSET; |
402 | 0 | sf_extra_offset = EXTENDED_SF_EXTRA_OFFSET; |
403 | 0 | } else { |
404 | 0 | sf_offset = SF_OFFSET; |
405 | 0 | sf_extra_offset = SF_EXTRA_OFFSET; |
406 | 0 | } |
407 | |
|
408 | 0 | proto_tree_add_item_ret_uint8(mtp2_tree, hf_mtp2_sf, su_tvb, sf_offset, SF_LENGTH, ENC_LITTLE_ENDIAN, &sf); |
409 | | |
410 | | /* If the LI is 2 then there is an extra octet following the standard SF |
411 | | * field but it is not defined what this octet is. |
412 | | * (In any case the first byte of the SF always has the same meaning.) |
413 | | */ |
414 | 0 | if (li == 2) |
415 | 0 | proto_tree_add_item(mtp2_tree, hf_mtp2_sf_extra, su_tvb, sf_extra_offset, SF_EXTRA_LENGTH, ENC_LITTLE_ENDIAN); |
416 | |
|
417 | 0 | col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(sf, status_field_acro_vals, "Unknown")); |
418 | 0 | } |
419 | | |
420 | | static void |
421 | | dissect_mtp2_msu(tvbuff_t *su_tvb, packet_info *pinfo, proto_item *mtp2_item, |
422 | | proto_item *tree, bool use_extended_sequence_numbers) |
423 | 0 | { |
424 | 0 | int sif_sio_length; |
425 | 0 | tvbuff_t *sif_sio_tvb; |
426 | |
|
427 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "MSU "); |
428 | |
|
429 | 0 | if (use_extended_sequence_numbers) { |
430 | 0 | sif_sio_length = tvb_reported_length(su_tvb) - EXTENDED_HEADER_LENGTH; |
431 | 0 | sif_sio_tvb = tvb_new_subset_length(su_tvb, EXTENDED_SIO_OFFSET, sif_sio_length); |
432 | 0 | } else { |
433 | 0 | sif_sio_length = tvb_reported_length(su_tvb) - HEADER_LENGTH; |
434 | 0 | sif_sio_tvb = tvb_new_subset_length(su_tvb, SIO_OFFSET, sif_sio_length); |
435 | 0 | } |
436 | 0 | call_dissector(mtp3_handle, sif_sio_tvb, pinfo, tree); |
437 | |
|
438 | 0 | if (tree) { |
439 | 0 | if (use_extended_sequence_numbers) |
440 | 0 | proto_item_set_len(mtp2_item, EXTENDED_HEADER_LENGTH); |
441 | 0 | else |
442 | 0 | proto_item_set_len(mtp2_item, HEADER_LENGTH); |
443 | 0 | } |
444 | 0 | } |
445 | | |
446 | | static void |
447 | | dissect_mtp2_su(tvbuff_t *su_tvb, packet_info *pinfo, proto_item *mtp2_item, |
448 | | proto_item *mtp2_tree, proto_tree *tree, bool validate_crc, |
449 | | bool use_extended_sequence_numbers) |
450 | 0 | { |
451 | 0 | uint32_t li=0; |
452 | 0 | tvbuff_t *next_tvb = NULL; |
453 | |
|
454 | 0 | dissect_mtp2_header(su_tvb, pinfo, mtp2_tree, use_extended_sequence_numbers, validate_crc, &li); |
455 | | /* In some capture files (like .rf5), CRC are not present */ |
456 | | /* So, to avoid trouble, give the complete buffer if CRC validation is disabled */ |
457 | 0 | if (validate_crc) |
458 | 0 | next_tvb = mtp2_decode_crc16(su_tvb, mtp2_tree, pinfo); |
459 | 0 | else |
460 | 0 | next_tvb = su_tvb; |
461 | |
|
462 | 0 | switch(li) { |
463 | 0 | case 0: |
464 | 0 | dissect_mtp2_fisu(pinfo); |
465 | 0 | break; |
466 | 0 | case 1: |
467 | 0 | case 2: |
468 | 0 | dissect_mtp2_lssu(next_tvb, pinfo, mtp2_tree, use_extended_sequence_numbers, li); |
469 | 0 | break; |
470 | 0 | default: |
471 | 0 | dissect_mtp2_msu(next_tvb, pinfo, mtp2_item, tree, use_extended_sequence_numbers); |
472 | 0 | break; |
473 | 0 | } |
474 | 0 | } |
475 | | |
476 | | static void |
477 | | dissect_mtp2_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
478 | | bool validate_crc, bool use_extended_sequence_numbers) |
479 | 0 | { |
480 | 0 | proto_item *mtp2_item; |
481 | 0 | proto_tree *mtp2_tree; |
482 | |
|
483 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP2"); |
484 | |
|
485 | 0 | mtp2_item = proto_tree_add_item(tree, proto_mtp2, tvb, 0, -1, ENC_NA); |
486 | 0 | mtp2_tree = proto_item_add_subtree(mtp2_item, ett_mtp2); |
487 | |
|
488 | 0 | dissect_mtp2_su(tvb, pinfo, mtp2_item, mtp2_tree, tree, validate_crc, |
489 | 0 | use_extended_sequence_numbers); |
490 | 0 | } |
491 | | |
492 | | /* Dissect MTP2 frame without CRC16 and with a pseudo-header */ |
493 | | static int |
494 | | dissect_mtp2_with_phdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
495 | 0 | { |
496 | 0 | if (pinfo->pseudo_header->mtp2.annex_a_used == MTP2_ANNEX_A_USED_UNKNOWN) |
497 | 0 | dissect_mtp2_common(tvb, pinfo, tree, false, use_extended_sequence_numbers_default); |
498 | 0 | else |
499 | 0 | dissect_mtp2_common(tvb, pinfo, tree, false, |
500 | 0 | (pinfo->pseudo_header->mtp2.annex_a_used == MTP2_ANNEX_A_USED)); |
501 | |
|
502 | 0 | return tvb_captured_length(tvb); |
503 | 0 | } |
504 | | |
505 | | /* Dissect MTP2 frame with CRC16 included at end of payload. Used |
506 | | * if the user has associated "mtp2_with_crc" with a DLT or if the |
507 | | * packets come from an Endace ERF file. |
508 | | */ |
509 | | static int |
510 | | dissect_mtp2_with_crc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
511 | 0 | { |
512 | 0 | dissect_mtp2_common(tvb, pinfo, tree, true, use_extended_sequence_numbers_default); |
513 | 0 | return tvb_captured_length(tvb); |
514 | 0 | } |
515 | | |
516 | | /* Dissect MTP2 frame where we don't know if the CRC16 is included at |
517 | | * end of payload or not. |
518 | | */ |
519 | | static int |
520 | | dissect_mtp2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
521 | 0 | { |
522 | 0 | dissect_mtp2_common(tvb, pinfo, tree, capture_contains_fcs_crc_default, |
523 | 0 | use_extended_sequence_numbers_default); |
524 | 0 | return tvb_captured_length(tvb); |
525 | 0 | } |
526 | | |
527 | | /* get one bit of a uint8_t byte |
528 | | * based on the order set in the preferences |
529 | | * reverse_bit_order_mtp2 = false: as the Q.703 states |
530 | | * reverse_bit_order_mtp2 = true: just the opposite |
531 | | */ |
532 | | static bool |
533 | | get_bit(uint8_t byte, uint8_t bit) |
534 | 0 | { |
535 | 0 | if (reverse_bit_order_mtp2 == false) { |
536 | 0 | return byte & ((0x80 >> (bit-1))) ? true : false; |
537 | 0 | } else { |
538 | 0 | return byte & ((0x01 << (bit-1))) ? true : false; |
539 | 0 | } |
540 | 0 | } |
541 | | |
542 | | /* store new byte of an MTP2 frame in an array |
543 | | * after the whole packet is stored the array will be used to construct a new tvb */ |
544 | | static void |
545 | | new_byte(wmem_allocator_t* allocator, char full_byte, uint8_t **data, unsigned *data_len) |
546 | 0 | { |
547 | 0 | uint8_t *new_data = NULL; |
548 | 0 | unsigned i = 0; |
549 | |
|
550 | 0 | if ((*data_len) == 0) { |
551 | | /* if data was never stored in this buffer before */ |
552 | 0 | *data = wmem_new(allocator, uint8_t); |
553 | 0 | (**data) = full_byte; |
554 | 0 | (*data_len)++; |
555 | 0 | } else { |
556 | | /* if this buffer is used -> create a completely new one |
557 | | * note, that after the dissection of this packet |
558 | | * the old data will be freed automatically (because of the wmem_alloc) */ |
559 | 0 | new_data = (uint8_t *)wmem_alloc(allocator, sizeof(uint8_t)*((*data_len)+1)); |
560 | | /* copy the old one's content */ |
561 | 0 | for (i = 0;i<(*data_len);i++) { |
562 | 0 | *(new_data+i) = *((*data)+i); |
563 | 0 | } |
564 | | /* store the new data */ |
565 | 0 | *(new_data+*data_len) = full_byte; |
566 | | /* re-point the pointer to the new structure's head */ |
567 | 0 | *data = new_data; |
568 | 0 | (*data_len)++; |
569 | 0 | } |
570 | 0 | } |
571 | | |
572 | | /* based on the actual packet's addresses and ports, |
573 | | * this function determines the packet's direction */ |
574 | | static enum packet_direction_state_mtp2 |
575 | | get_direction_state(packet_info *pinfo, mtp2_convo_data_t *convo_data) |
576 | 0 | { |
577 | 0 | if (convo_data != NULL) { |
578 | 0 | if (addresses_equal(&convo_data->addr_a, &pinfo->src) |
579 | 0 | && addresses_equal(&convo_data->addr_b, &pinfo->dst) |
580 | 0 | && convo_data->port_a == pinfo->srcport |
581 | 0 | && convo_data->port_b == pinfo->destport) { |
582 | 0 | return FORWARD; |
583 | 0 | } else if (addresses_equal(&convo_data->addr_b, &pinfo->src) |
584 | 0 | && addresses_equal(&convo_data->addr_a, &pinfo->dst) |
585 | 0 | && convo_data->port_b == pinfo->srcport |
586 | 0 | && convo_data->port_a == pinfo->destport) { |
587 | 0 | return BACKWARD; |
588 | 0 | } |
589 | 0 | } |
590 | | |
591 | 0 | return FORWARD; |
592 | 0 | } |
593 | | |
594 | | /* prepares the data to be stored as found packet in wmem_list */ |
595 | | static mtp2_recognized_packet_t* |
596 | | prepare_data_for_found_packet(tvbuff_t *tvb, wmem_allocator_t* allocator, uint8_t unalignment_offset) |
597 | 0 | { |
598 | 0 | mtp2_recognized_packet_t *packet; |
599 | |
|
600 | 0 | packet = wmem_new(allocator, mtp2_recognized_packet_t); |
601 | | /* store values */ |
602 | 0 | packet->data = tvb; |
603 | 0 | packet->unalignment_offset = unalignment_offset; |
604 | |
|
605 | 0 | return packet; |
606 | 0 | } |
607 | | |
608 | | /* this function does the actual dissection of a tvb got from the RTP dissector |
609 | | * sets the mtp2_flag_search, data_buffer, it's offset and the state to the one which was stored |
610 | | * at the end of the previous packet's dissection in the same direction */ |
611 | | static mtp2_dissect_tvb_res_t* |
612 | | dissect_mtp2_tvb(tvbuff_t* tvb, packet_info* pinfo, mtp2_mtp2_flag_search_t back_mtp2_flag_search, uint8_t back_data_buff, uint8_t back_data_buff_offset, |
613 | | enum mtp2_bitstream_states back_state, uint8_t back_last_flag_beginning_offset_for_align_check) |
614 | 0 | { |
615 | 0 | uint8_t mtp2_flag_search = 0x00, /* this helps to detect the flags in the bitstream */ |
616 | 0 | data_buff = 0x00, /* buffer to store the found bits without the stuffed zeros */ |
617 | 0 | data_buff_offset = 0, /* index of the data_buff_offset, where to store the next bit */ |
618 | 0 | *found_data_buff_byte = NULL, /* buffer to store the found data_buff bytes till they are assembled to a tvb */ |
619 | 0 | flag_beginning_offset_for_align_check = 0; /* this stores the offset of the first bit in a flag */ |
620 | | #ifdef MTP2_BITSTREAM_DEBUG |
621 | | bool zero_skip0 = 0, /* needed for debug output */ |
622 | | zero_skip1 = 0, /* needed for debug output */ |
623 | | flag = false, /* needed for debug to print flag found message. reset at every new octet read from tvb */ |
624 | | frame_reset = false; /* needed for debug, informs about a frame reset */ |
625 | | #endif |
626 | 0 | unsigned available_bytes_in_rtp_payload = 0, /* stores the tvb's length which need to be analyzed */ |
627 | 0 | offset = 0, /* offset of the tvb, needed to get the appropriate byte */ |
628 | 0 | data_len = 0; /* the length of the array where the data_buff's are stored */ |
629 | 0 | enum mtp2_bitstream_states state = OUT_OF_SYNC; /* actual state of the dissection */ |
630 | 0 | tvbuff_t *new_tvb = NULL; /* tvbuff which stores the assembled data from the data pointer */ |
631 | 0 | mtp2_dissect_tvb_res_t *result = NULL; /* the result structure */ |
632 | | |
633 | | /* initialize the result structure, this will be returned at the end */ |
634 | 0 | result = wmem_new(pinfo->pool, mtp2_dissect_tvb_res_t); |
635 | 0 | result->mtp2_remain_data.before_first_flag = NULL; |
636 | 0 | result->mtp2_remain_data.before_fh_unalignment_offset = 0; |
637 | 0 | result->mtp2_remain_data.before_fh_frame_reset = false; |
638 | 0 | result->mtp2_remain_data.after_last_flag = NULL; |
639 | 0 | result->found_packets = wmem_list_new(pinfo->pool); |
640 | 0 | result->flag_found = false; |
641 | 0 | result->last_flag_beginning_offset_for_align_check = 0; |
642 | | |
643 | | /* set the mtp2_flag_search if it is set */ |
644 | 0 | if (back_mtp2_flag_search.set == true) { |
645 | 0 | mtp2_flag_search = back_mtp2_flag_search.mtp2_flag_search; |
646 | 0 | } |
647 | | /* set every other variables from the prev. packet's end in the same direction */ |
648 | 0 | data_buff = back_data_buff; |
649 | 0 | data_buff_offset = back_data_buff_offset; |
650 | 0 | state = back_state; |
651 | 0 | flag_beginning_offset_for_align_check = back_last_flag_beginning_offset_for_align_check; |
652 | | |
653 | | /* determine how many byte are in the RTP payload */ |
654 | 0 | available_bytes_in_rtp_payload = tvb_reported_length_remaining(tvb, offset); |
655 | | |
656 | | /* walk through the tvb in means of octets */ |
657 | 0 | while (offset < available_bytes_in_rtp_payload) { |
658 | | /* get actual packet's byte */ |
659 | 0 | uint8_t byte = tvb_get_uint8(tvb,offset); |
660 | | /* for every bit in the byte */ |
661 | 0 | for (uint8_t i=1; i <= 8; i++) { |
662 | | /* get the bit's boolean value got from byte[i] */ |
663 | 0 | bool bit = get_bit(byte, i); |
664 | |
|
665 | | #ifdef MTP2_BITSTREAM_DEBUG |
666 | | /* in case of debug, print just the pure RTP payload, not the previous packet's end */ |
667 | | ws_debug("%u",(bit==false?0:1)); |
668 | | #endif |
669 | | |
670 | | /* update the mtp2_flag_search */ |
671 | 0 | mtp2_flag_search = (mtp2_flag_search << 1) | bit; |
672 | | |
673 | | /* this section contains actions to be taken when the state is not OUT_OF_SYNC like |
674 | | * skipping zeros after every 5 bits */ |
675 | 0 | if (state != OUT_OF_SYNC) { |
676 | | /* The only values of mtp2_flag_search if we need to drop a zero is 0xBE and 0x3E */ |
677 | 0 | if ( (mtp2_flag_search == 0xBE || mtp2_flag_search == 0x3E)) { |
678 | | #ifdef MTP2_BITSTREAM_DEBUG |
679 | | /* set the debug variables */ |
680 | | if (zero_skip0 == 0) |
681 | | zero_skip0 = i; |
682 | | else |
683 | | zero_skip1 = i; |
684 | | #endif |
685 | | /* if we need to skip a zero, the next flag offset have to be incremented because the raw data |
686 | | * between 2 flags is not a multiple of 8 bits now */ |
687 | 0 | flag_beginning_offset_for_align_check = (flag_beginning_offset_for_align_check + 1) % 8; |
688 | 0 | } else { |
689 | | /* No drop -> store the value */ |
690 | 0 | data_buff = data_buff | (bit << data_buff_offset); |
691 | 0 | data_buff_offset++; |
692 | | /* when a new complete byte without zeros was found */ |
693 | 0 | if (data_buff_offset == 8) { |
694 | | /* we don't store flags */ |
695 | 0 | if (data_buff != 0x7E) { |
696 | | /* store the data and change the state */ |
697 | 0 | state = DATA; |
698 | 0 | new_byte(pinfo->pool, data_buff, &found_data_buff_byte, &data_len); |
699 | 0 | } |
700 | | /* clear data_buff and it's offset */ |
701 | 0 | data_buff = 0x00; |
702 | 0 | data_buff_offset = 0; |
703 | 0 | } |
704 | 0 | } |
705 | 0 | } |
706 | | /* we have a flag */ |
707 | 0 | if (mtp2_flag_search == 0x7E && |
708 | 0 | !(offset == 0 && i < 8 && back_mtp2_flag_search.set == false)) |
709 | | /* the second part of the '&&' is not to recognize the 1111110x pattern as flag in the beginning of the 1st packet in every direction |
710 | | * the 1111110 would be shifted into the mtp2_flag_search variable, this has a 0x00 initial value |
711 | | * so after shifting 7 bits, the value of mtp2_flag_search would be 01111110 however there was no leading 0*/ |
712 | 0 | { |
713 | | /* set the state */ |
714 | 0 | state = FLAGS; |
715 | | /* if before this flag, we found some real packet related bytes */ |
716 | 0 | if (data_len != 0) { |
717 | 0 | uint8_t unaligned_packet_offset = 0; /* !=0 signals if the packet just found was not a multiple of 8 bits in the bitstream */ |
718 | | /* here we check if the just found MTP2 packet is unaligned or not |
719 | | * 0 is not valid value meaning the flag_beginning_offset_for_align_check was not set at the beginning of the func. |
720 | | * if flag_beginning_offset_for_align_check != i, we have an unaligned packet */ |
721 | 0 | if (flag_beginning_offset_for_align_check != 0 && flag_beginning_offset_for_align_check != i) { |
722 | | /* set the unaligned offset */ |
723 | 0 | unaligned_packet_offset = i; |
724 | | /* clear the data_buff and offset |
725 | | * this is needed because at the next flag we would have data_buff offset unaligned |
726 | | * and we would find a 1 length packet with a part of the flag in it */ |
727 | 0 | data_buff = 0x00; |
728 | 0 | data_buff_offset = 0; |
729 | 0 | } |
730 | | /* fill the temporary buffer with data */ |
731 | 0 | uint8_t *buff = (uint8_t *) wmem_memdup(pinfo->pool, found_data_buff_byte, data_len); |
732 | | /* Allocate new tvb for the proto frame */ |
733 | 0 | new_tvb = tvb_new_child_real_data(tvb, buff, data_len, data_len); |
734 | | /* if there were no flags before, we've found the bytes before the first flag */ |
735 | 0 | if (result->flag_found == false) { |
736 | | /* this tvb is the one we found before the 1st flag */ |
737 | 0 | result->mtp2_remain_data.before_first_flag = new_tvb; |
738 | | /* if the bytes before the first flag was unaligned -> the calling function needs this info */ |
739 | 0 | result->mtp2_remain_data.before_fh_unalignment_offset = unaligned_packet_offset; |
740 | 0 | } else { |
741 | | /* add the packet to the processable packet's list */ |
742 | 0 | wmem_list_append(result->found_packets, prepare_data_for_found_packet(new_tvb,pinfo->pool,unaligned_packet_offset)); |
743 | 0 | } |
744 | | /* clear data array (free will be done automatically) */ |
745 | 0 | data_len = 0; |
746 | 0 | found_data_buff_byte = NULL; |
747 | 0 | } |
748 | |
|
749 | 0 | flag_beginning_offset_for_align_check = i; |
750 | | #ifdef MTP2_BITSTREAM_DEBUG |
751 | | /* for local debug purposes */ |
752 | | flag = true; |
753 | | #endif |
754 | | /* set the result found in the result to true */ |
755 | 0 | result->flag_found = true; |
756 | | /* 7 consecutive 1s => out of sync */ |
757 | 0 | } else if (mtp2_flag_search == 0x7F || mtp2_flag_search == 0xFE || mtp2_flag_search == 0xFF) { |
758 | | /* set the state and clear everything */ |
759 | 0 | state = OUT_OF_SYNC; |
760 | 0 | data_len = 0; |
761 | 0 | found_data_buff_byte = NULL; |
762 | 0 | data_buff = 0x00; |
763 | 0 | data_buff_offset = 0; |
764 | | #ifdef MTP2_BITSTREAM_DEBUG |
765 | | frame_reset = true; |
766 | | #endif |
767 | 0 | if (result->flag_found == false) |
768 | 0 | result->mtp2_remain_data.before_fh_frame_reset = true; |
769 | 0 | } |
770 | 0 | } |
771 | |
|
772 | | #ifdef MTP2_BITSTREAM_DEBUG |
773 | | /* if there were flag, print debug info */ |
774 | | if (flag) { |
775 | | ws_debug("\tFLAG FOUND"); |
776 | | } |
777 | | /* if there were zeros skipped, print the debug data */ |
778 | | if (!zero_skip0 == 0) { |
779 | | ws_debug("\tSKIPPED ZEROS: %u.",zero_skip0); |
780 | | if (!zero_skip1 == 0) |
781 | | ws_debug(" %u",zero_skip1); |
782 | | } |
783 | | /* if there was frame reset, print debug info */ |
784 | | if (frame_reset) { |
785 | | ws_debug("\tFRAME RESET"); |
786 | | } |
787 | | /* print a \n to print the next byte in a different row */ |
788 | | ws_debug("\n"); |
789 | | /* after every byte read from tvb clear debug stuff */ |
790 | | zero_skip0 = 0; |
791 | | zero_skip1 = 0; |
792 | | /* set the debug variables as well */ |
793 | | flag = false; |
794 | | frame_reset = false; |
795 | | #endif |
796 | | /* increment tvb offset */ |
797 | 0 | offset++; |
798 | 0 | } |
799 | |
|
800 | 0 | if (data_len != 0) { |
801 | | /* fill the temporary buffer with data */ |
802 | 0 | uint8_t * buff = (uint8_t *) wmem_memdup(pinfo->pool, found_data_buff_byte, data_len); |
803 | | /* Allocate new tvb for the MTP2 frame */ |
804 | 0 | new_tvb = tvb_new_child_real_data(tvb, buff, data_len, data_len); |
805 | | /* this tvb is the one we found after the last flag */ |
806 | 0 | result->mtp2_remain_data.after_last_flag = new_tvb; |
807 | 0 | } |
808 | | |
809 | | /* we do not return NULL in before_first_flag because then the reassemble will not work |
810 | | * we have to add a 0 length tvb with the flag "no more packets" */ |
811 | 0 | if (result->mtp2_remain_data.before_first_flag == NULL) { |
812 | | /* fill the temporary buffer with data */ |
813 | 0 | uint8_t *buff = (uint8_t *) wmem_memdup(pinfo->pool, found_data_buff_byte, 0); |
814 | | /* Allocate new tvb for the MTP2 frame */ |
815 | 0 | new_tvb = tvb_new_child_real_data(tvb, buff, 0, 0); |
816 | | /* this tvb is the one we found after the last flag */ |
817 | 0 | result->mtp2_remain_data.before_first_flag = new_tvb; |
818 | 0 | } |
819 | | |
820 | | /* don't set mtp2_flag_search and other stuff if the packet ended in out_of_sync */ |
821 | 0 | if (state != OUT_OF_SYNC) { |
822 | 0 | result->mtp2_flag_search.set = true; |
823 | 0 | result->mtp2_flag_search.mtp2_flag_search = mtp2_flag_search; |
824 | 0 | result->data_buff = data_buff; |
825 | 0 | result->data_buff_offset = data_buff_offset; |
826 | 0 | } else { |
827 | 0 | result->mtp2_flag_search.set = false; |
828 | 0 | result->mtp2_flag_search.mtp2_flag_search = result->data_buff = result->data_buff_offset = 0x00; |
829 | 0 | } |
830 | | |
831 | | /* set the state as well, in every case */ |
832 | 0 | result->state = state; |
833 | | |
834 | | /* set the last_flag_beginning_offset_for_align_check in the result structure */ |
835 | 0 | result->last_flag_beginning_offset_for_align_check = flag_beginning_offset_for_align_check; |
836 | | |
837 | | /* return the result structure */ |
838 | 0 | return result; |
839 | 0 | } |
840 | | |
841 | | /* function to get a new reass. sequence number */ |
842 | | static uint32_t |
843 | | get_new_reass_seq_num(void) |
844 | 0 | { |
845 | | /* fail if it reached the max value */ |
846 | 0 | DISSECTOR_ASSERT(mtp2_absolute_reass_seq_num < 0xFFFFFFFE); |
847 | 0 | mtp2_absolute_reass_seq_num++; |
848 | |
|
849 | 0 | return mtp2_absolute_reass_seq_num; |
850 | 0 | } |
851 | | |
852 | | |
853 | | /* sign if the packet is unaligned in proto tree */ |
854 | | static void |
855 | | issue_unaligned_info(proto_tree *tree, tvbuff_t *tvb, uint8_t unalignment_offset) |
856 | 0 | { |
857 | 0 | proto_tree_add_none_format(tree, hf_mtp2_unexpect_end, tvb, 0, tvb_reported_length_remaining(tvb,0), |
858 | 0 | "[Packet ended in the middle of an octet. Octet: last, Offset: %u]", |
859 | 0 | unalignment_offset); |
860 | 0 | } |
861 | | |
862 | | /* sign if the packet is unaligned in proto tree */ |
863 | | static void |
864 | | issue_frame_reset_info(proto_tree *tree, tvbuff_t *tvb) |
865 | 0 | { |
866 | 0 | proto_tree_add_none_format(tree, hf_mtp2_frame_reset, tvb, 0, 0, |
867 | 0 | "[Frame Reset Occurred, No Reassembly]"); |
868 | 0 | } |
869 | | |
870 | | /* set per packet data based on direction data */ |
871 | | static void |
872 | | set_ppd_fields_based_on_convo_directon_data(mtp2_ppd_t *mtp2_ppd, mtp2_convo_data_prev_packet_t *direction_data) |
873 | 0 | { |
874 | 0 | mtp2_ppd->mtp2_flag_search = direction_data->mtp2_flag_search; |
875 | 0 | mtp2_ppd->data_buff = direction_data->data_buff; |
876 | 0 | mtp2_ppd->data_buff_offset = direction_data->data_buff_offset; |
877 | 0 | mtp2_ppd->state = direction_data->state; |
878 | | /* this is because the segment which will be reassembled in this packet |
879 | | * is stored with the reass_seq_num stored in the convo data |
880 | | * therefore we have to save this value for dissection in the future */ |
881 | 0 | mtp2_ppd->reass_seq_num_for_reass_check_before_fh = direction_data->reass_seq_num; |
882 | 0 | mtp2_ppd->last_flag_beginning_offset_for_align_check = direction_data->last_flag_beginning_offset_for_align_check; |
883 | 0 | } |
884 | | |
885 | | /* set convo data based on dissection result and reass_seq_num */ |
886 | | static void |
887 | | set_direction_fields_based_on_result_and_reass_seq_num(mtp2_convo_data_prev_packet_t *direction_data, mtp2_dissect_tvb_res_t *result, uint32_t reass_seq_num) |
888 | 0 | { |
889 | 0 | direction_data->mtp2_flag_search = result->mtp2_flag_search; |
890 | 0 | direction_data->data_buff = result->data_buff; |
891 | 0 | direction_data->data_buff_offset = result->data_buff_offset; |
892 | 0 | direction_data->state = result->state; |
893 | 0 | direction_data->reass_seq_num = reass_seq_num; |
894 | 0 | direction_data->last_flag_beginning_offset_for_align_check = result->last_flag_beginning_offset_for_align_check; |
895 | 0 | } |
896 | | |
897 | | /* function to dissect bitstream data of MTP2 */ |
898 | | static int |
899 | | dissect_mtp2_bitstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * user_data _U_) |
900 | 0 | { |
901 | 0 | uint32_t reass_seq_num = 0; /* reassemble sequence number at the beginning of this packet's dissection */ |
902 | 0 | conversation_t *conversation = NULL; /* conversation of the mtp2 dissection */ |
903 | 0 | mtp2_convo_data_t *convo_data = NULL; /* conversation data of the mtp2 dissection */ |
904 | 0 | mtp2_dissect_tvb_res_t *result = NULL; /* variable to store the result of dissect_mtp2_tvb */ |
905 | 0 | enum packet_direction_state_mtp2 dir_state = FORWARD; /* direction state of this packet in the conversation */ |
906 | 0 | mtp2_ppd_t *mtp2_ppd = NULL; /* per-packet data of this packet */ |
907 | |
|
908 | | #ifdef MTP2_BITSTREAM_DEBUG |
909 | | ws_debug("start_dissect_bitstream_packet: %u\n",pinfo->fd->num); |
910 | | #endif |
911 | | |
912 | | /* find conversation related to this packet */ |
913 | 0 | conversation = find_conversation(pinfo->fd->num,&pinfo->src, &pinfo->dst,conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport, pinfo->destport, 0); |
914 | | /* if there is no conversation or it does not contain the per packet data we need */ |
915 | 0 | if (conversation == NULL) { |
916 | | /* there was no conversation => this packet is the first in a new conversation => let's create it */ |
917 | | /* here we decide about the direction, every following packet with the same direction as this first one will be a forward packet */ |
918 | 0 | conversation = conversation_new(pinfo->fd->num,&pinfo->src, &pinfo->dst,conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport, pinfo->destport, 0); |
919 | 0 | } |
920 | | |
921 | | /* there is no proto data in the conversation */ |
922 | 0 | if (conversation_get_proto_data(conversation, proto_mtp2) == NULL) { |
923 | | /* create a new convo data and fill it with initial data */ |
924 | 0 | convo_data = wmem_new(wmem_file_scope(), mtp2_convo_data_t); |
925 | 0 | copy_address_wmem(wmem_file_scope(), &convo_data->addr_a, &pinfo->src); |
926 | 0 | copy_address_wmem(wmem_file_scope(), &convo_data->addr_b, &pinfo->dst); |
927 | 0 | convo_data->port_a = pinfo->srcport; |
928 | 0 | convo_data->port_b = pinfo->destport; |
929 | 0 | convo_data->forward = wmem_new(wmem_file_scope(), mtp2_convo_data_prev_packet_t); |
930 | 0 | convo_data->backward = wmem_new(wmem_file_scope(), mtp2_convo_data_prev_packet_t); |
931 | 0 | convo_data->forward->mtp2_flag_search.set = convo_data->backward->mtp2_flag_search.set= false; |
932 | 0 | convo_data->forward->mtp2_flag_search.mtp2_flag_search = convo_data->backward->mtp2_flag_search.mtp2_flag_search = 0x00; |
933 | 0 | convo_data->forward->data_buff = convo_data->backward->data_buff = 0x00; |
934 | 0 | convo_data->forward->data_buff_offset = convo_data->backward->data_buff_offset = 0; |
935 | 0 | convo_data->forward->state = convo_data->backward->state = OUT_OF_SYNC; |
936 | 0 | convo_data->forward->reass_seq_num = get_new_reass_seq_num(); |
937 | 0 | convo_data->backward->reass_seq_num = get_new_reass_seq_num(); |
938 | 0 | convo_data->forward->last_flag_beginning_offset_for_align_check = convo_data->backward->last_flag_beginning_offset_for_align_check = 0; |
939 | | /* store the convo data */ |
940 | 0 | conversation_add_proto_data(conversation, proto_mtp2, convo_data); |
941 | 0 | } else { |
942 | | /* the packet is part of an existing conversation => get the conversation data */ |
943 | 0 | convo_data = (mtp2_convo_data_t*)conversation_get_proto_data(conversation, proto_mtp2); |
944 | 0 | } |
945 | | |
946 | | /* get the packet's state */ |
947 | 0 | dir_state = get_direction_state(pinfo, convo_data); |
948 | | |
949 | | /* get the per packet data */ |
950 | 0 | mtp2_ppd = (mtp2_ppd_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_mtp2, pinfo->fd->num); |
951 | | |
952 | | /* if there is no per packet data -> create it */ |
953 | 0 | if (mtp2_ppd == NULL) { |
954 | 0 | mtp2_ppd = wmem_new0(wmem_file_scope(), mtp2_ppd_t); |
955 | | /* set the proto_data_fields |
956 | | * because these are the values which we would like to see |
957 | | * if this packet is seen again */ |
958 | 0 | if (dir_state == FORWARD) { |
959 | 0 | set_ppd_fields_based_on_convo_directon_data(mtp2_ppd, convo_data->forward); |
960 | 0 | } else { |
961 | 0 | set_ppd_fields_based_on_convo_directon_data(mtp2_ppd, convo_data->backward); |
962 | 0 | } |
963 | | /* store the ppd to be able to get in the next time we see this packet */ |
964 | 0 | p_add_proto_data(wmem_file_scope(), pinfo, proto_mtp2, pinfo->fd->num, mtp2_ppd); |
965 | 0 | } |
966 | | |
967 | | /* get the reass. seq num from the ppd |
968 | | * this is needed because it is modified and stored in the convo_data */ |
969 | 0 | reass_seq_num = mtp2_ppd->reass_seq_num_for_reass_check_before_fh; |
970 | | |
971 | | /* call the function to dissect this actual tvb */ |
972 | 0 | result = dissect_mtp2_tvb(tvb, pinfo, |
973 | 0 | mtp2_ppd->mtp2_flag_search, |
974 | 0 | mtp2_ppd->data_buff, |
975 | 0 | mtp2_ppd->data_buff_offset, |
976 | 0 | mtp2_ppd->state, |
977 | 0 | mtp2_ppd->last_flag_beginning_offset_for_align_check); |
978 | | |
979 | | /* if this is the first time, do the reassemble things |
980 | | * else just check for reassembled data */ |
981 | 0 | if (pinfo->fd->visited == false) { |
982 | | /* if there was a flag in this tvb, the data found before the 1st flag |
983 | | * have to be treated differently than the data found after the last flag |
984 | | * this means we need to use different reass_seq_num when adding them to the reass. handler */ |
985 | 0 | if (result->flag_found == true) { |
986 | | /* add the data found before the first flag with the same reass_seq_num as the |
987 | | * data found after the last flag in the previous packet in this direction */ |
988 | 0 | fragment_add_seq_next(&mtp2_reassembly_table, /* bookkeeping table */ |
989 | 0 | result->mtp2_remain_data.before_first_flag, /* tvb containing the data which was unidentified before the first flag */ |
990 | 0 | 0, /* offset is 0 because this tvb contains the unidentified data only */ |
991 | 0 | pinfo, |
992 | 0 | mtp2_ppd->reass_seq_num_for_reass_check_before_fh, /* sequence number of the fragment stream */ |
993 | 0 | NULL, /* additional data to identify the segment */ |
994 | 0 | tvb_reported_length_remaining(result->mtp2_remain_data.before_first_flag, 0), /* length is the whole tvb's length */ |
995 | 0 | false); /* there are no more fragments */ |
996 | | |
997 | | /* get a new reass seq num for the data found after the last flag */ |
998 | 0 | mtp2_ppd->reass_seq_num_for_reass_check_after_lh = reass_seq_num = get_new_reass_seq_num(); |
999 | | |
1000 | | /* if there were data found after the last flag, add it to the reass. handler with the new reass_seq_num */ |
1001 | 0 | if (result->mtp2_remain_data.after_last_flag != NULL) { |
1002 | 0 | fragment_add_seq_next(&mtp2_reassembly_table, /* bookkeeping table */ |
1003 | 0 | result->mtp2_remain_data.after_last_flag, /* tvb containing the data which was unidentified before the first flag */ |
1004 | 0 | 0, /* offset is 0 because this tvb contains the unidentified data only */ |
1005 | 0 | pinfo, |
1006 | 0 | mtp2_ppd->reass_seq_num_for_reass_check_after_lh, /* sequence number of the fragment stream */ |
1007 | 0 | NULL, /* additional data to identify the segment */ |
1008 | 0 | tvb_reported_length_remaining(result->mtp2_remain_data.after_last_flag, 0), /* length is the whole tvb's length */ |
1009 | 0 | true); /* there are more fragments */ |
1010 | 0 | } |
1011 | 0 | } else { |
1012 | | /* here the increment of the reass_seq_num is not needed because this RTP frame was completely part |
1013 | | * of an MTP2 frame beginning in the previous packet |
1014 | | * this need to be added with the same reass_seq_num */ |
1015 | 0 | if (result->mtp2_remain_data.after_last_flag != NULL) { |
1016 | 0 | fragment_add_seq_next(&mtp2_reassembly_table, /* bookkeeping table */ |
1017 | 0 | result->mtp2_remain_data.after_last_flag, /* tvb containing the data which was unidentified before the first flag */ |
1018 | 0 | 0, /* offset is 0 because this tvb contains the unidentified data only */ |
1019 | 0 | pinfo, |
1020 | 0 | mtp2_ppd->reass_seq_num_for_reass_check_before_fh, /* sequence number of the fragment stream */ |
1021 | 0 | NULL, /* additional data to identify the segment */ |
1022 | 0 | tvb_reported_length_remaining(result->mtp2_remain_data.after_last_flag, 0), /* length is the whole tvb's length */ |
1023 | 0 | true); /* there are more fragments */ |
1024 | 0 | } |
1025 | 0 | } |
1026 | | /* store the values in convo_data |
1027 | | * but just in case if this packet was not seen before |
1028 | | * if it was |
1029 | | * then the convo data shall not be used (contains inappropriate info for us |
1030 | | * the actual values needed for reassembly should be get from the mtp2_ppd |
1031 | | * therefore no need to set the convo data */ |
1032 | | /* differentiate between forward and backward directions */ |
1033 | 0 | if (dir_state == FORWARD) { |
1034 | 0 | set_direction_fields_based_on_result_and_reass_seq_num(convo_data->forward, result, reass_seq_num); |
1035 | 0 | } else { |
1036 | 0 | set_direction_fields_based_on_result_and_reass_seq_num(convo_data->backward, result, reass_seq_num); |
1037 | 0 | } |
1038 | | |
1039 | | /* if the packet was seen before */ |
1040 | 0 | } else { |
1041 | 0 | tvbuff_t *new_tvb = NULL; |
1042 | 0 | fragment_head *frag_msg_before_fh = NULL; |
1043 | 0 | fragment_head *frag_msg_after_lh = NULL; |
1044 | 0 | char *col_info_str = NULL; /* char array to store temporary string for col info update */ |
1045 | | |
1046 | | /* get the fragment data both for before first and after last flags */ |
1047 | | /* before first flag */ |
1048 | 0 | frag_msg_before_fh = fragment_get_reassembled_id(&mtp2_reassembly_table, |
1049 | 0 | pinfo, |
1050 | 0 | mtp2_ppd->reass_seq_num_for_reass_check_before_fh); |
1051 | | /* after last flag */ |
1052 | 0 | frag_msg_after_lh = fragment_get_reassembled_id(&mtp2_reassembly_table, |
1053 | 0 | pinfo, |
1054 | 0 | mtp2_ppd->reass_seq_num_for_reass_check_after_lh); |
1055 | | /* if there is reassembled data before the first flag */ |
1056 | 0 | if (frag_msg_before_fh != NULL) { |
1057 | | /* get the reassembled tvb */ |
1058 | 0 | new_tvb = process_reassembled_data(result->mtp2_remain_data.before_first_flag, |
1059 | 0 | 0, |
1060 | 0 | pinfo, |
1061 | 0 | (result->mtp2_remain_data.before_fh_unalignment_offset != 0 |
1062 | 0 | ?"Reassembled MTP2 Packet [Unaligned]" |
1063 | 0 | :"Reassembled MTP2 Packet"), |
1064 | 0 | frag_msg_before_fh, |
1065 | 0 | &mtp2_frag_items, |
1066 | 0 | NULL, |
1067 | 0 | tree); |
1068 | | /* there is reassembled data */ |
1069 | 0 | if (new_tvb != NULL && tvb_reported_length_remaining(new_tvb, 0) > 0) { |
1070 | | |
1071 | | /* if there was a frame reset before the first flag */ |
1072 | 0 | if (result->mtp2_remain_data.before_fh_frame_reset == true) { |
1073 | | /* issue frame reset */ |
1074 | 0 | issue_frame_reset_info(tree, new_tvb); |
1075 | | /* prepare col_info string */ |
1076 | 0 | col_info_str = "[Frame Reset in reassembly]"; |
1077 | 0 | } else { |
1078 | | /* append the reassembled packet to the head of the packet list */ |
1079 | 0 | wmem_list_prepend(result->found_packets, prepare_data_for_found_packet(new_tvb,pinfo->pool,result->mtp2_remain_data.before_fh_unalignment_offset)); |
1080 | | /* set the protocol name */ |
1081 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP2"); |
1082 | 0 | } |
1083 | 0 | } |
1084 | 0 | } |
1085 | | |
1086 | | /* if there were packets found */ |
1087 | 0 | if (wmem_list_count(result->found_packets) != 0) { |
1088 | | /* boolean variable to help to print proper col_info if unaligned packet is found */ |
1089 | 0 | bool was_unaligned_packet = false; |
1090 | | /* pointer walking through the list of found packets */ |
1091 | 0 | wmem_list_frame_t *recognized_packet = wmem_list_head(result->found_packets); |
1092 | | |
1093 | | /* info field pre-set, we can see the MTP2 strings even if there is an error in the dissection */ |
1094 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP2"); |
1095 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "MTP2"); |
1096 | | /* while there are available packets */ |
1097 | 0 | while (recognized_packet != NULL) { |
1098 | 0 | mtp2_recognized_packet_t *recognized_packet_data = (mtp2_recognized_packet_t *) wmem_list_frame_data(recognized_packet); |
1099 | 0 | if (recognized_packet_data->unalignment_offset == 0) { |
1100 | | /* pass the data to the mtp2 dissector */ |
1101 | 0 | add_new_data_source(pinfo, recognized_packet_data->data, "MTP2 packet"); |
1102 | 0 | dissect_mtp2_common(recognized_packet_data->data, pinfo, tree, false, use_extended_sequence_numbers_default); |
1103 | 0 | } else { |
1104 | 0 | add_new_data_source(pinfo, recognized_packet_data->data, "MTP2 packet [Unaligned]"); |
1105 | 0 | issue_unaligned_info(tree, recognized_packet_data->data, recognized_packet_data->unalignment_offset); |
1106 | 0 | was_unaligned_packet = true; |
1107 | 0 | } |
1108 | | |
1109 | | /* increment the pointer */ |
1110 | 0 | recognized_packet = wmem_list_frame_next(recognized_packet); |
1111 | 0 | } |
1112 | | /* insert how many packets were found */ |
1113 | 0 | col_info_str = wmem_strdup_printf(pinfo->pool, "%s: %u Packet%s%s%s", |
1114 | 0 | "MTP2", |
1115 | 0 | wmem_list_count(result->found_packets), |
1116 | 0 | (wmem_list_count(result->found_packets) > 1 |
1117 | 0 | ?"s" |
1118 | 0 | :"" |
1119 | 0 | ), |
1120 | 0 | (was_unaligned_packet |
1121 | 0 | ?wmem_strdup_printf(pinfo->pool, " [Unaligned Packet%s]", (wmem_list_count(result->found_packets)>1 |
1122 | 0 | ?"s" |
1123 | 0 | :"")) |
1124 | 0 | :"" |
1125 | 0 | ), |
1126 | 0 | (col_info_str == NULL |
1127 | 0 | ?"" |
1128 | 0 | :col_info_str |
1129 | 0 | ) |
1130 | 0 | ); |
1131 | 0 | col_add_str(pinfo->cinfo, COL_INFO, col_info_str); |
1132 | | /* if there were no packets found */ |
1133 | 0 | } else { |
1134 | 0 | if (tvb_reported_length_remaining(result->mtp2_remain_data.before_first_flag,0) == 0 |
1135 | 0 | && result->mtp2_remain_data.after_last_flag != NULL |
1136 | 0 | && frag_msg_before_fh) |
1137 | 0 | { |
1138 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP2"); |
1139 | 0 | col_info_str = wmem_strdup_printf(pinfo->pool, "[MTP2 Reassembled in: %u]", frag_msg_before_fh->reassembled_in); |
1140 | 0 | col_add_str(pinfo->cinfo, COL_INFO, col_info_str); |
1141 | 0 | } else { |
1142 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP2"); |
1143 | 0 | col_info_str = "[MTP2 No Packets]"; |
1144 | 0 | col_set_str(pinfo->cinfo, COL_INFO, col_info_str); |
1145 | 0 | } |
1146 | 0 | } |
1147 | | /* this adds the "Reassembled in" text to the proto tree to the packet where there is leftover data at the end */ |
1148 | 0 | process_reassembled_data(result->mtp2_remain_data.after_last_flag, |
1149 | 0 | 0, |
1150 | 0 | pinfo, |
1151 | 0 | "Reassembled MTP2 Packet", |
1152 | 0 | frag_msg_after_lh, |
1153 | 0 | &mtp2_frag_items, |
1154 | 0 | NULL, |
1155 | 0 | tree); |
1156 | 0 | } |
1157 | | |
1158 | | /* the whole tvb was processed */ |
1159 | 0 | return tvb_captured_length(tvb); |
1160 | 0 | } |
1161 | | |
1162 | | void |
1163 | | proto_register_mtp2(void) |
1164 | 16 | { |
1165 | | |
1166 | 16 | static hf_register_info hf[] = { |
1167 | 16 | { &hf_mtp2_bsn, { "Backward sequence number", "mtp2.bsn", FT_UINT8, BASE_DEC, NULL, BSN_MASK, NULL, HFILL } }, |
1168 | 16 | { &hf_mtp2_ext_bsn, { "Backward sequence number", "mtp2.bsn", FT_UINT16, BASE_DEC, NULL, EXTENDED_BSN_MASK, NULL, HFILL } }, |
1169 | 16 | { &hf_mtp2_ext_res, { "Reserved", "mtp2.res", FT_UINT16, BASE_DEC, NULL, EXTENDED_RES_MASK, NULL, HFILL } }, |
1170 | 16 | { &hf_mtp2_bib, { "Backward indicator bit", "mtp2.bib", FT_UINT8, BASE_DEC, NULL, BIB_MASK, NULL, HFILL } }, |
1171 | 16 | { &hf_mtp2_ext_bib, { "Backward indicator bit", "mtp2.bib", FT_UINT16, BASE_DEC, NULL, EXTENDED_BIB_MASK, NULL, HFILL } }, |
1172 | 16 | { &hf_mtp2_fsn, { "Forward sequence number", "mtp2.fsn", FT_UINT8, BASE_DEC, NULL, FSN_MASK, NULL, HFILL } }, |
1173 | 16 | { &hf_mtp2_ext_fsn, { "Forward sequence number", "mtp2.fsn", FT_UINT16, BASE_DEC, NULL, EXTENDED_FSN_MASK, NULL, HFILL } }, |
1174 | 16 | { &hf_mtp2_fib, { "Forward indicator bit", "mtp2.fib", FT_UINT8, BASE_DEC, NULL, FIB_MASK, NULL, HFILL } }, |
1175 | 16 | { &hf_mtp2_ext_fib, { "Forward indicator bit", "mtp2.fib", FT_UINT16, BASE_DEC, NULL, EXTENDED_FIB_MASK, NULL, HFILL } }, |
1176 | 16 | { &hf_mtp2_li, { "Length Indicator", "mtp2.li", FT_UINT8, BASE_DEC, NULL, LI_MASK, NULL, HFILL } }, |
1177 | 16 | { &hf_mtp2_ext_li, { "Length Indicator", "mtp2.li", FT_UINT16, BASE_DEC, NULL, EXTENDED_LI_MASK, NULL, HFILL } }, |
1178 | 16 | { &hf_mtp2_spare, { "Spare", "mtp2.spare", FT_UINT8, BASE_DEC, NULL, SPARE_MASK, NULL, HFILL } }, |
1179 | 16 | { &hf_mtp2_ext_spare, { "Spare", "mtp2.spare", FT_UINT16, BASE_DEC, NULL, EXTENDED_SPARE_MASK, NULL, HFILL } }, |
1180 | 16 | { &hf_mtp2_sf, { "Status field", "mtp2.sf", FT_UINT8, BASE_DEC, VALS(status_field_vals), 0x0, NULL, HFILL } }, |
1181 | 16 | { &hf_mtp2_sf_extra, { "Status field extra octet", "mtp2.sf_extra", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
1182 | 16 | { &hf_mtp2_fcs_16, { "FCS 16", "mtp2.fcs_16", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
1183 | 16 | { &hf_mtp2_fcs_16_status, { "FCS 16", "mtp2.fcs_16.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL } }, |
1184 | 16 | { &hf_mtp2_unexpect_end, { "Unexpected packet end","mtp2.unexpected_end", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
1185 | 16 | { &hf_mtp2_frame_reset, { "Frame reset", "mtp2.frame_reset", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
1186 | | /* extend header fields with the reassemble ones */ |
1187 | 16 | {&hf_mtp2_fragments, |
1188 | 16 | {"Message fragments", "mtp2.msg.fragments", |
1189 | 16 | FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } }, |
1190 | 16 | {&hf_mtp2_fragment, |
1191 | 16 | {"Message fragment", "mtp2.msg.fragment", |
1192 | 16 | FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, |
1193 | 16 | {&hf_mtp2_fragment_overlap, |
1194 | 16 | {"Message fragment overlap", "mtp2.msg.fragment.overlap", |
1195 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, |
1196 | 16 | {&hf_mtp2_fragment_overlap_conflicts, |
1197 | 16 | {"Message fragment overlapping with conflicting data", |
1198 | 16 | "mtp2.msg.fragment.overlap.conflicts", |
1199 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, |
1200 | 16 | {&hf_mtp2_fragment_multiple_tails, |
1201 | 16 | {"Message has multiple tail fragments", |
1202 | 16 | "mtp2.msg.fragment.multiple_tails", |
1203 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, |
1204 | 16 | {&hf_mtp2_fragment_too_long_fragment, |
1205 | 16 | {"Message fragment too long", "mtp2.msg.fragment.too_long_fragment", |
1206 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, |
1207 | 16 | {&hf_mtp2_fragment_error, |
1208 | 16 | {"Message defragmentation error", "mtp2.msg.fragment.error", |
1209 | 16 | FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, |
1210 | 16 | {&hf_mtp2_fragment_count, |
1211 | 16 | {"Message defragmentation count", "mtp2.msg.fragment.count", |
1212 | 16 | FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, |
1213 | 16 | {&hf_mtp2_reassembled_in, |
1214 | 16 | {"Reassembled in", "mtp2.msg.reassembled.in", |
1215 | 16 | FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, |
1216 | 16 | {&hf_mtp2_reassembled_length, |
1217 | 16 | {"Reassembled length", "mtp2.msg.reassembled.length", |
1218 | 16 | FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } } |
1219 | 16 | }; |
1220 | | |
1221 | 16 | static int *ett[] = { |
1222 | 16 | &ett_mtp2, |
1223 | | /* extend ett with the fragment fields */ |
1224 | 16 | &ett_mtp2_fragment, |
1225 | 16 | &ett_mtp2_fragments |
1226 | 16 | }; |
1227 | | |
1228 | 16 | static ei_register_info ei[] = { |
1229 | 16 | { &ei_mtp2_checksum_error, { "mtp2.checksum.error", PI_CHECKSUM, PI_WARN, "MTP2 Frame CheckFCS 16 Error", EXPFILL }}, |
1230 | 16 | { &ei_mtp2_li_bad, { "mtp2.li.bad", PI_PROTOCOL, PI_WARN, "Bad length indicator value", EXPFILL }}, |
1231 | 16 | }; |
1232 | | |
1233 | 16 | module_t *mtp2_module; |
1234 | 16 | expert_module_t* expert_mtp2; |
1235 | | |
1236 | 16 | proto_mtp2 = proto_register_protocol("Message Transfer Part Level 2", "MTP2", "mtp2"); |
1237 | 16 | mtp2_handle = register_dissector("mtp2", dissect_mtp2, proto_mtp2); |
1238 | 16 | register_dissector("mtp2_with_crc", dissect_mtp2_with_crc, proto_mtp2); |
1239 | 16 | mtp2_with_phdr_handle = register_dissector("mtp2_with_phdr", dissect_mtp2_with_phdr, |
1240 | 16 | proto_mtp2); |
1241 | 16 | mtp2_bitstream_handle = register_dissector("mtp2_bitstream", dissect_mtp2_bitstream, proto_mtp2); |
1242 | | |
1243 | 16 | proto_register_field_array(proto_mtp2, hf, array_length(hf)); |
1244 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
1245 | 16 | expert_mtp2 = expert_register_protocol(proto_mtp2); |
1246 | 16 | expert_register_field_array(expert_mtp2, ei, array_length(ei)); |
1247 | | |
1248 | 16 | mtp2_module = prefs_register_protocol(proto_mtp2, NULL); |
1249 | 16 | prefs_register_bool_preference(mtp2_module, |
1250 | 16 | "use_extended_sequence_numbers", |
1251 | 16 | "Use extended sequence numbers", |
1252 | 16 | "Whether the MTP2 dissector should use extended sequence numbers as described in Q.703, Annex A as a default.", |
1253 | 16 | &use_extended_sequence_numbers_default); |
1254 | 16 | prefs_register_bool_preference(mtp2_module, |
1255 | 16 | "capture_contains_frame_check_sequence", |
1256 | 16 | "Assume packets have FCS", |
1257 | 16 | "Some SS7 capture hardware includes the FCS at the end of the packet, others do not.", |
1258 | 16 | &capture_contains_fcs_crc_default); |
1259 | | |
1260 | | /* register bool and range preferences */ |
1261 | 16 | prefs_register_bool_preference(mtp2_module, |
1262 | 16 | "reverse_bit_order_mtp2", |
1263 | 16 | "Reverse bit order inside bytes", |
1264 | 16 | "Reverse the bit order inside bytes specified in Q.703.", |
1265 | 16 | &reverse_bit_order_mtp2); |
1266 | 16 | prefs_register_obsolete_preference(mtp2_module, "rtp_payload_type"); |
1267 | | |
1268 | 16 | reassembly_table_register(&mtp2_reassembly_table, &addresses_ports_reassembly_table_functions); |
1269 | 16 | } |
1270 | | |
1271 | | void |
1272 | | proto_reg_handoff_mtp2(void) |
1273 | 16 | { |
1274 | 16 | dissector_add_uint("wtap_encap", WTAP_ENCAP_MTP2, mtp2_handle); |
1275 | 16 | dissector_add_uint("wtap_encap", WTAP_ENCAP_MTP2_WITH_PHDR, |
1276 | 16 | mtp2_with_phdr_handle); |
1277 | | |
1278 | 16 | mtp3_handle = find_dissector_add_dependency("mtp3", proto_mtp2); |
1279 | | |
1280 | 16 | dissector_add_string("rtp_dyn_payload_type", "MTP2", mtp2_bitstream_handle); |
1281 | | |
1282 | 16 | dissector_add_uint_range_with_preference("rtp.pt", "", mtp2_bitstream_handle); |
1283 | 16 | } |
1284 | | |
1285 | | /* |
1286 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1287 | | * |
1288 | | * Local Variables: |
1289 | | * c-basic-offset: 2 |
1290 | | * tab-width: 8 |
1291 | | * indent-tabs-mode: nil |
1292 | | * End: |
1293 | | * |
1294 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
1295 | | * :indentSize=2:tabSize=8:noTabs=true: |
1296 | | */ |