/src/wireshark/epan/dissectors/packet-uts.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-uts.c |
2 | | * Routines for UTS WAN protocol dissection |
3 | | * Copyright 2007, Fulko Hew, SITA INC Canada, Inc. |
4 | | * |
5 | | * Copied from packet-ipars.c |
6 | | * |
7 | | * Wireshark - Network traffic analyzer |
8 | | * By Gerald Combs <gerald@wireshark.org> |
9 | | * Copyright 1998 Gerald Combs |
10 | | * |
11 | | * SPDX-License-Identifier: GPL-2.0-or-later |
12 | | */ |
13 | | |
14 | | /* Use tabstops = 4 */ |
15 | | |
16 | | #include "config.h" |
17 | | |
18 | | #include <epan/packet.h> |
19 | | #include <wiretap/wtap.h> |
20 | | #include <wsutil/str_util.h> |
21 | | |
22 | 0 | #define SOH (0x01) |
23 | 0 | #define STX (0x02) |
24 | 0 | #define ETX (0x03) |
25 | 0 | #define EOT (0x04) |
26 | 0 | #define ENQ (0x05) |
27 | 0 | #define BEL (0x07) |
28 | 0 | #define NAK (0x15) |
29 | 0 | #define DLE (0x10) |
30 | | |
31 | 0 | #define GRID (0x20) |
32 | 0 | #define GSID (0x50) |
33 | 0 | #define GDID (0x70) |
34 | | |
35 | | #define MAX_POLL_TYPE_MSG_SIZE (50) |
36 | | |
37 | | void proto_register_uts(void); |
38 | | |
39 | | static int proto_uts; |
40 | | static int ett_uts; |
41 | | static int ett_header_uts; |
42 | | static int ett_trailer_uts; |
43 | | static int hf_rid; |
44 | | static int hf_sid; |
45 | | static int hf_did; |
46 | | static int hf_retxrequest; |
47 | | static int hf_ack; |
48 | | static int hf_replyrequest; |
49 | | static int hf_busy; |
50 | | static int hf_notbusy; |
51 | | static int hf_msgwaiting; |
52 | | static int hf_function; |
53 | | static int hf_data; |
54 | | |
55 | 0 | #define MATCH (1) |
56 | 0 | #define FETCH (2) |
57 | | |
58 | 0 | #define SRC (1) |
59 | 0 | #define DST (2) |
60 | | |
61 | | static int testchar(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, int op, char match, char *storage) |
62 | 0 | { |
63 | 0 | char temp; |
64 | |
|
65 | 0 | if (tvb_bytes_exist(tvb, offset, 1)) { |
66 | 0 | temp = tvb_get_uint8(tvb, offset) & 0x7f; |
67 | 0 | if (op == FETCH || (op == MATCH && temp == match)) { |
68 | 0 | if (storage != NULL) |
69 | 0 | *storage = temp; |
70 | 0 | return 1; |
71 | 0 | } else { |
72 | 0 | return 0; |
73 | 0 | } |
74 | 0 | } else { |
75 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Unknown Message Format"); |
76 | 0 | return 0; |
77 | 0 | } |
78 | 0 | } |
79 | | |
80 | | static void |
81 | | set_addr(packet_info *pinfo _U_ , int field, char rid, char sid, char did) |
82 | 0 | { |
83 | 0 | if (field == SRC) { |
84 | 0 | col_append_fstr(pinfo->cinfo, COL_DEF_SRC, " %2.2X:%2.2X:%2.2X", rid, sid, did); |
85 | 0 | } else { |
86 | 0 | col_append_fstr(pinfo->cinfo, COL_DEF_DST, " %2.2X:%2.2X:%2.2X", rid, sid, did); |
87 | 0 | } |
88 | 0 | } |
89 | | |
90 | | static int |
91 | | dissect_uts(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree, void* data _U_) |
92 | 0 | { |
93 | 0 | proto_tree *uts_tree = NULL; |
94 | 0 | proto_tree *uts_header_tree = NULL; |
95 | 0 | proto_tree *uts_trailer_tree = NULL; |
96 | 0 | proto_item *ti; |
97 | 0 | int length; |
98 | 0 | char rid = 0, sid = 0, did = 0; |
99 | 0 | int offset = 0; |
100 | 0 | int header_length = -1; |
101 | 0 | int ack_start = 0; |
102 | 0 | int busy_start = 0; |
103 | 0 | int notbusy_start = 0; |
104 | 0 | int replyrequest_start = 0; |
105 | 0 | int function_start = 0; |
106 | 0 | int msgwaiting_start = 0; |
107 | 0 | int nak_start = 0; |
108 | 0 | int etx_start = 0; |
109 | 0 | int bcc_start = 0; |
110 | 0 | int stx_start = 0; |
111 | 0 | char function_code; |
112 | 0 | uint8_t *data_ptr; |
113 | |
|
114 | 0 | enum { NOTRAFFIC, OTHER } msg_type = OTHER; |
115 | |
|
116 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "UTS"); |
117 | |
|
118 | 0 | if (testchar(tvb, pinfo, 0, MATCH, EOT, NULL) && |
119 | 0 | testchar(tvb, pinfo, 1, MATCH, EOT, NULL) && |
120 | 0 | testchar(tvb, pinfo, 2, MATCH, ETX, NULL)) { |
121 | 0 | msg_type = NOTRAFFIC; |
122 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "No Traffic"); |
123 | 0 | } else { |
124 | 0 | if (testchar(tvb, pinfo, 0, MATCH, SOH, NULL) && |
125 | 0 | testchar(tvb, pinfo, 1, FETCH, 0, (char *)&rid) && |
126 | 0 | testchar(tvb, pinfo, 2, FETCH, 0, (char *)&sid) && |
127 | 0 | testchar(tvb, pinfo, 3, FETCH, 0, (char *)&did)) { |
128 | 0 | offset = 4; |
129 | 0 | if (testchar(tvb, pinfo, offset, MATCH, ETX, NULL)) { |
130 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "General Poll"); |
131 | 0 | set_addr(pinfo, DST, rid, sid, did); |
132 | 0 | } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) && |
133 | 0 | testchar(tvb, pinfo, offset+1, MATCH, '1', NULL) && |
134 | 0 | testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) { |
135 | 0 | ack_start = offset; |
136 | 0 | if (sid == GSID && did == GDID) { |
137 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "General Poll + ACK"); |
138 | 0 | set_addr(pinfo, DST, rid, sid, did); |
139 | 0 | } else if (sid != GSID && did == GDID) { |
140 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Specific Poll + ACK"); |
141 | 0 | set_addr(pinfo, DST, rid, sid, did); |
142 | 0 | } else if (sid != GSID && did != GDID) { |
143 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "No Traffic + ACK"); |
144 | 0 | set_addr(pinfo, SRC, rid, sid, did); |
145 | 0 | } else { |
146 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Unknown Message Format"); |
147 | 0 | if ((pinfo->pseudo_header->sita.sita_flags & SITA_FRAME_DIR) == SITA_FRAME_DIR_TXED) { |
148 | 0 | set_addr(pinfo, DST, rid, sid, did); /* if the ACN sent it, the address is of the destination... the terminal */ |
149 | 0 | } else { |
150 | 0 | set_addr(pinfo, SRC, rid, sid, did); /* if the ACN received it, the address if of the source... the terminal */ |
151 | 0 | } |
152 | 0 | } |
153 | 0 | } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) && |
154 | 0 | testchar(tvb, pinfo, offset+1, MATCH, NAK, NULL) && |
155 | 0 | testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL) && |
156 | 0 | sid != GSID && did == GDID) { |
157 | 0 | nak_start = offset; |
158 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Retransmit Request"); |
159 | 0 | set_addr(pinfo, DST, rid, sid, did); |
160 | 0 | } else if (testchar(tvb, pinfo, offset, MATCH, BEL, NULL) && |
161 | 0 | testchar(tvb, pinfo, offset+1, MATCH, STX, NULL) && |
162 | 0 | testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) { |
163 | 0 | header_length = offset+2; |
164 | 0 | msgwaiting_start = offset; |
165 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Message Waiting"); |
166 | 0 | set_addr(pinfo, DST, rid, sid, did); |
167 | 0 | } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) && |
168 | 0 | testchar(tvb, pinfo, offset+1, MATCH, '1', NULL) && |
169 | 0 | testchar(tvb, pinfo, offset+2, MATCH, STX, NULL)) { |
170 | 0 | ack_start = offset; |
171 | 0 | header_length = offset+3; |
172 | 0 | stx_start = offset+2; |
173 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Text + ACK"); |
174 | 0 | set_addr(pinfo, SRC, rid, sid, did); |
175 | 0 | } else if (testchar(tvb, pinfo, offset, MATCH, STX, NULL)) { |
176 | 0 | header_length = offset+1; |
177 | 0 | stx_start = offset; |
178 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Text"); |
179 | 0 | if ((pinfo->pseudo_header->sita.sita_flags & SITA_FRAME_DIR) == SITA_FRAME_DIR_TXED) { |
180 | 0 | set_addr(pinfo, DST, rid, sid, did); /* if the ACN sent it, the address is of the destination... the terminal */ |
181 | 0 | } else { |
182 | 0 | set_addr(pinfo, SRC, rid, sid, did); /* if the ACN received it, the address if of the source... the terminal */ |
183 | 0 | } |
184 | 0 | } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) && |
185 | 0 | testchar(tvb, pinfo, offset+1, MATCH, ENQ, NULL) && |
186 | 0 | testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) { |
187 | 0 | replyrequest_start = offset; |
188 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Reply Request"); |
189 | 0 | set_addr(pinfo, SRC, rid, sid, did); |
190 | 0 | } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) && |
191 | 0 | testchar(tvb, pinfo, offset+1, MATCH, '?', NULL) && |
192 | 0 | testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) { |
193 | 0 | busy_start = offset; |
194 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Busy"); |
195 | 0 | set_addr(pinfo, SRC, rid, sid, did); |
196 | 0 | } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) && |
197 | 0 | testchar(tvb, pinfo, offset+1, MATCH, ';', NULL) && |
198 | 0 | testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) { |
199 | 0 | notbusy_start = offset; |
200 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Not Busy"); |
201 | 0 | set_addr(pinfo, SRC, rid, sid, did); |
202 | 0 | } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) && |
203 | 0 | testchar(tvb, pinfo, offset+1, MATCH, '1', NULL) && |
204 | 0 | testchar(tvb, pinfo, offset+2, MATCH, DLE, NULL) && |
205 | 0 | testchar(tvb, pinfo, offset+3, MATCH, ';', NULL) && |
206 | 0 | testchar(tvb, pinfo, offset+4, MATCH, ETX, NULL)) { |
207 | 0 | notbusy_start = offset+2; |
208 | 0 | ack_start = offset; |
209 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Not Busy + ACK"); |
210 | 0 | set_addr(pinfo, SRC, rid, sid, did); |
211 | 0 | } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) && |
212 | 0 | testchar(tvb, pinfo, offset+1, MATCH, '1', NULL) && |
213 | 0 | testchar(tvb, pinfo, offset+2, FETCH, 0, &function_code) && |
214 | 0 | testchar(tvb, pinfo, offset+3, MATCH, ETX, NULL)) { |
215 | 0 | ack_start = offset; |
216 | 0 | function_start = offset + 2; |
217 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, "Function Message '%c' + ACK", function_code); |
218 | 0 | set_addr(pinfo, SRC, rid, sid, did); |
219 | 0 | } else if (testchar(tvb, pinfo, offset, FETCH, 0, &function_code) && |
220 | 0 | testchar(tvb, pinfo, offset+1, MATCH, ETX, NULL)) { |
221 | 0 | function_start = offset; |
222 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, "Function Message '%c'", function_code); |
223 | 0 | set_addr(pinfo, SRC, rid, sid, did); |
224 | 0 | } |
225 | 0 | } |
226 | 0 | } |
227 | |
|
228 | 0 | while (tvb_reported_length_remaining(tvb, offset) > 0) { /* now look for the ETX */ |
229 | 0 | if ((tvb_get_uint8(tvb, offset) & 0x7f) == ETX) { |
230 | 0 | if (header_length == -1) |
231 | 0 | header_length = offset; /* the header ends at an STX, or if not found, the ETX */ |
232 | 0 | etx_start = offset; |
233 | 0 | offset++; |
234 | 0 | break; |
235 | 0 | } |
236 | 0 | offset++; |
237 | 0 | } |
238 | 0 | if (tvb_reported_length_remaining(tvb, offset)) /* if there is anything left, it could be the BCC and pads */ |
239 | 0 | bcc_start = offset; |
240 | |
|
241 | 0 | if (tree) { |
242 | 0 | ti = proto_tree_add_protocol_format(tree, proto_uts, tvb, 0, -1, "UTS"); |
243 | 0 | uts_tree = proto_item_add_subtree(ti, ett_uts); |
244 | |
|
245 | 0 | if (msg_type == NOTRAFFIC) { |
246 | 0 | proto_tree_add_protocol_format(uts_tree, proto_uts, tvb, 0, 2, "No Traffic"); |
247 | 0 | proto_tree_add_protocol_format(uts_tree, proto_uts, tvb, 2, -1, "ETX + padding"); |
248 | 0 | } else { |
249 | 0 | uts_header_tree = proto_tree_add_subtree(uts_tree, tvb, 0, header_length, ett_header_uts, NULL, "Header"); |
250 | |
|
251 | 0 | proto_tree_add_protocol_format(uts_header_tree, proto_uts, tvb, 0, 1, "SOH"); |
252 | |
|
253 | 0 | if (rid == GRID) |
254 | 0 | proto_tree_add_uint_format(uts_header_tree, hf_rid, tvb, 1, 1, rid, "RID (%02X) (General)", rid); |
255 | 0 | else |
256 | 0 | proto_tree_add_uint_format(uts_header_tree, hf_rid, tvb, 1, 1, rid, "RID (%02X)", rid); |
257 | |
|
258 | 0 | if (sid == GSID) |
259 | 0 | proto_tree_add_uint_format(uts_header_tree, hf_sid, tvb, 2, 1, sid, "SID (%02X) (General)", sid); |
260 | 0 | else |
261 | 0 | proto_tree_add_uint_format(uts_header_tree, hf_sid, tvb, 2, 1, sid, "SID (%02X)", sid); |
262 | |
|
263 | 0 | if (did == GDID) |
264 | 0 | proto_tree_add_uint_format(uts_header_tree, hf_did, tvb, 3, 1, did, "DID (%02X) (General)", did); |
265 | 0 | else |
266 | 0 | proto_tree_add_uint_format(uts_header_tree, hf_did, tvb, 3, 1, did, "DID (%02X)", did); |
267 | |
|
268 | 0 | if (nak_start) |
269 | 0 | proto_tree_add_boolean_format(uts_header_tree, hf_retxrequest, tvb, nak_start, 2, 1, "Re-transmit Request"); |
270 | 0 | if (ack_start) |
271 | 0 | proto_tree_add_boolean_format(uts_header_tree, hf_ack, tvb, ack_start, 2, 1, "Ack"); |
272 | |
|
273 | 0 | if (replyrequest_start) |
274 | 0 | proto_tree_add_boolean_format(uts_header_tree, hf_replyrequest, tvb, replyrequest_start, 2, 1, "Reply Request"); |
275 | 0 | if (busy_start) |
276 | 0 | proto_tree_add_boolean_format(uts_header_tree, hf_busy, tvb, busy_start, 2, 1, "Busy"); |
277 | |
|
278 | 0 | if (notbusy_start) |
279 | 0 | proto_tree_add_boolean_format(uts_header_tree, hf_notbusy, tvb, notbusy_start, 2, 1, "Not Busy"); |
280 | |
|
281 | 0 | if (msgwaiting_start) |
282 | 0 | proto_tree_add_boolean_format(uts_header_tree, hf_msgwaiting, tvb, msgwaiting_start, 1, 1, "Message Waiting"); |
283 | |
|
284 | 0 | if (function_start) |
285 | 0 | proto_tree_add_uint_format(uts_header_tree, hf_function, tvb, function_start, 1, function_code, "Function '%c'", function_code ); |
286 | |
|
287 | 0 | if (stx_start) { |
288 | 0 | proto_tree_add_protocol_format(uts_header_tree, proto_uts, tvb, stx_start, 1, "Start of Text"); |
289 | 0 | length = tvb_captured_length_remaining(tvb, stx_start+1); /* find out how much message remains */ |
290 | 0 | if (etx_start) |
291 | 0 | length = (etx_start - stx_start - 1); /* and the data part is the rest... */ |
292 | | /* whatever precedes the ETX if it exists */ |
293 | 0 | data_ptr = tvb_get_string_enc(pinfo->pool, tvb, stx_start+1, length, ENC_ASCII); /* copy the string for dissecting */ |
294 | 0 | proto_tree_add_string_format(uts_tree, hf_data, tvb, stx_start + 1, length, data_ptr, |
295 | 0 | "Text (%d byte%s)", length, plurality(length, "", "s")); |
296 | 0 | } |
297 | |
|
298 | 0 | if (etx_start) { |
299 | 0 | uts_trailer_tree = proto_tree_add_subtree(uts_tree, tvb, etx_start, -1, ett_trailer_uts, NULL, "Trailer"); |
300 | |
|
301 | 0 | if (etx_start) |
302 | 0 | proto_tree_add_protocol_format(uts_trailer_tree, proto_uts, tvb, etx_start, 1, "ETX"); |
303 | 0 | if (bcc_start) |
304 | 0 | proto_tree_add_protocol_format(uts_trailer_tree, proto_uts, tvb, bcc_start, -1, "CCC + padding"); |
305 | 0 | } |
306 | 0 | } |
307 | 0 | } |
308 | 0 | return tvb_captured_length(tvb); |
309 | 0 | } |
310 | | |
311 | | void |
312 | | proto_register_uts(void) |
313 | 14 | { |
314 | 14 | static hf_register_info hf[] = { |
315 | 14 | { &hf_rid, |
316 | 14 | { "RID", "uts.rid", |
317 | 14 | FT_UINT8, BASE_HEX, NULL, 0, "Remote Identifier address", HFILL }}, |
318 | 14 | { &hf_sid, |
319 | 14 | { "SID", "uts.sid", |
320 | 14 | FT_UINT8, BASE_HEX, NULL, 0, "Site Identifier address", HFILL }}, |
321 | 14 | { &hf_did, |
322 | 14 | { "DID", "uts.did", |
323 | 14 | FT_UINT8, BASE_HEX, NULL, 0, "Device Identifier address", HFILL }}, |
324 | 14 | { &hf_retxrequest, |
325 | 14 | { "ReTxRequest", "uts.retxrequest", |
326 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, "true if Re-transmit Request", HFILL }}, |
327 | 14 | { &hf_ack, |
328 | 14 | { "Ack", "uts.ack", |
329 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, "true if Ack", HFILL }}, |
330 | 14 | { &hf_replyrequest, |
331 | 14 | { "ReplyRequest", "uts.replyrequest", |
332 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, "true if Reply Request", HFILL }}, |
333 | 14 | { &hf_busy, |
334 | 14 | { "Busy", "uts.busy", |
335 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, "true if Busy", HFILL }}, |
336 | 14 | { &hf_notbusy, |
337 | 14 | { "NotBusy", "uts.notbusy", |
338 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, "true if Not Busy", HFILL }}, |
339 | 14 | { &hf_msgwaiting, |
340 | 14 | { "MsgWaiting", "uts.msgwaiting", |
341 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, "true if Message Waiting", HFILL }}, |
342 | 14 | { &hf_function, |
343 | 14 | { "Function", "uts.function", |
344 | 14 | FT_UINT8, BASE_HEX, NULL, 0, "Function Code value", HFILL }}, |
345 | 14 | { &hf_data, |
346 | 14 | { "Data", "uts.data", |
347 | 14 | FT_STRING, BASE_NONE, NULL, 0, "User Data Message", HFILL }}, |
348 | 14 | }; |
349 | | |
350 | 14 | static int *ett[] = { |
351 | 14 | &ett_uts, |
352 | 14 | &ett_header_uts, |
353 | 14 | &ett_trailer_uts, |
354 | 14 | }; |
355 | | |
356 | 14 | proto_uts = proto_register_protocol("Unisys Transmittal System", "UTS", "uts"); /* name, short name, abbrev */ |
357 | 14 | proto_register_field_array(proto_uts, hf, array_length(hf)); |
358 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
359 | 14 | register_dissector("uts", dissect_uts, proto_uts); |
360 | 14 | } |
361 | | |
362 | | /* |
363 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
364 | | * |
365 | | * Local variables: |
366 | | * c-basic-offset: 8 |
367 | | * tab-width: 8 |
368 | | * indent-tabs-mode: t |
369 | | * End: |
370 | | * |
371 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
372 | | * :indentSize=8:tabSize=8:noTabs=false: |
373 | | */ |