/src/wireshark/epan/dissectors/packet-tdmop.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-tdmop.c |
2 | | * Routines for TDM over Packet network disassembly |
3 | | * Copyright 2015, Andrew Chernyh <andew.chernyh@gmail.com> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | /* |
12 | | * TDMoP protocol is proprietary protocol developed by "NSC Communication Siberia Ltd." |
13 | | */ |
14 | | #include "config.h" |
15 | | #include <epan/packet.h> |
16 | | #include <epan/conversation.h> |
17 | | #include <epan/prefs.h> |
18 | | |
19 | | /*Using of ethertype 0x0808(assigned to Frame Relay ARP) was implemented in hardware, when ethertype was not assigned*/ |
20 | | #define ETHERTYPE_TDMOP 0 |
21 | | |
22 | 0 | #define MAX_DCHANNEL_LEN 128 |
23 | | |
24 | | void proto_register_tdmop(void); |
25 | | void proto_reg_handoff_tdmop(void); |
26 | | |
27 | | static dissector_handle_t tdmop_handle; |
28 | | |
29 | | static int proto_tdmop; |
30 | | static int ett_tdmop; |
31 | | static int ett_tdmop_channel; |
32 | | |
33 | | static int hf_tdmop_TransferID; |
34 | | static int hf_tdmop_DstCh; |
35 | | static int hf_tdmop_SrcCh; |
36 | | static int hf_tdmop_Flags; |
37 | | static int hf_tdmop_Flags_no_data; |
38 | | static int hf_tdmop_Flags_lost_request; |
39 | | static int hf_tdmop_Flags_remote_no_data; |
40 | | static int hf_tdmop_Flags_compressed; |
41 | | static int hf_tdmop_SrcDst; |
42 | | static int hf_tdmop_SeqNum; |
43 | | static int hf_tdmop_LastRecv; |
44 | | static int hf_tdmop_Delay; |
45 | | static int hf_tdmop_Reserved; |
46 | | static int hf_tdmop_payload; |
47 | | static int hf_tdmop_Compression_mask; |
48 | | |
49 | | static dissector_handle_t lapd_handle; |
50 | | |
51 | | static int pref_tdmop_d_channel = 16; |
52 | | static uint32_t pref_tdmop_mask = 0xFFFFFFFFUL; |
53 | | static uint32_t pref_tdmop_ethertype = ETHERTYPE_TDMOP; |
54 | | |
55 | 14 | #define TDMOP_FLAG_NO_DATA (1<<3) |
56 | 14 | #define TDMOP_FLAG_REMOTE_NO_DATA (1<<2) |
57 | 14 | #define TDMOP_FLAG_COMPRESSED (1<<4) |
58 | 14 | #define TDMOP_FLAG_LOST_REQUEST ((1<<3)|(0x02)) |
59 | | |
60 | | static uint8_t reverse_map[256]= |
61 | | { |
62 | | 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, |
63 | | 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, |
64 | | 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, |
65 | | 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, |
66 | | 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, |
67 | | 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, |
68 | | 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, |
69 | | 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, |
70 | | 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, |
71 | | 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, |
72 | | 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, |
73 | | 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, |
74 | | 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, |
75 | | 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, |
76 | | 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, |
77 | | 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF |
78 | | }; |
79 | | |
80 | | static int dissect_tdmop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
81 | 0 | { |
82 | 0 | uint8_t dchannel_data[MAX_DCHANNEL_LEN]; |
83 | 0 | unsigned dchannel_len; |
84 | 0 | uint8_t flags; |
85 | 0 | int offset; |
86 | 0 | proto_item *ti; |
87 | 0 | proto_tree *tdmop_tree; |
88 | 0 | uint32_t dstch, srcch; |
89 | 0 | flags = tvb_get_uint8(tvb, 4); |
90 | 0 | offset = 0; |
91 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "TDMoP"); |
92 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
93 | 0 | if (flags & TDMOP_FLAG_LOST_REQUEST) |
94 | 0 | { |
95 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Lost Request"); |
96 | 0 | } |
97 | |
|
98 | 0 | ti = proto_tree_add_item(tree, proto_tdmop, tvb, 0, -1, ENC_NA); |
99 | 0 | tdmop_tree = proto_item_add_subtree(ti, ett_tdmop); |
100 | | /*path info*/ |
101 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_TransferID, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
102 | 0 | offset += 2; |
103 | 0 | proto_tree_add_item_ret_uint(tdmop_tree, hf_tdmop_DstCh, tvb, offset, 1, ENC_LITTLE_ENDIAN, &dstch); |
104 | 0 | offset += 1; |
105 | 0 | proto_tree_add_item_ret_uint(tdmop_tree, hf_tdmop_SrcCh, tvb, offset, 1, ENC_LITTLE_ENDIAN, &srcch); |
106 | 0 | offset += 1; |
107 | | |
108 | | /*conversation*/ |
109 | 0 | conversation_set_conv_addr_port_endpoints(pinfo, &pinfo->src, &pinfo->dst, CONVERSATION_TDMOP, srcch, dstch); |
110 | | |
111 | | /*flags*/ |
112 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_Flags, tvb, offset, 1, ENC_NA); |
113 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_Flags_no_data, tvb, offset, 1, ENC_NA); |
114 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_Flags_lost_request, tvb, offset, 1, ENC_NA); |
115 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_Flags_remote_no_data, tvb, offset, 1, ENC_NA); |
116 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_Flags_compressed, tvb, offset, 1, ENC_NA); |
117 | 0 | offset += 1; |
118 | | /*sequence and delay info*/ |
119 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_SrcDst, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
120 | 0 | offset += 1; |
121 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_SeqNum, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
122 | 0 | offset += 2; |
123 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_LastRecv, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
124 | 0 | offset += 2; |
125 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_Delay, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
126 | 0 | offset += 2; |
127 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_Reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
128 | 0 | offset += 2; |
129 | 0 | if ((flags & TDMOP_FLAG_NO_DATA)==0) |
130 | 0 | { |
131 | 0 | int len; |
132 | 0 | int blockid; |
133 | 0 | dchannel_len=0; |
134 | 0 | len=tvb_captured_length_remaining(tvb, 0); |
135 | 0 | proto_tree_add_item(tdmop_tree, hf_tdmop_payload, tvb, offset, -1, ENC_NA); |
136 | 0 | blockid=0; |
137 | | /*demux TDM stream*/ |
138 | 0 | while (offset<len) |
139 | 0 | { |
140 | 0 | proto_tree *currentblock = proto_tree_add_subtree_format(tdmop_tree, tvb, 0, 0, ett_tdmop_channel, 0, "Block %d", blockid); |
141 | 0 | uint32_t mask; |
142 | 0 | int i; |
143 | 0 | int j; |
144 | 0 | blockid++; |
145 | 0 | mask = pref_tdmop_mask; /*default mask is for timeslots 1-32*/ |
146 | 0 | if (flags&TDMOP_FLAG_COMPRESSED) |
147 | 0 | { |
148 | 0 | mask = tvb_get_letohl(tvb,offset); |
149 | 0 | mask = ((mask >> 16) & 0xFFFF)|((mask & 0xFFFF) << 16); |
150 | 0 | proto_tree_add_uint(currentblock, hf_tdmop_Compression_mask, tvb, offset, 4, mask); |
151 | 0 | offset+=4; |
152 | 0 | } |
153 | 0 | for (i=0; i<32; i++) |
154 | 0 | { |
155 | 0 | if (mask & (1UL<<i)) |
156 | 0 | { |
157 | 0 | proto_tree *subtree; |
158 | 0 | tvbuff_t *cdata; |
159 | 0 | subtree = proto_tree_add_subtree_format(currentblock, tvb, 0, 0, ett_tdmop_channel, 0, "Channel %d", i); |
160 | 0 | cdata = tvb_new_subset_length(tvb, offset, 4); |
161 | 0 | if (i==pref_tdmop_d_channel) |
162 | 0 | { |
163 | 0 | if (dchannel_len + 4 < MAX_DCHANNEL_LEN) |
164 | 0 | { |
165 | 0 | for (j = 0; j < 4; j++) |
166 | 0 | { |
167 | 0 | dchannel_data[dchannel_len+j]=reverse_map[tvb_get_uint8(cdata, j)]; |
168 | 0 | } |
169 | 0 | dchannel_len += 4; |
170 | 0 | } |
171 | 0 | } else |
172 | 0 | { |
173 | 0 | call_data_dissector(cdata, pinfo, subtree); |
174 | 0 | } |
175 | 0 | offset += 4; |
176 | 0 | } |
177 | 0 | } |
178 | 0 | } |
179 | 0 | if (dchannel_len>0) |
180 | 0 | { |
181 | 0 | uint8_t *buff = (uint8_t *)wmem_memdup(pinfo->pool, dchannel_data, dchannel_len); |
182 | 0 | tvbuff_t *new_tvb; |
183 | 0 | new_tvb = tvb_new_child_real_data(tvb, buff, dchannel_len, dchannel_len); |
184 | 0 | call_dissector(lapd_handle, new_tvb, pinfo, tree); |
185 | 0 | } |
186 | 0 | } |
187 | 0 | return tvb_captured_length(tvb); |
188 | 0 | } |
189 | | |
190 | | void proto_register_tdmop(void) |
191 | 14 | { |
192 | 14 | module_t *tdmop_module; |
193 | 14 | static hf_register_info hf[] = |
194 | 14 | { |
195 | 14 | { |
196 | 14 | &hf_tdmop_TransferID, |
197 | 14 | { "TDMoP Transfer ID", "tdmop.transferid", |
198 | 14 | FT_UINT32, BASE_HEX, |
199 | 14 | NULL, 0x0, |
200 | 14 | NULL, HFILL} |
201 | 14 | }, |
202 | 14 | { |
203 | 14 | &hf_tdmop_DstCh, |
204 | 14 | { "TDMoP Dst Ch", "tdmop.dstch", |
205 | 14 | FT_UINT8, BASE_DEC, |
206 | 14 | NULL, 0x0, |
207 | 14 | NULL, HFILL} |
208 | 14 | }, |
209 | 14 | { |
210 | 14 | &hf_tdmop_SrcCh, |
211 | 14 | { "TDMoP Src Ch", "tdmop.srcch", |
212 | 14 | FT_UINT8, BASE_DEC, |
213 | 14 | NULL, 0x0, |
214 | 14 | NULL, HFILL} |
215 | 14 | }, |
216 | 14 | { |
217 | 14 | &hf_tdmop_Flags, |
218 | 14 | { "TDMoP Flags", "tdmop.flags", |
219 | 14 | FT_UINT8, BASE_DEC, |
220 | 14 | NULL, 0x0, |
221 | 14 | NULL, HFILL} |
222 | 14 | }, |
223 | 14 | { |
224 | 14 | &hf_tdmop_Flags_lost_request, |
225 | 14 | { "TDMoP Lost Request Flag", "tdmop.flags.lostrequest", |
226 | 14 | FT_BOOLEAN, 8, |
227 | 14 | NULL, TDMOP_FLAG_LOST_REQUEST, |
228 | 14 | NULL, HFILL} |
229 | 14 | }, |
230 | 14 | { |
231 | 14 | &hf_tdmop_Flags_no_data, |
232 | 14 | { "TDMoP No data flag", "tdmop.flags.nodata", |
233 | 14 | FT_BOOLEAN, 8, |
234 | 14 | NULL, TDMOP_FLAG_NO_DATA, |
235 | 14 | NULL, HFILL} |
236 | 14 | }, |
237 | 14 | { |
238 | 14 | &hf_tdmop_Flags_remote_no_data, |
239 | 14 | { "TDMoP No data received from remote side flag", "tdmop.flags.remotenodata", |
240 | 14 | FT_BOOLEAN, 8, |
241 | 14 | NULL, TDMOP_FLAG_REMOTE_NO_DATA, |
242 | 14 | NULL, HFILL} |
243 | 14 | }, |
244 | 14 | { |
245 | 14 | &hf_tdmop_Flags_compressed, |
246 | 14 | { "TDMoP compressed framed", "tdmop.flags.compressed", |
247 | 14 | FT_BOOLEAN, 8, |
248 | 14 | NULL, TDMOP_FLAG_COMPRESSED, |
249 | 14 | NULL, HFILL} |
250 | 14 | }, |
251 | 14 | { |
252 | 14 | &hf_tdmop_SrcDst, |
253 | 14 | { "TDMoP Short SrcDst", "tdmop.srcdst", |
254 | 14 | FT_UINT8, BASE_HEX, |
255 | 14 | NULL, 0x0, |
256 | 14 | NULL, HFILL} |
257 | 14 | }, |
258 | 14 | { |
259 | 14 | &hf_tdmop_SeqNum, |
260 | 14 | { "TDMoP Sequence number", "tdmop.seqnum", |
261 | 14 | FT_UINT16, BASE_DEC, |
262 | 14 | NULL, 0x0, |
263 | 14 | NULL, HFILL} |
264 | 14 | }, |
265 | 14 | { |
266 | 14 | &hf_tdmop_LastRecv, |
267 | 14 | { "TDMoP Last Received number", "tdmop.recvnumber", |
268 | 14 | FT_UINT16, BASE_DEC, |
269 | 14 | NULL, 0x0, |
270 | 14 | NULL, HFILL} |
271 | 14 | }, |
272 | 14 | { |
273 | 14 | &hf_tdmop_Delay, |
274 | 14 | { "TDMoP Delay", "tdmop.delay", |
275 | 14 | FT_UINT16, BASE_DEC, |
276 | 14 | NULL, 0x0, |
277 | 14 | NULL, HFILL} |
278 | 14 | }, |
279 | 14 | { |
280 | 14 | &hf_tdmop_Reserved, |
281 | 14 | { "TDMoP Reserved", "tdmop.reserved", |
282 | 14 | FT_UINT16, BASE_DEC, |
283 | 14 | NULL, 0x0, |
284 | 14 | NULL, HFILL} |
285 | 14 | }, |
286 | 14 | { |
287 | 14 | &hf_tdmop_payload, |
288 | 14 | { "TDMoP Payload", "tdmop.payload", |
289 | 14 | FT_BYTES, BASE_NONE, |
290 | 14 | NULL, 0x0, |
291 | 14 | NULL, HFILL} |
292 | 14 | }, |
293 | 14 | { |
294 | 14 | &hf_tdmop_Compression_mask, |
295 | 14 | { "TDMoP Compression mask", "tdmop.cmask", |
296 | 14 | FT_UINT32, BASE_HEX, |
297 | 14 | NULL, 0x0, |
298 | 14 | NULL, HFILL} |
299 | 14 | } |
300 | 14 | }; |
301 | 14 | static int *ett[] = { |
302 | 14 | &ett_tdmop, |
303 | 14 | &ett_tdmop_channel |
304 | 14 | }; |
305 | 14 | proto_tdmop = proto_register_protocol ("TDMoP protocol", "TDMoP", "tdmop"); |
306 | 14 | proto_register_field_array(proto_tdmop, hf, array_length(hf)); |
307 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
308 | 14 | tdmop_handle = register_dissector("tdmop", dissect_tdmop, proto_tdmop); |
309 | 14 | tdmop_module = prefs_register_protocol(proto_tdmop, proto_reg_handoff_tdmop); |
310 | 14 | prefs_register_uint_preference(tdmop_module, "d_channel", |
311 | 14 | "TDMoP D-Channel", |
312 | 14 | "The TDMoD channel that contains the D-Channel.", |
313 | 14 | 10, &pref_tdmop_d_channel); |
314 | 14 | prefs_register_uint_preference(tdmop_module, "ts_mask", |
315 | 14 | "TDMoP default timeslot mask", |
316 | 14 | "The bitmask of channels in uncompressed TDMoP frame", |
317 | 14 | 16, &pref_tdmop_mask); |
318 | 14 | prefs_register_uint_preference(tdmop_module, "ethertype", |
319 | 14 | "Ethertype for TDMoP stream(Usually 0808)", |
320 | 14 | "The ethertype assigned to TDMoP (without IP/UDP) stream", |
321 | 14 | 16, &pref_tdmop_ethertype); |
322 | 14 | } |
323 | | |
324 | | void proto_reg_handoff_tdmop(void) |
325 | 14 | { |
326 | 14 | static bool init = false; |
327 | 14 | static uint32_t current_tdmop_ethertype; |
328 | 14 | if (!init) |
329 | 14 | { |
330 | 14 | dissector_add_for_decode_as_with_preference("udp.port", tdmop_handle); |
331 | | |
332 | 14 | if (pref_tdmop_ethertype) { |
333 | 0 | dissector_add_uint("ethertype", pref_tdmop_ethertype, tdmop_handle); |
334 | 0 | } |
335 | 14 | lapd_handle = find_dissector_add_dependency("lapd-bitstream", proto_tdmop); |
336 | 14 | current_tdmop_ethertype = pref_tdmop_ethertype; |
337 | 14 | init = true; |
338 | 14 | } |
339 | 14 | if (current_tdmop_ethertype != pref_tdmop_ethertype) |
340 | 0 | { |
341 | 0 | dissector_delete_uint("ethertype", current_tdmop_ethertype, tdmop_handle); |
342 | 0 | if (pref_tdmop_ethertype) { |
343 | 0 | dissector_add_uint("ethertype", pref_tdmop_ethertype, tdmop_handle); |
344 | 0 | } |
345 | 0 | current_tdmop_ethertype = pref_tdmop_ethertype; |
346 | 0 | } |
347 | 14 | } |
348 | | |
349 | | /* |
350 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
351 | | * |
352 | | * Local variables: |
353 | | * c-basic-offset: 4 |
354 | | * tab-width: 8 |
355 | | * indent-tabs-mode: nil |
356 | | * End: |
357 | | * |
358 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
359 | | * :indentSize=4:tabSize=8:noTabs=true: |
360 | | */ |