HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-uts.c
blob6061a0103126301f46dd350fff99fe18e33cd63e
1 /* packet-uts.c
2 * Routines for UTS WAN protocol dissection
3 * Copyright 2007, Fulko Hew, SITA INC Canada, Inc.
5 * $Id$
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 */
30 #include "config.h"
32 #include <glib.h>
33 #include <epan/packet.h>
35 #define SOH (0x01)
36 #define STX (0x02)
37 #define ETX (0x03)
38 #define EOT (0x04)
39 #define ENQ (0x05)
40 #define BEL (0x07)
41 #define NAK (0x15)
42 #define DLE (0x10)
44 #define GRID (0x20)
45 #define GSID (0x50)
46 #define GDID (0x70)
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;
66 #define MATCH (1)
67 #define FETCH (2)
69 #define SRC (1)
70 #define DST (2)
72 static int testchar(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, int op, gchar match, gchar *storage)
74 gchar temp;
76 if (tvb_length_remaining(tvb, offset)) {
77 temp = tvb_get_guint8(tvb, offset) & 0x7f;
78 if (op == FETCH || (op == MATCH && temp == match)) {
79 if (storage != NULL)
80 *storage = temp;
81 return 1;
82 } else {
83 return 0;
85 } else {
86 col_set_str(pinfo->cinfo, COL_INFO, "Unknown Message Format");
87 return 0;
91 static void
92 set_addr(packet_info *pinfo _U_ , int field, gchar rid, gchar sid, gchar did)
94 if (field == SRC) {
95 col_append_fstr(pinfo->cinfo, COL_DEF_SRC, " %2.2X:%2.2X:%2.2X", rid, sid, did);
96 } else {
97 col_append_fstr(pinfo->cinfo, COL_DEF_DST, " %2.2X:%2.2X:%2.2X", rid, sid, did);
101 static void
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;
107 proto_item *ti;
108 int length;
109 gchar rid = 0, sid = 0, did = 0;
110 int offset = 0;
111 int header_length = -1;
112 int ack_start = 0;
113 int busy_start = 0;
114 int notbusy_start = 0;
115 int replyrequest_start = 0;
116 int function_start = 0;
117 int msgwaiting_start = 0;
118 int nak_start = 0;
119 int etx_start = 0;
120 int bcc_start = 0;
121 int stx_start = 0;
122 gchar function_code;
123 guint8 *data_ptr;
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");
134 } else {
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)) {
139 offset = 4;
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)) {
146 ack_start = offset;
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);
156 } else {
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 */
160 } else {
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) {
168 nak_start = offset;
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)) {
181 ack_start = offset;
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;
188 stx_start = offset;
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 */
192 } else {
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)) {
204 busy_start = offset;
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;
219 ack_start = offset;
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)) {
226 ack_start = offset;
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 */
243 etx_start = offset;
244 offset++;
245 break;
247 offset++;
249 if (tvb_length_remaining(tvb, offset)) /* if there is anything left, it could be the BCC and pads */
250 bcc_start = offset;
252 if (tree) {
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");
259 } else {
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");
265 if (rid == GRID)
266 proto_tree_add_uint_format(uts_header_tree, hf_rid, tvb, 1, 1, rid, "RID (%02X) (General)", rid);
267 else
268 proto_tree_add_uint_format(uts_header_tree, hf_rid, tvb, 1, 1, rid, "RID (%02X)", rid);
270 if (sid == GSID)
271 proto_tree_add_uint_format(uts_header_tree, hf_sid, tvb, 2, 1, sid, "SID (%02X) (General)", sid);
272 else
273 proto_tree_add_uint_format(uts_header_tree, hf_sid, tvb, 2, 1, sid, "SID (%02X)", sid);
275 if (sid == GDID)
276 proto_tree_add_uint_format(uts_header_tree, hf_did, tvb, 3, 1, did, "DID (%02X) (General)", did);
277 else
278 proto_tree_add_uint_format(uts_header_tree, hf_did, tvb, 3, 1, did, "DID (%02X)", did);
280 if (nak_start)
281 proto_tree_add_boolean_format(uts_header_tree, hf_retxrequest, tvb, nak_start, 2, 1, "Re-transmit Request");
282 if (ack_start)
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");
287 if (busy_start)
288 proto_tree_add_boolean_format(uts_header_tree, hf_busy, tvb, busy_start, 2, 1, "Busy");
290 if (notbusy_start)
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");
296 if (function_start)
297 proto_tree_add_uint_format(uts_header_tree, hf_function, tvb, function_start, 1, function_code, "Function '%c'", function_code );
299 if (stx_start) {
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 */
302 if (etx_start)
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"));
310 if (etx_start) {
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);
314 if (etx_start)
315 proto_tree_add_protocol_format(uts_trailer_tree, proto_uts, tvb, etx_start, 1, "ETX");
316 if (bcc_start)
317 proto_tree_add_protocol_format(uts_trailer_tree, proto_uts, tvb, bcc_start, -1, "CCC + padding");
323 void
324 proto_register_uts(void)
326 static hf_register_info hf[] = {
327 { &hf_rid,
328 { "RID", "uts.rid",
329 FT_UINT8, BASE_HEX, NULL, 0, "Remote Identifier address", HFILL }},
330 { &hf_sid,
331 { "SID", "uts.sid",
332 FT_UINT8, BASE_HEX, NULL, 0, "Site Identifier address", HFILL }},
333 { &hf_did,
334 { "DID", "uts.did",
335 FT_UINT8, BASE_HEX, NULL, 0, "Device Identifier address", HFILL }},
336 { &hf_retxrequest,
337 { "ReTxRequst", "uts.retxrequst",
338 FT_BOOLEAN, BASE_NONE, NULL, 0x0, "TRUE if Re-transmit Request", HFILL }},
339 { &hf_ack,
340 { "Ack", "uts.ack",
341 FT_BOOLEAN, BASE_NONE, NULL, 0x0, "TRUE if Ack", HFILL }},
342 { &hf_replyrequest,
343 { "ReplyRequst", "uts.replyrequest",
344 FT_BOOLEAN, BASE_NONE, NULL, 0x0, "TRUE if Reply Request", HFILL }},
345 { &hf_busy,
346 { "Busy", "uts.busy",
347 FT_BOOLEAN, BASE_NONE, NULL, 0x0, "TRUE if Busy", HFILL }},
348 { &hf_notbusy,
349 { "NotBusy", "uts.notbusy",
350 FT_BOOLEAN, BASE_NONE, NULL, 0x0, "TRUE if Not Busy", HFILL }},
351 { &hf_msgwaiting,
352 { "MsgWaiting", "uts.msgwaiting",
353 FT_BOOLEAN, BASE_NONE, NULL, 0x0, "TRUE if Message Waiting", HFILL }},
354 { &hf_function,
355 { "Function", "uts.function",
356 FT_UINT8, BASE_HEX, NULL, 0, "Function Code value", HFILL }},
357 { &hf_data,
358 { "Data", "uts.data",
359 FT_STRING, BASE_NONE, NULL, 0, "User Data Message", HFILL }},
362 static gint *ett[] = {
363 &ett_uts,
364 &ett_header_uts,
365 &ett_trailer_uts,
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);