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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 /* Use tabstops = 4 */
33 #include <epan/packet.h>
48 #define MAX_POLL_TYPE_MSG_SIZE (50)
50 static int proto_uts
= -1;
51 static gint ett_uts
= -1;
52 static gint ett_header_uts
= -1;
53 static gint ett_trailer_uts
= -1;
54 static int hf_rid
= -1;
55 static int hf_sid
= -1;
56 static int hf_did
= -1;
57 static int hf_retxrequest
= -1;
58 static int hf_ack
= -1;
59 static int hf_replyrequest
= -1;
60 static int hf_busy
= -1;
61 static int hf_notbusy
= -1;
62 static int hf_msgwaiting
= -1;
63 static int hf_function
= -1;
64 static int hf_data
= -1;
72 static int testchar(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, int offset
, int op
, gchar match
, gchar
*storage
)
76 if (tvb_length_remaining(tvb
, offset
)) {
77 temp
= tvb_get_guint8(tvb
, offset
) & 0x7f;
78 if (op
== FETCH
|| (op
== MATCH
&& temp
== match
)) {
86 col_set_str(pinfo
->cinfo
, COL_INFO
, "Unknown Message Format");
92 set_addr(packet_info
*pinfo _U_
, int field
, gchar rid
, gchar sid
, gchar did
)
95 col_append_fstr(pinfo
->cinfo
, COL_DEF_SRC
, " %2.2X:%2.2X:%2.2X", rid
, sid
, did
);
97 col_append_fstr(pinfo
->cinfo
, COL_DEF_DST
, " %2.2X:%2.2X:%2.2X", rid
, sid
, did
);
102 dissect_uts(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
)
104 proto_tree
*uts_tree
= NULL
;
105 proto_tree
*uts_header_tree
= NULL
;
106 proto_tree
*uts_trailer_tree
= NULL
;
109 gchar rid
= 0, sid
= 0, did
= 0;
111 int header_length
= -1;
114 int notbusy_start
= 0;
115 int replyrequest_start
= 0;
116 int function_start
= 0;
117 int msgwaiting_start
= 0;
125 enum { NOTRAFFIC
, OTHER
} msg_type
= OTHER
;
127 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "UTS");
129 if (testchar(tvb
, pinfo
, 0, MATCH
, EOT
, NULL
) &&
130 testchar(tvb
, pinfo
, 1, MATCH
, EOT
, NULL
) &&
131 testchar(tvb
, pinfo
, 2, MATCH
, ETX
, NULL
)) {
132 msg_type
= NOTRAFFIC
;
133 col_set_str(pinfo
->cinfo
, COL_INFO
, "No Traffic");
135 if (testchar(tvb
, pinfo
, 0, MATCH
, SOH
, NULL
) &&
136 testchar(tvb
, pinfo
, 1, FETCH
, 0, (gchar
*)&rid
) &&
137 testchar(tvb
, pinfo
, 2, FETCH
, 0, (gchar
*)&sid
) &&
138 testchar(tvb
, pinfo
, 3, FETCH
, 0, (gchar
*)&did
)) {
140 if (testchar(tvb
, pinfo
, offset
, MATCH
, ETX
, NULL
)) {
141 col_set_str(pinfo
->cinfo
, COL_INFO
, "General Poll");
142 set_addr(pinfo
, DST
, rid
, sid
, did
);
143 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
144 testchar(tvb
, pinfo
, offset
+1, MATCH
, '1', NULL
) &&
145 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
)) {
147 if (sid
== GSID
&& did
== GDID
) {
148 col_set_str(pinfo
->cinfo
, COL_INFO
, "General Poll + ACK");
149 set_addr(pinfo
, DST
, rid
, sid
, did
);
150 } else if (sid
!= GSID
&& did
== GDID
) {
151 col_set_str(pinfo
->cinfo
, COL_INFO
, "Specific Poll + ACK");
152 set_addr(pinfo
, DST
, rid
, sid
, did
);
153 } else if (sid
!= GSID
&& did
!= GDID
) {
154 col_set_str(pinfo
->cinfo
, COL_INFO
, "No Traffic + ACK");
155 set_addr(pinfo
, SRC
, rid
, sid
, did
);
157 col_set_str(pinfo
->cinfo
, COL_INFO
, "Unknown Message Format");
158 if ((pinfo
->pseudo_header
->sita
.sita_flags
& SITA_FRAME_DIR
) == SITA_FRAME_DIR_TXED
) {
159 set_addr(pinfo
, DST
, rid
, sid
, did
); /* if the ACN sent it, the address is of the destination... the terminal */
161 set_addr(pinfo
, SRC
, rid
, sid
, did
); /* if the ACN received it, the address if of the source... the terminal */
164 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
165 testchar(tvb
, pinfo
, offset
+1, MATCH
, NAK
, NULL
) &&
166 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
) &&
167 sid
!= GSID
&& did
== GDID
) {
169 col_set_str(pinfo
->cinfo
, COL_INFO
, "Retransmit Request");
170 set_addr(pinfo
, DST
, rid
, sid
, did
);
171 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, BEL
, NULL
) &&
172 testchar(tvb
, pinfo
, offset
+1, MATCH
, STX
, NULL
) &&
173 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
)) {
174 header_length
= offset
+2;
175 msgwaiting_start
= offset
;
176 col_set_str(pinfo
->cinfo
, COL_INFO
, "Message Waiting");
177 set_addr(pinfo
, DST
, rid
, sid
, did
);
178 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
179 testchar(tvb
, pinfo
, offset
+1, MATCH
, '1', NULL
) &&
180 testchar(tvb
, pinfo
, offset
+2, MATCH
, STX
, NULL
)) {
182 header_length
= offset
+3;
183 stx_start
= offset
+2;
184 col_set_str(pinfo
->cinfo
, COL_INFO
, "Text + ACK");
185 set_addr(pinfo
, SRC
, rid
, sid
, did
);
186 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, STX
, NULL
)) {
187 header_length
= offset
+1;
189 col_set_str(pinfo
->cinfo
, COL_INFO
, "Text");
190 if ((pinfo
->pseudo_header
->sita
.sita_flags
& SITA_FRAME_DIR
) == SITA_FRAME_DIR_TXED
) {
191 set_addr(pinfo
, DST
, rid
, sid
, did
); /* if the ACN sent it, the address is of the destination... the terminal */
193 set_addr(pinfo
, SRC
, rid
, sid
, did
); /* if the ACN received it, the address if of the source... the terminal */
195 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
196 testchar(tvb
, pinfo
, offset
+1, MATCH
, ENQ
, NULL
) &&
197 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
)) {
198 replyrequest_start
= offset
;
199 col_set_str(pinfo
->cinfo
, COL_INFO
, "Reply Request");
200 set_addr(pinfo
, SRC
, rid
, sid
, did
);
201 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
202 testchar(tvb
, pinfo
, offset
+1, MATCH
, '?', NULL
) &&
203 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
)) {
205 col_set_str(pinfo
->cinfo
, COL_INFO
, "Busy");
206 set_addr(pinfo
, SRC
, rid
, sid
, did
);
207 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
208 testchar(tvb
, pinfo
, offset
+1, MATCH
, ';', NULL
) &&
209 testchar(tvb
, pinfo
, offset
+2, MATCH
, ETX
, NULL
)) {
210 notbusy_start
= offset
;
211 col_set_str(pinfo
->cinfo
, COL_INFO
, "Not Busy");
212 set_addr(pinfo
, SRC
, rid
, sid
, did
);
213 } else if (testchar(tvb
, pinfo
, offset
, MATCH
, DLE
, NULL
) &&
214 testchar(tvb
, pinfo
, offset
+1, MATCH
, '1', NULL
) &&
215 testchar(tvb
, pinfo
, offset
+2, MATCH
, DLE
, NULL
) &&
216 testchar(tvb
, pinfo
, offset
+3, MATCH
, ';', NULL
) &&
217 testchar(tvb
, pinfo
, offset
+4, MATCH
, ETX
, NULL
)) {
218 notbusy_start
= offset
+2;
220 col_set_str(pinfo
->cinfo
, COL_INFO
, "Not Busy + ACK");
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, FETCH
, 0, &function_code
) &&
225 testchar(tvb
, pinfo
, offset
+3, MATCH
, ETX
, NULL
)) {
227 function_start
= offset
+ 2;
228 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Function Message '%c' + ACK", function_code
);
229 set_addr(pinfo
, SRC
, rid
, sid
, did
);
230 } else if (testchar(tvb
, pinfo
, offset
, FETCH
, 0, &function_code
) &&
231 testchar(tvb
, pinfo
, offset
+1, MATCH
, ETX
, NULL
)) {
232 function_start
= offset
;
233 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Function Message '%c'", function_code
);
234 set_addr(pinfo
, SRC
, rid
, sid
, did
);
239 while (tvb_length_remaining(tvb
, offset
) > 0) { /* now look for the ETX */
240 if ((tvb_get_guint8(tvb
, offset
) & 0x7f) == ETX
) {
241 if (header_length
== -1)
242 header_length
= offset
; /* the header ends at an STX, or if not found, the ETX */
249 if (tvb_length_remaining(tvb
, offset
)) /* if there is anything left, it could be the BCC and pads */
253 ti
= proto_tree_add_protocol_format(tree
, proto_uts
, tvb
, 0, -1, "UTS");
254 uts_tree
= proto_item_add_subtree(ti
, ett_uts
);
256 if (msg_type
== NOTRAFFIC
) {
257 proto_tree_add_protocol_format(uts_tree
, proto_uts
, tvb
, 0, 2, "No Traffic");
258 proto_tree_add_protocol_format(uts_tree
, proto_uts
, tvb
, 2, -1, "ETX + padding");
260 ti
= proto_tree_add_text(uts_tree
, tvb
, 0, header_length
, "Header");
261 uts_header_tree
= proto_item_add_subtree(ti
, ett_header_uts
);
263 proto_tree_add_protocol_format(uts_header_tree
, proto_uts
, tvb
, 0, 1, "SOH");
266 proto_tree_add_uint_format(uts_header_tree
, hf_rid
, tvb
, 1, 1, rid
, "RID (%02X) (General)", rid
);
268 proto_tree_add_uint_format(uts_header_tree
, hf_rid
, tvb
, 1, 1, rid
, "RID (%02X)", rid
);
271 proto_tree_add_uint_format(uts_header_tree
, hf_sid
, tvb
, 2, 1, sid
, "SID (%02X) (General)", sid
);
273 proto_tree_add_uint_format(uts_header_tree
, hf_sid
, tvb
, 2, 1, sid
, "SID (%02X)", sid
);
276 proto_tree_add_uint_format(uts_header_tree
, hf_did
, tvb
, 3, 1, did
, "DID (%02X) (General)", did
);
278 proto_tree_add_uint_format(uts_header_tree
, hf_did
, tvb
, 3, 1, did
, "DID (%02X)", did
);
281 proto_tree_add_boolean_format(uts_header_tree
, hf_retxrequest
, tvb
, nak_start
, 2, 1, "Re-transmit Request");
283 proto_tree_add_boolean_format(uts_header_tree
, hf_ack
, tvb
, ack_start
, 2, 1, "Ack");
285 if (replyrequest_start
)
286 proto_tree_add_boolean_format(uts_header_tree
, hf_replyrequest
, tvb
, replyrequest_start
, 2, 1, "Reply Request");
288 proto_tree_add_boolean_format(uts_header_tree
, hf_busy
, tvb
, busy_start
, 2, 1, "Busy");
291 proto_tree_add_boolean_format(uts_header_tree
, hf_notbusy
, tvb
, notbusy_start
, 2, 1, "Not Busy");
293 if (msgwaiting_start
)
294 proto_tree_add_boolean_format(uts_header_tree
, hf_msgwaiting
, tvb
, msgwaiting_start
, 1, 1, "Message Waiting");
297 proto_tree_add_uint_format(uts_header_tree
, hf_function
, tvb
, function_start
, 1, function_code
, "Function '%c'", function_code
);
300 proto_tree_add_protocol_format(uts_header_tree
, proto_uts
, tvb
, stx_start
, 1, "Start of Text");
301 length
= tvb_length_remaining(tvb
, stx_start
+1); /* find out how much message remains */
303 length
= (etx_start
- stx_start
- 1); /* and the data part is the rest... */
304 /* whatever preceeds the ETX if it exists */
305 data_ptr
= tvb_get_string(wmem_packet_scope(), tvb
, stx_start
+1, length
); /* copy the string for dissecting */
306 proto_tree_add_string_format(uts_tree
, hf_data
, tvb
, stx_start
+ 1, length
, data_ptr
,
307 "Text (%d byte%s)", length
, plurality(length
, "", "s"));
311 ti
= proto_tree_add_text(uts_tree
, tvb
, etx_start
, -1, "Trailer");
312 uts_trailer_tree
= proto_item_add_subtree(ti
, ett_trailer_uts
);
315 proto_tree_add_protocol_format(uts_trailer_tree
, proto_uts
, tvb
, etx_start
, 1, "ETX");
317 proto_tree_add_protocol_format(uts_trailer_tree
, proto_uts
, tvb
, bcc_start
, -1, "CCC + padding");
324 proto_register_uts(void)
326 static hf_register_info hf
[] = {
329 FT_UINT8
, BASE_HEX
, NULL
, 0, "Remote Identifier address", HFILL
}},
332 FT_UINT8
, BASE_HEX
, NULL
, 0, "Site Identifier address", HFILL
}},
335 FT_UINT8
, BASE_HEX
, NULL
, 0, "Device Identifier address", HFILL
}},
337 { "ReTxRequst", "uts.retxrequst",
338 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "TRUE if Re-transmit Request", HFILL
}},
341 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "TRUE if Ack", HFILL
}},
343 { "ReplyRequst", "uts.replyrequest",
344 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "TRUE if Reply Request", HFILL
}},
346 { "Busy", "uts.busy",
347 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "TRUE if Busy", HFILL
}},
349 { "NotBusy", "uts.notbusy",
350 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "TRUE if Not Busy", HFILL
}},
352 { "MsgWaiting", "uts.msgwaiting",
353 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "TRUE if Message Waiting", HFILL
}},
355 { "Function", "uts.function",
356 FT_UINT8
, BASE_HEX
, NULL
, 0, "Function Code value", HFILL
}},
358 { "Data", "uts.data",
359 FT_STRING
, BASE_NONE
, NULL
, 0, "User Data Message", HFILL
}},
362 static gint
*ett
[] = {
368 proto_uts
= proto_register_protocol("Unisys Transmittal System", "UTS", "uts"); /* name, short name, abbrev */
369 proto_register_field_array(proto_uts
, hf
, array_length(hf
));
370 proto_register_subtree_array(ett
, array_length(ett
));
371 register_dissector("uts", dissect_uts
, proto_uts
);