2 * Routines for UTS WAN protocol dissection
3 * Copyright 2007, Fulko Hew, SITA INC Canada, Inc.
7 * Copied from packet-ipars.c
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 /* Use tabstops = 4 */
36 #include <epan/packet.h>
37 #include <epan/emem.h>
52 #define MAX_POLL_TYPE_MSG_SIZE (50)
54 static int proto_uts = -1;
55 static gint ett_uts = -1;
56 static gint ett_header_uts = -1;
57 static gint ett_trailer_uts = -1;
58 static int hf_rid = -1;
59 static int hf_sid = -1;
60 static int hf_did = -1;
61 static int hf_retxrequest = -1;
62 static int hf_ack = -1;
63 static int hf_replyrequest = -1;
64 static int hf_busy = -1;
65 static int hf_notbusy = -1;
66 static int hf_msgwaiting = -1;
67 static int hf_function = -1;
68 static int hf_data = -1;
76 static int testchar(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, int op, gchar match, gchar *storage)
80 if (tvb_length_remaining(tvb, offset)) {
81 temp = tvb_get_guint8(tvb, offset) & 0x7f;
82 if (op == FETCH || (op == MATCH && temp == match)) {
83 if (storage != NULL) *storage = temp;
89 if (check_col(pinfo->cinfo, COL_INFO))
90 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown Message Format");
96 set_addr(packet_info *pinfo _U_ , int field, gchar rid, gchar sid, gchar did)
99 if (check_col(pinfo->cinfo, COL_DEF_SRC)) col_append_fstr(pinfo->cinfo, COL_DEF_SRC, " %2.2X:%2.2X:%2.2X", rid, sid, did);
101 if (check_col(pinfo->cinfo, COL_DEF_DST)) col_append_fstr(pinfo->cinfo, COL_DEF_DST, " %2.2X:%2.2X:%2.2X", rid, sid, did);
106 dissect_uts(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree)
108 proto_tree *uts_tree = NULL;
109 proto_tree *uts_header_tree = NULL;
110 proto_tree *uts_trailer_tree = NULL;
116 int header_length = -1;
119 int notbusy_start = 0;
120 int replyrequest_start = 0;
121 int function_start = 0;
122 int msgwaiting_start = 0;
130 enum { NOTRAFFIC, OTHER } msg_type = OTHER;
132 msg_msg = ep_alloc(MAX_POLL_TYPE_MSG_SIZE);
135 if (check_col(pinfo->cinfo, COL_PROTOCOL)) /* set the protocol column on summary display */
136 col_set_str(pinfo->cinfo, COL_PROTOCOL, "UTS");
138 if (testchar(tvb, pinfo, 0, MATCH, EOT, NULL) &&
139 testchar(tvb, pinfo, 1, MATCH, EOT, NULL) &&
140 testchar(tvb, pinfo, 2, MATCH, ETX, NULL)) {
141 msg_type = NOTRAFFIC;
142 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "No Traffic");
144 if (testchar(tvb, pinfo, 0, MATCH, SOH, NULL) &&
145 testchar(tvb, pinfo, 1, FETCH, 0, (gchar *)&rid) &&
146 testchar(tvb, pinfo, 2, FETCH, 0, (gchar *)&sid) &&
147 testchar(tvb, pinfo, 3, FETCH, 0, (gchar *)&did)) {
149 if (testchar(tvb, pinfo, offset, MATCH, ETX, NULL)) {
150 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "General Poll");
151 set_addr(pinfo, DST, rid, sid, did);
152 } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
153 testchar(tvb, pinfo, offset+1, MATCH, '1', NULL) &&
154 testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) {
156 if (sid == GSID && did == GDID) {
157 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "General Poll + ACK");
158 set_addr(pinfo, DST, rid, sid, did);
159 } else if (sid != GSID && did == GDID) {
160 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "Specific Poll + ACK");
161 set_addr(pinfo, DST, rid, sid, did);
162 } else if (sid != GSID && did != GDID) {
163 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "No Traffic + ACK");
164 set_addr(pinfo, SRC, rid, sid, did);
166 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "Unknown Message Format");
167 if ((pinfo->pseudo_header->sita.flags & SITA_FRAME_DIR) == SITA_FRAME_DIR_TXED) {
168 set_addr(pinfo, DST, rid, sid, did); /* if the ACN sent it, the address is of the destination... the terminal */
170 set_addr(pinfo, SRC, rid, sid, did); /* if the ACN received it, the address if of the source... the terminal */
173 } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
174 testchar(tvb, pinfo, offset+1, MATCH, NAK, NULL) &&
175 testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL) &&
176 sid != GSID && did == GDID) {
178 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "Retransmit Request");
179 set_addr(pinfo, DST, rid, sid, did);
180 } else if (testchar(tvb, pinfo, offset, MATCH, BEL, NULL) &&
181 testchar(tvb, pinfo, offset+1, MATCH, STX, NULL) &&
182 testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) {
183 header_length = offset+2;
184 msgwaiting_start = offset;
185 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "Message Waiting");
186 set_addr(pinfo, DST, rid, sid, did);
187 } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
188 testchar(tvb, pinfo, offset+1, MATCH, '1', NULL) &&
189 testchar(tvb, pinfo, offset+2, MATCH, STX, NULL)) {
191 header_length = offset+3;
192 stx_start = offset+2;
193 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "Text + ACK");
194 set_addr(pinfo, SRC, rid, sid, did);
195 } else if (testchar(tvb, pinfo, offset, MATCH, STX, NULL)) {
196 header_length = offset+1;
198 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "Text");
199 if ((pinfo->pseudo_header->sita.flags & SITA_FRAME_DIR) == SITA_FRAME_DIR_TXED) {
200 set_addr(pinfo, DST, rid, sid, did); /* if the ACN sent it, the address is of the destination... the terminal */
202 set_addr(pinfo, SRC, rid, sid, did); /* if the ACN received it, the address if of the source... the terminal */
204 } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
205 testchar(tvb, pinfo, offset+1, MATCH, ENQ, NULL) &&
206 testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) {
207 replyrequest_start = offset;
208 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "Reply Request");
209 set_addr(pinfo, SRC, rid, sid, did);
210 } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
211 testchar(tvb, pinfo, offset+1, MATCH, '?', NULL) &&
212 testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) {
214 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "Busy");
215 set_addr(pinfo, SRC, rid, sid, did);
216 } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
217 testchar(tvb, pinfo, offset+1, MATCH, ';', NULL) &&
218 testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) {
219 notbusy_start = offset;
220 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "Not Busy");
221 set_addr(pinfo, SRC, rid, sid, did);
222 } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
223 testchar(tvb, pinfo, offset+1, MATCH, '1', NULL) &&
224 testchar(tvb, pinfo, offset+2, MATCH, DLE, NULL) &&
225 testchar(tvb, pinfo, offset+3, MATCH, ';', NULL) &&
226 testchar(tvb, pinfo, offset+4, MATCH, ETX, NULL)) {
227 notbusy_start = offset+2;
229 g_snprintf(msg_msg, MAX_POLL_TYPE_MSG_SIZE, "Not Busy + ACK");
230 set_addr(pinfo, SRC, rid, sid, did);
231 } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
232 testchar(tvb, pinfo, offset+1, MATCH, '1', NULL) &&
233 testchar(tvb, pinfo, offset+2, FETCH, 0, &function_code) &&
234 testchar(tvb, pinfo, offset+3, MATCH, ETX, NULL)) {
236 function_start = offset + 2;
237 if (check_col(pinfo->cinfo, COL_INFO))
238 col_add_fstr(pinfo->cinfo, COL_INFO, "Function Message '%c' + ACK", function_code);
239 set_addr(pinfo, SRC, rid, sid, did);
240 } else if (testchar(tvb, pinfo, offset, FETCH, 0, &function_code) &&
241 testchar(tvb, pinfo, offset+1, MATCH, ETX, NULL)) {
242 function_start = offset;
243 if (check_col(pinfo->cinfo, COL_INFO))
244 col_add_fstr(pinfo->cinfo, COL_INFO, "Function Message '%c'", function_code);
245 set_addr(pinfo, SRC, rid, sid, did);
249 if ((check_col(pinfo->cinfo, COL_INFO)) && strlen(msg_msg))
250 col_add_str(pinfo->cinfo, COL_INFO, msg_msg);
252 while (tvb_length_remaining(tvb, offset)) { /* now look for the ETX */
253 if ((tvb_get_guint8(tvb, offset) & 0x7f) == ETX) {
254 if (header_length == -1) header_length = offset; /* the header ends at an STX, or if not found, the ETX */
261 if (tvb_length_remaining(tvb, offset)) /* if there is anything left, it could be the BCC and pads */
265 ti = proto_tree_add_protocol_format(tree, proto_uts, tvb, 0, -1, "UTS");
266 uts_tree = proto_item_add_subtree(ti, ett_uts);
268 if (msg_type == NOTRAFFIC) {
269 proto_tree_add_protocol_format(uts_tree, proto_uts, tvb, 0, 2, "No Traffic");
270 proto_tree_add_protocol_format(uts_tree, proto_uts, tvb, 2, -1, "ETX + padding");
272 ti = proto_tree_add_text(uts_tree, tvb, 0, header_length, "Header");
273 uts_header_tree = proto_item_add_subtree(ti, ett_header_uts);
275 proto_tree_add_protocol_format(uts_header_tree, proto_uts, tvb, 0, 1, "SOH");
277 if (rid == GRID) proto_tree_add_uint_format(uts_header_tree, hf_rid, tvb, 1, 1, rid, "RID (%02X) (General)", rid );
278 else proto_tree_add_uint_format(uts_header_tree, hf_rid, tvb, 1, 1, rid, "RID (%02X)", rid );
279 if (sid == GSID) proto_tree_add_uint_format(uts_header_tree, hf_sid, tvb, 2, 1, sid, "SID (%02X) (General)", sid );
280 else proto_tree_add_uint_format(uts_header_tree, hf_sid, tvb, 2, 1, sid, "SID (%02X)", sid );
281 if (sid == GDID) proto_tree_add_uint_format(uts_header_tree, hf_did, tvb, 3, 1, did, "DID (%02X) (General)", did );
282 else proto_tree_add_uint_format(uts_header_tree, hf_did, tvb, 3, 1, did, "DID (%02X)", did );
284 if (nak_start) proto_tree_add_boolean_format(uts_header_tree, hf_retxrequest, tvb, nak_start, 2, 1, "Re-transmit Request");
285 if (ack_start) proto_tree_add_boolean_format(uts_header_tree, hf_ack, tvb, ack_start, 2, 1, "Ack");
286 if (replyrequest_start) proto_tree_add_boolean_format(uts_header_tree, hf_replyrequest, tvb, replyrequest_start, 2, 1, "Reply Request");
287 if (busy_start) proto_tree_add_boolean_format(uts_header_tree, hf_busy, tvb, busy_start, 2, 1, "Busy");
288 if (notbusy_start) proto_tree_add_boolean_format(uts_header_tree, hf_notbusy, tvb, notbusy_start, 2, 1, "Not Busy");
289 if (msgwaiting_start) proto_tree_add_boolean_format(uts_header_tree, hf_msgwaiting, tvb, msgwaiting_start, 1, 1, "Message Waiting");
291 proto_tree_add_uint_format(uts_header_tree, hf_function, tvb, function_start, 1, function_code, "Function '%c'", function_code );
294 proto_tree_add_protocol_format(uts_header_tree, proto_uts, tvb, stx_start, 1, "Start of Text" );
295 length = tvb_length_remaining(tvb, stx_start+1); /* find out how much message remains */
296 if (etx_start) length = (etx_start - stx_start - 1); /* and the data part is the rest... whatever preceeds the ETX if it exists */
297 data_ptr = tvb_get_ephemeral_string(tvb, stx_start+1, length); /* copy the string for dissecting */
298 proto_tree_add_string_format(uts_tree, hf_data, tvb, stx_start + 1, length, data_ptr, "Text (%d byte%s)", length, plurality(length, "", "s"));
301 ti = proto_tree_add_text(uts_tree, tvb, etx_start, -1, "Trailer");
302 uts_trailer_tree = proto_item_add_subtree(ti, ett_trailer_uts);
304 if (etx_start) proto_tree_add_protocol_format(uts_trailer_tree, proto_uts, tvb, etx_start, 1, "ETX" );
305 if (bcc_start) proto_tree_add_protocol_format(uts_trailer_tree, proto_uts, tvb, bcc_start, -1, "CCC + padding" );
312 proto_register_uts(void)
314 static hf_register_info hf[] = {
315 { &hf_rid, { "RID", "uts.rid", FT_UINT8, BASE_HEX, NULL, 0, "Remote Identifier address", HFILL }},
316 { &hf_sid, { "SID", "uts.sid", FT_UINT8, BASE_HEX, NULL, 0, "Site Identifier address", HFILL }},
317 { &hf_did, { "DID", "uts.did", FT_UINT8, BASE_HEX, NULL, 0, "Device Identifier address", HFILL }},
318 { &hf_retxrequest, { "ReTxRequst", "uts.retxrequst", FT_BOOLEAN, BASE_NONE, NULL, 0, "TRUE if Re-transmit Request", HFILL }},
319 { &hf_ack, { "Ack", "uts.ack", FT_BOOLEAN, BASE_NONE, NULL, 0, "TRUE if Ack", HFILL }},
320 { &hf_replyrequest, { "ReplyRequst", "uts.replyrequest", FT_BOOLEAN, BASE_NONE, NULL, 0, "TRUE if Reply Request", HFILL }},
321 { &hf_busy, { "Busy", "uts.busy", FT_BOOLEAN, BASE_NONE, NULL, 0, "TRUE if Busy", HFILL }},
322 { &hf_notbusy, { "NotBusy", "uts.notbusy", FT_BOOLEAN, BASE_NONE, NULL, 0, "TRUE if Not Busy", HFILL }},
323 { &hf_msgwaiting, { "MsgWaiting", "uts.msgwaiting", FT_BOOLEAN, BASE_NONE, NULL, 0, "TRUE if Message Waiting", HFILL }},
324 { &hf_function, { "Function", "uts.function", FT_UINT8, BASE_HEX, NULL, 0, "Function Code value", HFILL }},
325 { &hf_data, { "Data", "uts.data", FT_STRING, BASE_NONE, NULL, 0, "User Data Message", HFILL }},
328 static gint *ett[] = {
334 proto_uts = proto_register_protocol("Unisys Transmittal System", "UTS", "uts"); /* name, short name, abbrev */
335 proto_register_field_array(proto_uts, hf, array_length(hf));
336 proto_register_subtree_array(ett, array_length(ett));
337 register_dissector("uts", dissect_uts, proto_uts);