2 * Routines for UTS WAN protocol dissection
3 * Copyright 2007, Fulko Hew, SITA INC Canada, Inc.
5 * Copied from packet-ipars.c
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 /* Use tabstops = 4 */
18 #include <epan/packet.h>
19 #include <wiretap/wtap.h>
20 #include <wsutil/str_util.h>
35 #define MAX_POLL_TYPE_MSG_SIZE (50)
37 void proto_register_uts(void);
41 static int ett_header_uts
;
42 static int ett_trailer_uts
;
46 static int hf_retxrequest
;
48 static int hf_replyrequest
;
50 static int hf_notbusy
;
51 static int hf_msgwaiting
;
52 static int hf_function
;
61 static int testchar(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, int offset
, int op
, char match
, char *storage
)
65 if (tvb_bytes_exist(tvb
, offset
, 1)) {
66 temp
= tvb_get_uint8(tvb
, offset
) & 0x7f;
67 if (op
== FETCH
|| (op
== MATCH
&& temp
== match
)) {
75 col_set_str(pinfo
->cinfo
, COL_INFO
, "Unknown Message Format");
81 set_addr(packet_info
*pinfo _U_
, int field
, char rid
, char sid
, char did
)
84 col_append_fstr(pinfo
->cinfo
, COL_DEF_SRC
, " %2.2X:%2.2X:%2.2X", rid
, sid
, did
);
86 col_append_fstr(pinfo
->cinfo
, COL_DEF_DST
, " %2.2X:%2.2X:%2.2X", rid
, sid
, did
);
91 dissect_uts(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void* data _U_
)
93 proto_tree
*uts_tree
= NULL
;
94 proto_tree
*uts_header_tree
= NULL
;
95 proto_tree
*uts_trailer_tree
= NULL
;
98 char rid
= 0, sid
= 0, did
= 0;
100 int header_length
= -1;
103 int notbusy_start
= 0;
104 int replyrequest_start
= 0;
105 int function_start
= 0;
106 int msgwaiting_start
= 0;
114 enum { NOTRAFFIC
, OTHER
} msg_type
= OTHER
;
116 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "UTS");
118 if (testchar(tvb
, pinfo
, 0, MATCH
, EOT
, NULL
) &&
119 testchar(tvb
, pinfo
, 1, MATCH
, EOT
, NULL
) &&
120 testchar(tvb
, pinfo
, 2, MATCH
, ETX
, NULL
)) {
121 msg_type
= NOTRAFFIC
;
122 col_set_str(pinfo
->cinfo
, COL_INFO
, "No Traffic");
124 if (testchar(tvb
, pinfo
, 0, MATCH
, SOH
, NULL
) &&
125 testchar(tvb
, pinfo
, 1, FETCH
, 0, (char *)&rid
) &&
126 testchar(tvb
, pinfo
, 2, FETCH
, 0, (char *)&sid
) &&
127 testchar(tvb
, pinfo
, 3, FETCH
, 0, (char *)&did
)) {
129 if (testchar(tvb
, pinfo
, offset
, MATCH
, ETX
, NULL
)) {
130 col_set_str(pinfo
->cinfo
, COL_INFO
, "General Poll");
131 set_addr(pinfo
, DST
, rid
, sid
, did
);
132 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
133 testchar(tvb
, pinfo
, offset
+1, MATCH
, '1', NULL
) &&
134 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
)) {
136 if (sid
== GSID
&& did
== GDID
) {
137 col_set_str(pinfo
->cinfo
, COL_INFO
, "General Poll + ACK");
138 set_addr(pinfo
, DST
, rid
, sid
, did
);
139 } else if (sid
!= GSID
&& did
== GDID
) {
140 col_set_str(pinfo
->cinfo
, COL_INFO
, "Specific Poll + ACK");
141 set_addr(pinfo
, DST
, rid
, sid
, did
);
142 } else if (sid
!= GSID
&& did
!= GDID
) {
143 col_set_str(pinfo
->cinfo
, COL_INFO
, "No Traffic + ACK");
144 set_addr(pinfo
, SRC
, rid
, sid
, did
);
146 col_set_str(pinfo
->cinfo
, COL_INFO
, "Unknown Message Format");
147 if ((pinfo
->pseudo_header
->sita
.sita_flags
& SITA_FRAME_DIR
) == SITA_FRAME_DIR_TXED
) {
148 set_addr(pinfo
, DST
, rid
, sid
, did
); /* if the ACN sent it, the address is of the destination... the terminal */
150 set_addr(pinfo
, SRC
, rid
, sid
, did
); /* if the ACN received it, the address if of the source... the terminal */
153 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
154 testchar(tvb
, pinfo
, offset
+1, MATCH
, NAK
, NULL
) &&
155 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
) &&
156 sid
!= GSID
&& did
== GDID
) {
158 col_set_str(pinfo
->cinfo
, COL_INFO
, "Retransmit Request");
159 set_addr(pinfo
, DST
, rid
, sid
, did
);
160 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, BEL
, NULL
) &&
161 testchar(tvb
, pinfo
, offset
+1, MATCH
, STX
, NULL
) &&
162 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
)) {
163 header_length
= offset
+2;
164 msgwaiting_start
= offset
;
165 col_set_str(pinfo
->cinfo
, COL_INFO
, "Message Waiting");
166 set_addr(pinfo
, DST
, rid
, sid
, did
);
167 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
168 testchar(tvb
, pinfo
, offset
+1, MATCH
, '1', NULL
) &&
169 testchar(tvb
, pinfo
, offset
+2, MATCH
, STX
, NULL
)) {
171 header_length
= offset
+3;
172 stx_start
= offset
+2;
173 col_set_str(pinfo
->cinfo
, COL_INFO
, "Text + ACK");
174 set_addr(pinfo
, SRC
, rid
, sid
, did
);
175 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, STX
, NULL
)) {
176 header_length
= offset
+1;
178 col_set_str(pinfo
->cinfo
, COL_INFO
, "Text");
179 if ((pinfo
->pseudo_header
->sita
.sita_flags
& SITA_FRAME_DIR
) == SITA_FRAME_DIR_TXED
) {
180 set_addr(pinfo
, DST
, rid
, sid
, did
); /* if the ACN sent it, the address is of the destination... the terminal */
182 set_addr(pinfo
, SRC
, rid
, sid
, did
); /* if the ACN received it, the address if of the source... the terminal */
184 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
185 testchar(tvb
, pinfo
, offset
+1, MATCH
, ENQ
, NULL
) &&
186 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
)) {
187 replyrequest_start
= offset
;
188 col_set_str(pinfo
->cinfo
, COL_INFO
, "Reply Request");
189 set_addr(pinfo
, SRC
, rid
, sid
, did
);
190 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
191 testchar(tvb
, pinfo
, offset
+1, MATCH
, '?', NULL
) &&
192 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
)) {
194 col_set_str(pinfo
->cinfo
, COL_INFO
, "Busy");
195 set_addr(pinfo
, SRC
, rid
, sid
, did
);
196 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
197 testchar(tvb
, pinfo
, offset
+1, MATCH
, ';', NULL
) &&
198 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
)) {
199 notbusy_start
= offset
;
200 col_set_str(pinfo
->cinfo
, COL_INFO
, "Not Busy");
201 set_addr(pinfo
, SRC
, rid
, sid
, did
);
202 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
203 testchar(tvb
, pinfo
, offset
+1, MATCH
, '1', NULL
) &&
204 testchar(tvb
, pinfo
, offset
+2, MATCH
, DLE
, NULL
) &&
205 testchar(tvb
, pinfo
, offset
+3, MATCH
, ';', NULL
) &&
206 testchar(tvb
, pinfo
, offset
+4, MATCH
, ETX
, NULL
)) {
207 notbusy_start
= offset
+2;
209 col_set_str(pinfo
->cinfo
, COL_INFO
, "Not Busy + ACK");
210 set_addr(pinfo
, SRC
, rid
, sid
, did
);
211 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
212 testchar(tvb
, pinfo
, offset
+1, MATCH
, '1', NULL
) &&
213 testchar(tvb
, pinfo
, offset
+2, FETCH
, 0, &function_code
) &&
214 testchar(tvb
, pinfo
, offset
+3, MATCH
, ETX
, NULL
)) {
216 function_start
= offset
+ 2;
217 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Function Message '%c' + ACK", function_code
);
218 set_addr(pinfo
, SRC
, rid
, sid
, did
);
219 } else if (testchar(tvb
, pinfo
, offset
, FETCH
, 0, &function_code
) &&
220 testchar(tvb
, pinfo
, offset
+1, MATCH
, ETX
, NULL
)) {
221 function_start
= offset
;
222 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Function Message '%c'", function_code
);
223 set_addr(pinfo
, SRC
, rid
, sid
, did
);
228 while (tvb_reported_length_remaining(tvb
, offset
) > 0) { /* now look for the ETX */
229 if ((tvb_get_uint8(tvb
, offset
) & 0x7f) == ETX
) {
230 if (header_length
== -1)
231 header_length
= offset
; /* the header ends at an STX, or if not found, the ETX */
238 if (tvb_reported_length_remaining(tvb
, offset
)) /* if there is anything left, it could be the BCC and pads */
242 ti
= proto_tree_add_protocol_format(tree
, proto_uts
, tvb
, 0, -1, "UTS");
243 uts_tree
= proto_item_add_subtree(ti
, ett_uts
);
245 if (msg_type
== NOTRAFFIC
) {
246 proto_tree_add_protocol_format(uts_tree
, proto_uts
, tvb
, 0, 2, "No Traffic");
247 proto_tree_add_protocol_format(uts_tree
, proto_uts
, tvb
, 2, -1, "ETX + padding");
249 uts_header_tree
= proto_tree_add_subtree(uts_tree
, tvb
, 0, header_length
, ett_header_uts
, NULL
, "Header");
251 proto_tree_add_protocol_format(uts_header_tree
, proto_uts
, tvb
, 0, 1, "SOH");
254 proto_tree_add_uint_format(uts_header_tree
, hf_rid
, tvb
, 1, 1, rid
, "RID (%02X) (General)", rid
);
256 proto_tree_add_uint_format(uts_header_tree
, hf_rid
, tvb
, 1, 1, rid
, "RID (%02X)", rid
);
259 proto_tree_add_uint_format(uts_header_tree
, hf_sid
, tvb
, 2, 1, sid
, "SID (%02X) (General)", sid
);
261 proto_tree_add_uint_format(uts_header_tree
, hf_sid
, tvb
, 2, 1, sid
, "SID (%02X)", sid
);
264 proto_tree_add_uint_format(uts_header_tree
, hf_did
, tvb
, 3, 1, did
, "DID (%02X) (General)", did
);
266 proto_tree_add_uint_format(uts_header_tree
, hf_did
, tvb
, 3, 1, did
, "DID (%02X)", did
);
269 proto_tree_add_boolean_format(uts_header_tree
, hf_retxrequest
, tvb
, nak_start
, 2, 1, "Re-transmit Request");
271 proto_tree_add_boolean_format(uts_header_tree
, hf_ack
, tvb
, ack_start
, 2, 1, "Ack");
273 if (replyrequest_start
)
274 proto_tree_add_boolean_format(uts_header_tree
, hf_replyrequest
, tvb
, replyrequest_start
, 2, 1, "Reply Request");
276 proto_tree_add_boolean_format(uts_header_tree
, hf_busy
, tvb
, busy_start
, 2, 1, "Busy");
279 proto_tree_add_boolean_format(uts_header_tree
, hf_notbusy
, tvb
, notbusy_start
, 2, 1, "Not Busy");
281 if (msgwaiting_start
)
282 proto_tree_add_boolean_format(uts_header_tree
, hf_msgwaiting
, tvb
, msgwaiting_start
, 1, 1, "Message Waiting");
285 proto_tree_add_uint_format(uts_header_tree
, hf_function
, tvb
, function_start
, 1, function_code
, "Function '%c'", function_code
);
288 proto_tree_add_protocol_format(uts_header_tree
, proto_uts
, tvb
, stx_start
, 1, "Start of Text");
289 length
= tvb_captured_length_remaining(tvb
, stx_start
+1); /* find out how much message remains */
291 length
= (etx_start
- stx_start
- 1); /* and the data part is the rest... */
292 /* whatever precedes the ETX if it exists */
293 data_ptr
= tvb_get_string_enc(pinfo
->pool
, tvb
, stx_start
+1, length
, ENC_ASCII
); /* copy the string for dissecting */
294 proto_tree_add_string_format(uts_tree
, hf_data
, tvb
, stx_start
+ 1, length
, data_ptr
,
295 "Text (%d byte%s)", length
, plurality(length
, "", "s"));
299 uts_trailer_tree
= proto_tree_add_subtree(uts_tree
, tvb
, etx_start
, -1, ett_trailer_uts
, NULL
, "Trailer");
302 proto_tree_add_protocol_format(uts_trailer_tree
, proto_uts
, tvb
, etx_start
, 1, "ETX");
304 proto_tree_add_protocol_format(uts_trailer_tree
, proto_uts
, tvb
, bcc_start
, -1, "CCC + padding");
308 return tvb_captured_length(tvb
);
312 proto_register_uts(void)
314 static hf_register_info hf
[] = {
317 FT_UINT8
, BASE_HEX
, NULL
, 0, "Remote Identifier address", HFILL
}},
320 FT_UINT8
, BASE_HEX
, NULL
, 0, "Site Identifier address", HFILL
}},
323 FT_UINT8
, BASE_HEX
, NULL
, 0, "Device Identifier address", HFILL
}},
325 { "ReTxRequest", "uts.retxrequest",
326 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "true if Re-transmit Request", HFILL
}},
329 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "true if Ack", HFILL
}},
331 { "ReplyRequest", "uts.replyrequest",
332 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "true if Reply Request", HFILL
}},
334 { "Busy", "uts.busy",
335 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "true if Busy", HFILL
}},
337 { "NotBusy", "uts.notbusy",
338 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "true if Not Busy", HFILL
}},
340 { "MsgWaiting", "uts.msgwaiting",
341 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "true if Message Waiting", HFILL
}},
343 { "Function", "uts.function",
344 FT_UINT8
, BASE_HEX
, NULL
, 0, "Function Code value", HFILL
}},
346 { "Data", "uts.data",
347 FT_STRING
, BASE_NONE
, NULL
, 0, "User Data Message", HFILL
}},
350 static int *ett
[] = {
356 proto_uts
= proto_register_protocol("Unisys Transmittal System", "UTS", "uts"); /* name, short name, abbrev */
357 proto_register_field_array(proto_uts
, hf
, array_length(hf
));
358 proto_register_subtree_array(ett
, array_length(ett
));
359 register_dissector("uts", dissect_uts
, proto_uts
);
363 * Editor modelines - https://www.wireshark.org/tools/modelines.html
368 * indent-tabs-mode: t
371 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
372 * :indentSize=8:tabSize=8:noTabs=false: