Don't guard col_set_str (COL_PROTOCOL) with col_check
[obnox/wireshark/wip.git] / plugins / gryphon / packet-gryphon.c
1 /* packet-gryphon.c
2  * Routines for Gryphon protocol packet disassembly
3  * By Steve Limkemann <stevelim@dgtech.com>
4  * Copyright 1998 Steve Limkemann
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <string.h>
32 #include <ctype.h>
33 #include <time.h>
34
35 #include <glib.h>
36 #include <epan/packet.h>
37 #include "packet-gryphon.h"
38 #include <epan/dissectors/packet-tcp.h>
39 #include <epan/prefs.h>
40
41 /*
42  * See
43  *
44  *      http://www.dgtech.com/gryphon/sys/www/docs/html/
45  */
46
47 static int proto_gryphon = -1;
48
49 static int hf_gryphon_src = -1;
50 static int hf_gryphon_srcchan = -1;
51 static int hf_gryphon_dest = -1;
52 static int hf_gryphon_destchan= -1;
53 static int hf_gryphon_type = -1;
54 static int hf_gryphon_cmd = -1;
55
56 static gint ett_gryphon = -1;
57 static gint ett_gryphon_header = -1;
58 static gint ett_gryphon_body = -1;
59 static gint ett_gryphon_command_data = -1;
60 static gint ett_gryphon_response_data = -1;
61 static gint ett_gryphon_data_header = -1;
62 static gint ett_gryphon_flags = -1;
63 static gint ett_gryphon_data_body = -1;
64 static gint ett_gryphon_cmd_filter_block = -1;
65 static gint ett_gryphon_cmd_events_data = -1;
66 static gint ett_gryphon_cmd_config_device = -1;
67 static gint ett_gryphon_cmd_sched_data = -1;
68 static gint ett_gryphon_cmd_sched_cmd = -1;
69 static gint ett_gryphon_cmd_response_block = -1;
70 static gint ett_gryphon_pgm_list = -1;
71 static gint ett_gryphon_pgm_status = -1;
72 static gint ett_gryphon_pgm_options = -1;
73 static gint ett_gryphon_valid_headers = -1;
74 static gint ett_gryphon_usdt_data = -1;
75 static gint ett_gryphon_digital_data = -1;
76
77 /* desegmentation of Gryphon */
78 static gboolean gryphon_desegment = TRUE;
79
80 static void dissect_gryphon_message(tvbuff_t *tvb, packet_info *pinfo,
81     proto_tree *tree, gboolean is_msgresp_add);
82 static int decode_command(tvbuff_t*, int, int, proto_tree*);
83 static int decode_response(tvbuff_t*, int, int, proto_tree*);
84 static int decode_data(tvbuff_t*, int, proto_tree*);
85 static int decode_event(tvbuff_t*, int, proto_tree*);
86 static int decode_misc(tvbuff_t*, int, proto_tree*);
87 static int cmd_init(tvbuff_t*, int, proto_tree*);
88 static int resp_time(tvbuff_t*, int, proto_tree*);
89 static int cmd_setfilt(tvbuff_t*, int, proto_tree*);
90 static int cmd_ioctl(tvbuff_t*, int, proto_tree*);
91 static int cmd_addfilt(tvbuff_t*, int, proto_tree*);
92 static int resp_addfilt(tvbuff_t*, int, proto_tree*);
93 static int cmd_modfilt(tvbuff_t*, int, proto_tree*);
94 static int resp_filthan(tvbuff_t*, int, proto_tree*);
95 static int dfiltmode(tvbuff_t*, int, proto_tree*);
96 static int filtmode(tvbuff_t*, int, proto_tree*);
97 static int resp_events(tvbuff_t*, int, proto_tree*);
98 static int cmd_register(tvbuff_t*, int, proto_tree*);
99 static int resp_register(tvbuff_t*, int, proto_tree*);
100 static int resp_getspeeds(tvbuff_t*, int, proto_tree*);
101 static int cmd_sort(tvbuff_t*, int, proto_tree*);
102 static int cmd_optimize(tvbuff_t*, int, proto_tree*);
103 static int resp_config(tvbuff_t*, int, proto_tree*);
104 static int cmd_sched(tvbuff_t*, int, proto_tree*);
105 static int cmd_sched_rep(tvbuff_t*, int, proto_tree*);
106 static int resp_blm_data(tvbuff_t*, int, proto_tree*);
107 static int resp_blm_stat(tvbuff_t*, int, proto_tree*);
108 static int cmd_addresp(tvbuff_t*, int, proto_tree*);
109 static int resp_addresp(tvbuff_t*, int, proto_tree*);
110 static int cmd_modresp(tvbuff_t*, int, proto_tree*);
111 static int resp_resphan(tvbuff_t*, int, proto_tree*);
112 static int resp_sched(tvbuff_t*, int, proto_tree*);
113 static int cmd_desc(tvbuff_t*, int, proto_tree*);
114 static int resp_desc(tvbuff_t*, int, proto_tree*);
115 static int cmd_upload(tvbuff_t*, int, proto_tree*);
116 static int cmd_delete(tvbuff_t*, int, proto_tree*);
117 static int cmd_list(tvbuff_t*, int, proto_tree*);
118 static int resp_list(tvbuff_t*, int, proto_tree*);
119 static int cmd_start(tvbuff_t*, int, proto_tree*);
120 static int resp_start(tvbuff_t*, int, proto_tree*);
121 static int resp_status(tvbuff_t*, int, proto_tree*);
122 static int cmd_options(tvbuff_t*, int, proto_tree*);
123 static int cmd_files(tvbuff_t*, int, proto_tree*);
124 static int resp_files(tvbuff_t*, int, proto_tree*);
125 static int eventnum(tvbuff_t*, int, proto_tree*);
126 static int speed(tvbuff_t*, int, proto_tree*);
127 static int filter_block(tvbuff_t*, int, proto_tree*);
128 static int blm_mode(tvbuff_t*, int, proto_tree*);
129 static int cmd_usdt(tvbuff_t*, int, proto_tree*);
130 static int cmd_bits_in(tvbuff_t*, int, proto_tree*);
131 static int cmd_bits_out(tvbuff_t*, int, proto_tree*);
132 static int cmd_init_strat(tvbuff_t*, int, proto_tree*);
133
134 static const char *frame_type[] = {
135         "",
136         "Command request",
137         "Command response",
138         "Network (vehicle) data",
139         "Event",
140         "Miscellaneous",
141         "Text string"
142 };
143
144 /*
145  * Length of the frame header.
146  */
147 #define FRAME_HEADER_LEN        8
148
149 static guint
150 get_gryphon_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
151 {
152     guint16 plen;
153     int padded_len;
154
155     /*
156      * Get the length of the Gryphon packet, and then get the length as
157      * padded to a 4-byte boundary.
158      */
159     plen = tvb_get_ntohs(tvb, offset + 4);
160     padded_len = plen + 3 - (plen + 3) % 4;
161
162     /*
163      * That length doesn't include the fixed-length part of the header;
164      * add that in.
165      */
166     return padded_len + FRAME_HEADER_LEN;
167 }
168
169 static void
170 dissect_gryphon_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
171 {
172     dissect_gryphon_message(tvb, pinfo, tree, FALSE);
173 }
174
175 static void
176 dissect_gryphon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
177 {
178     tcp_dissect_pdus(tvb, pinfo, tree, gryphon_desegment, FRAME_HEADER_LEN,
179         get_gryphon_pdu_len, dissect_gryphon_pdu);
180 }
181
182 static const value_string src_dest[] = {
183     {SD_CARD,           "Card"},
184     {SD_SERVER,         "Server"},
185     {SD_CLIENT,         "Client"},
186     {SD_SCHED,          "Scheduler"},
187     {SD_SCRIPT,         "Script Processor"},
188     {SD_PGM,            "Program Loader"},
189     {SD_USDT,           "USDT Server"},
190     {SD_BLM,            "Bus Load Monitoring"},
191     {SD_FLIGHT,         "Flight Recorder"},
192     {SD_RESP,           "Message Responder"},
193     {SD_IOPWR,          "I/O and power"},
194     {SD_UTIL,           "Utility/Miscellaneous"},
195     {0,                 NULL}
196 };
197
198 static void
199 dissect_gryphon_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
200     gboolean is_msgresp_add)
201 {
202     int             offset = 0;
203     proto_tree      *gryphon_tree;
204     proto_item      *ti;
205     proto_tree      *header_tree, *body_tree, *localTree;
206     proto_item      *header_item, *body_item, *localItem, *hiddenItem;
207     int             start_offset, msgend;
208     int             msglen, msgpad;
209     unsigned int    src, dest, i, frmtyp;
210     guint8          flags;
211
212     if (!is_msgresp_add) {
213         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Gryphon");
214         if (check_col(pinfo->cinfo, COL_INFO))
215             col_clear(pinfo->cinfo, COL_INFO);
216     }
217
218     if (!is_msgresp_add) {
219         ti = proto_tree_add_item(tree, proto_gryphon, tvb, 0, -1, FALSE);
220         gryphon_tree = proto_item_add_subtree(ti, ett_gryphon);
221     } else
222         gryphon_tree = tree;
223
224     src = tvb_get_guint8(tvb, offset + 0);
225     dest = tvb_get_guint8(tvb, offset + 2);
226     msglen = tvb_get_ntohs(tvb, offset + 4);
227     flags = tvb_get_guint8(tvb, offset + 6);
228     frmtyp = flags & ~RESPONSE_FLAGS;
229
230     if (!is_msgresp_add) {
231         /*
232          * This tvbuff includes padding to make its length a multiple
233          * of 4 bytes; set it to the actual length.
234          */
235         set_actual_length(tvb, msglen + FRAME_HEADER_LEN);
236
237         if (check_col(pinfo->cinfo, COL_INFO)) {
238             /*
239              * Indicate what kind of message this is.
240              */
241             if (frmtyp >= SIZEOF (frame_type))
242                 col_set_str(pinfo->cinfo, COL_INFO, "- Invalid -");
243             else
244                 col_set_str(pinfo->cinfo, COL_INFO, frame_type[frmtyp]);
245         }
246     }
247
248     if (tree == NULL)
249         return;
250
251     if (frmtyp >= SIZEOF (frame_type)) {
252         /*
253          * Unknown message type.
254          */
255         proto_tree_add_text(gryphon_tree, tvb, offset, msglen, "Data");
256         return;
257     }
258
259     header_item = proto_tree_add_text(gryphon_tree, tvb, offset, MSG_HDR_SZ, "Header");
260     header_tree = proto_item_add_subtree(header_item, ett_gryphon_header);
261     proto_tree_add_text(header_tree, tvb, offset, 2,
262         "Source: %s, channel %u",
263         val_to_str(src, src_dest, "Unknown (0x%02x)"),
264         tvb_get_guint8(tvb, offset + 1));
265     
266         hiddenItem = proto_tree_add_uint(header_tree, hf_gryphon_src, tvb,
267         offset, 1, src);
268         PROTO_ITEM_SET_HIDDEN(hiddenItem);
269     
270         hiddenItem = proto_tree_add_uint(header_tree, hf_gryphon_srcchan, tvb,
271         offset+1, 1, tvb_get_guint8(tvb, offset + 1));
272         PROTO_ITEM_SET_HIDDEN(hiddenItem);
273
274     proto_tree_add_text(header_tree, tvb, offset+2, 2,
275         "Destination: %s, channel %u",
276         val_to_str(dest, src_dest, "Unknown (0x%02x)"),
277         tvb_get_guint8(tvb, offset + 3));
278     
279         hiddenItem = proto_tree_add_uint(header_tree, hf_gryphon_dest, tvb,
280         offset+2, 1, dest);
281         PROTO_ITEM_SET_HIDDEN(hiddenItem);
282
283     hiddenItem = proto_tree_add_uint(header_tree, hf_gryphon_destchan, tvb,
284         offset+3, 1, tvb_get_guint8(tvb, offset + 3));
285         PROTO_ITEM_SET_HIDDEN(hiddenItem);
286
287     proto_tree_add_text(header_tree, tvb, offset+4, 2,
288         "Data length: %u byte%s", msglen, msglen == 1 ? "" : "s");
289     proto_tree_add_text(header_tree, tvb, offset+6, 1,
290         "Frame type: %s", frame_type[frmtyp]);
291     
292         if (is_msgresp_add) {
293         localItem = proto_tree_add_text(header_tree, tvb, offset+6, 1, "Flags");
294         localTree = proto_item_add_subtree (localItem, ett_gryphon_flags);
295         proto_tree_add_text(localTree, tvb, offset+6, 1, "%s",
296             decode_boolean_bitfield(flags, DONT_WAIT_FOR_RESP, 8,
297                 "Don't wait for response",
298                 "Wait for response"));
299         proto_tree_add_text(localTree, tvb, offset+6, 1, "%s",
300             decode_boolean_bitfield(flags, WAIT_FOR_PREV_RESP, 8,
301                 "Wait for previous responses",
302                 "Don't wait for previous responses"));
303     }
304     proto_tree_add_text(header_tree, tvb, offset+7, 1, "reserved");
305
306     hiddenItem = proto_tree_add_uint(header_tree, hf_gryphon_type, tvb,
307         offset+6, 1, frmtyp);
308         PROTO_ITEM_SET_HIDDEN(hiddenItem);
309
310     msgpad = 3 - (msglen + 3) % 4;
311     msgend = offset + msglen + msgpad + MSG_HDR_SZ;
312
313     body_item = proto_tree_add_text(gryphon_tree, tvb, offset + MSG_HDR_SZ,
314         msglen + msgpad, "Body");
315     body_tree = proto_item_add_subtree(body_item, ett_gryphon_body);
316
317     start_offset = offset;
318     offset += MSG_HDR_SZ;
319     switch (frmtyp) {
320     case GY_FT_CMD:
321         offset = decode_command(tvb, offset, dest, body_tree);
322         break;
323     case GY_FT_RESP:
324         offset = decode_response(tvb, offset, src, body_tree);
325         break;
326     case GY_FT_DATA:
327         offset = decode_data(tvb, offset, body_tree);
328         break;
329     case GY_FT_EVENT:
330         offset = decode_event(tvb, offset, body_tree);
331         break;
332     case GY_FT_MISC:
333         offset = decode_misc (tvb, offset, body_tree);
334         break;
335     case GY_FT_TEXT:
336         break;
337     default:
338         break;
339     }
340     if (offset < msgend - msgpad) {
341         i = msgend - msgpad - offset;
342         proto_tree_add_text(gryphon_tree, tvb, offset, i, "Data");
343         offset += i;
344     }
345     if (offset < msgend) {
346         i = msgend - offset;
347         proto_tree_add_text(gryphon_tree, tvb, offset, i, "padding");
348         offset += i;
349     }
350 }
351
352
353 static const val_str_dsp cmds[] = {
354         {CMD_INIT,              "Initialize", cmd_init, NULL},
355         {CMD_GET_STAT,          "Get status", NULL, NULL},
356         {CMD_GET_CONFIG,        "Get configuration", NULL, resp_config},
357         {CMD_EVENT_ENABLE,      "Enable event", eventnum, NULL},
358         {CMD_EVENT_DISABLE,     "Disable event", eventnum, NULL},
359         {CMD_GET_TIME,          "Get time", NULL, resp_time},
360         {CMD_SET_TIME,          "Set time", resp_time, NULL},
361         {CMD_GET_RXDROP,        "Get number of dropped RX messages", NULL, NULL},
362         {CMD_RESET_RXDROP,      "Clear number of dropped RX messages", NULL, NULL},
363         {CMD_BCAST_ON,          "Set broadcasts on", NULL, NULL},
364         {CMD_BCAST_OFF,         "Set broadcasts off", NULL, NULL},
365         {CMD_CARD_SET_SPEED,    "Set channel baud rate", speed, NULL},
366         {CMD_CARD_GET_SPEED,    "Get channel baud rate", NULL, speed},
367         {CMD_CARD_SET_FILTER,   "Set filter (deprecated)", cmd_setfilt, NULL},
368         {CMD_CARD_GET_FILTER,   "Get filter", resp_addfilt, cmd_addfilt},
369         {CMD_CARD_TX,           "Transmit message", decode_data, NULL},
370         {CMD_CARD_TX_LOOP_ON,   "Set transmit loopback on", NULL, NULL},
371         {CMD_CARD_TX_LOOP_OFF,  "Set transmit loopback off", NULL, NULL},
372         {CMD_CARD_IOCTL,        "IOCTL pass-through", cmd_ioctl, NULL},
373         {CMD_CARD_ADD_FILTER,   "Add a filter", cmd_addfilt, resp_addfilt},
374         {CMD_CARD_MODIFY_FILTER, "Modify a filter", cmd_modfilt, NULL},
375         {CMD_CARD_GET_FILTER_HANDLES, "Get filter handles", NULL, resp_filthan},
376         {CMD_CARD_SET_DEFAULT_FILTER, "Set default filter", dfiltmode, NULL},
377         {CMD_CARD_GET_DEFAULT_FILTER, "Get default filter mode", NULL, dfiltmode},
378         {CMD_CARD_SET_FILTER_MODE, "Set filter mode", filtmode, NULL},
379         {CMD_CARD_GET_FILTER_MODE, "Get filter mode", NULL, filtmode},
380         {CMD_CARD_GET_EVNAMES,  "Get event names", NULL, resp_events},
381         {CMD_CARD_GET_SPEEDS,   "Get defined speeds", NULL, resp_getspeeds},
382         {CMD_SERVER_REG,        "Register with server", cmd_register, resp_register},
383         {CMD_SERVER_SET_SORT,   "Set the sorting behavior", cmd_sort, NULL},
384         {CMD_SERVER_SET_OPT,    "Set the type of optimization", cmd_optimize, NULL},
385         {CMD_BLM_SET_MODE,      "Set Bus Load Monitoring mode", blm_mode, NULL},
386         {CMD_BLM_GET_MODE,      "Get Bus Load Monitoring mode", NULL, blm_mode},
387         {CMD_BLM_GET_DATA,      "Get Bus Load data", NULL, resp_blm_data},
388         {CMD_BLM_GET_STATS,     "Get Bus Load statistics", NULL, resp_blm_stat},
389         {CMD_FLIGHT_GET_CONFIG, "Get flight recorder channel info", NULL, NULL},
390         {CMD_FLIGHT_START_MON,  "Start flight recorder monitoring", NULL, NULL},
391         {CMD_FLIGHT_STOP_MON,   "Stop flight recorder monitoring", NULL, NULL},
392         {CMD_MSGRESP_ADD,       "Add response message", cmd_addresp, resp_addresp},
393         {CMD_MSGRESP_GET,       "Get response message", resp_addresp, cmd_addresp},
394         {CMD_MSGRESP_MODIFY,    "Modify response message state", cmd_modresp, NULL},
395         {CMD_MSGRESP_GET_HANDLES, "Get response message handles", NULL, resp_resphan},
396         {CMD_PGM_DESC,          "Describe program to to uploaded", cmd_desc, resp_desc},
397         {CMD_PGM_UPLOAD,        "Upload a program to the Gryphon", cmd_upload, NULL},
398         {CMD_PGM_DELETE,        "Delete an uploaded program", cmd_delete, NULL},
399         {CMD_PGM_LIST,          "Get a list of uploaded programs", cmd_list, resp_list},
400         {CMD_PGM_START,         "Start an uploaded program", cmd_start, resp_start},
401         {CMD_PGM_START2,        "Start an uploaded program", NULL, resp_start},
402         {CMD_PGM_STOP,          "Stop an uploaded program", resp_start, NULL},
403         {CMD_PGM_STATUS,        "Get status of an uploaded program", cmd_delete, resp_status},
404         {CMD_PGM_OPTIONS,       "Set program upload options", cmd_options, resp_status},
405         {CMD_PGM_FILES,         "Get a list of files & directories", cmd_files, resp_files},
406         {CMD_SCHED_TX,          "Schedule transmission of messages", cmd_sched, resp_sched},
407         {CMD_SCHED_KILL_TX,     "Stop and destroy a message transmission", resp_sched, NULL},
408         {CMD_SCHED_STOP_TX,     "Kill a message transmission (deprecated)", resp_sched, NULL},
409         {CMD_SCHED_MSG_REPLACE, "Replace a scheduled message", cmd_sched_rep, NULL},
410         {CMD_USDT_IOCTL,        "Register/Unregister with USDT server", cmd_usdt, NULL},
411         {CMD_USDT_REGISTER,     "Register/Unregister with USDT server", cmd_usdt, NULL},
412         {CMD_USDT_SET_FUNCTIONAL, "Set IDs to use extended addressing", cmd_usdt, NULL},
413         {CMD_IOPWR_GETINP,      "Read current digital inputs", NULL, cmd_bits_in},
414         {CMD_IOPWR_GETLATCH,    "Read latched digital inputs", NULL, cmd_bits_in},
415         {CMD_IOPWR_CLRLATCH,    "Read & clear latched digital inputs", cmd_bits_in, cmd_bits_in},
416         {CMD_IOPWR_GETOUT,      "Read digital outputs", NULL, cmd_bits_out},
417         {CMD_IOPWR_SETOUT,      "Write digital outputs", cmd_bits_out, NULL},
418         {CMD_IOPWR_SETBIT,      "Set indicated output bits", cmd_bits_out, NULL},
419         {CMD_IOPWR_CLRBIT,      "Clear indicated output bits", cmd_bits_out, NULL},
420         {CMD_IOPWR_GETPOWER,    "Read digital inputs at power on time", NULL, cmd_bits_in},
421         {CMD_UTIL_SET_INIT_STRATEGY, "Set initialization strategy", cmd_init_strat, NULL},
422         {CMD_UTIL_GET_INIT_STRATEGY, "Get initialization strategy", NULL, cmd_init_strat},
423         {-1,                    "- unknown -", NULL, NULL},
424         };
425
426 static const value_string responses[] = {
427         {RESP_OK,               "OK - no error"},
428         {RESP_UNKNOWN_ERR,      "Unknown error"},
429         {RESP_UNKNOWN_CMD,      "Unrecognised command"},
430         {RESP_UNSUPPORTED,      "Unsupported command"},
431         {RESP_INVAL_CHAN,       "Invalid channel specified"},
432         {RESP_INVAL_DST,        "Invalid destination"},
433         {RESP_INVAL_PARAM,      "Invalid parameter(s)"},
434         {RESP_INVAL_MSG,        "Invalid message"},
435         {RESP_INVAL_LEN,        "Invalid length field"},
436         {RESP_TX_FAIL,          "Transmit failed"},
437         {RESP_RX_FAIL,          "Receive failed"},
438         {RESP_AUTH_FAIL,        "Authorization failed"},
439         {RESP_MEM_ALLOC_ERR,    "Memory allocation error"},
440         {RESP_TIMEOUT,          "Command timed out"},
441         {RESP_UNAVAILABLE,      "Unavailable"},
442         {RESP_BUF_FULL,         "Buffer full"},
443         {RESP_NO_SUCH_JOB,      "No such job"},
444         {0,                     NULL},
445         };
446
447 static const value_string filter_data_types[] = {
448         {FILTER_DATA_TYPE_HEADER_FRAME, "frame header"},
449         {FILTER_DATA_TYPE_HEADER,       "data message header"},
450         {FILTER_DATA_TYPE_DATA,         "data message data"},
451         {FILTER_DATA_TYPE_EXTRA_DATA,   "data message extra data"},
452         {FILTER_EVENT_TYPE_HEADER,      "event message header"},
453         {FILTER_EVENT_TYPE_DATA,        "event message"},
454         {0,                             NULL},
455         };
456
457 static const value_string operators[] = {
458         {BIT_FIELD_CHECK,       "Bit field check"},
459         {SVALUE_GT,             "Greater than (signed)"},
460         {SVALUE_GE,             "Greater than or equal to (signed)"},
461         {SVALUE_LT,             "Less than (signed)"},
462         {SVALUE_LE,             "Less than or equal to (signed)"},
463         {VALUE_EQ,              "Equal to"},
464         {VALUE_NE,              "Not equal to"},
465         {UVALUE_GT,             "Greater than (unsigned)"},
466         {UVALUE_GE,             "Greater than or equal to (unsigned)"},
467         {UVALUE_LT,             "Less than (unsigned)"},
468         {UVALUE_LE,             "Less than or equal to (unsigned)"},
469         {DIG_LOW_TO_HIGH,       "Digital, low to high transistion"},
470         {DIG_HIGH_TO_LOW,       "Digital, high to low transistion"},
471         {DIG_TRANSITION,        "Digital, change of state"},
472         {0,                     NULL},
473         };
474
475 static const value_string modes[] = {
476         {FILTER_OFF_PASS_ALL,   "Filter off, pass all messages"},
477         {FILTER_OFF_BLOCK_ALL,  "Filter off, block all messages"},
478         {FILTER_ON,             "Filter on"},
479         {0,                     NULL},
480         };
481
482 static const value_string dmodes[] = {
483         {DEFAULT_FILTER_BLOCK,  "Block"},
484         {DEFAULT_FILTER_PASS,   "Pass"},
485         {0,                     NULL},
486         };
487
488 static const value_string filtacts[] = {
489         {DELETE_FILTER,         "Delete"},
490         {ACTIVATE_FILTER,       "Activate"},
491         {DEACTIVATE_FILTER,     "Deactivate"},
492         {0,                     NULL},
493         };
494
495 static const value_string ioctls[] = {
496         {GINIT,                 "GINIT: Initialize"},
497         {GLOOPON,               "GLOOPON: Loop on"},
498         {GLOOPOFF,              "GLOOPOFF: Loop off"},
499         {GGETHWTYPE,            "GGETHWTYPE: Get hardware type"},
500         {GGETREG,               "GGETREG: Get register"},
501         {GSETREG,               "GSETREG: Set register"},
502         {GGETRXCOUNT,           "GGETRXCOUNT: Get the receive message counter"},
503         {GSETRXCOUNT,           "GSETRXCOUNT: Set the receive message counter"},
504         {GGETTXCOUNT,           "GGETTXCOUNT: Get the transmit message counter"},
505         {GSETTXCOUNT,           "GSETTXCOUNT: Set the transmit message counter"},
506         {GGETRXDROP,            "GGETRXDROP: Get the number of dropped receive messages"},
507         {GSETRXDROP,            "GSETRXDROP: Set the number of dropped receive messages"},
508         {GGETTXDROP,            "GGETTXDROP: Get the number of dropped transmit messages"},
509         {GSETTXDROP,            "GSETTXDROP: Set the number of dropped transmit messages"},
510         {GGETRXBAD,             "GGETRXBAD: Get the number of bad receive messages"},
511         {GGETTXBAD,             "GGETTXBAD: Get the number of bad transmit messages"},
512         {GGETCOUNTS,            "GGETCOUNTS: Get total message counter"},
513         {GGETBLMON,             "GGETBLMON: Get bus load monitoring status"},
514         {GSETBLMON,             "GSETBLMON: Set bus load monitoring status (turn on/off)"},
515         {GGETERRLEV,            "GGETERRLEV: Get error level"},
516         {GSETERRLEV,            "GSETERRLEV: Set error level"},
517         {GGETBITRATE,           "GGETBITRATE: Get bit rate"},
518         {GGETRAM,               "GGETRAM: Read value from RAM"},
519         {GSETRAM,               "GSETRAM: Write value to RAM"},
520         {GCANGETBTRS,           "GCANGETBTRS: Read CAN bit timing registers"},
521         {GCANSETBTRS,           "GCANSETBTRS: Write CAN bit timing registers"},
522         {GCANGETBC,             "GCANGETBC: Read CAN bus configuration register"},
523         {GCANSETBC,             "GCANSETBC: Write CAN bus configuration register"},
524         {GCANGETMODE,           "GCANGETMODE"},
525         {GCANSETMODE,           "GCANSETMODE"},
526         {GCANGETTRANS,          "GCANGETTRANS"},
527         {GCANSETTRANS,          "GCANSETTRANS"},
528         {GCANSENDERR,           "GCANSENDERR"},
529         {GCANRGETOBJ,           "GCANRGETOBJ"},
530         {GCANRSETSTDID,         "GCANRSETSTDID"},
531         {GCANRSETEXTID,         "GCANRSETEXTID"},
532         {GCANRSETDATA,          "GCANRSETDATA"},
533         {GCANRENABLE,           "GCANRENABLE"},
534         {GCANRDISABLE,          "GCANRDISABLE"},
535         {GCANRGETMASKS,         "GCANRGETMASKS"},
536         {GCANRSETMASKS,         "GCANRSETMASKS"},
537         {GCANSWGETMODE,         "GCANSWGETMODE"},
538         {GCANSWSETMODE,         "GCANSWSETMODE"},
539         {GDLCGETFOURX,          "GDLCGETFOURX"},
540         {GDLCSETFOURX,          "GDLCSETFOURX"},
541         {GDLCGETLOAD,           "GDLCGETLOAD"},
542         {GDLCSETLOAD,           "GDLCSETLOAD"},
543         {GDLCSENDBREAK,         "GDLCSENDBREAK"},
544         {GDLCABORTTX,           "GDLCABORTTX"},
545         {GDLCGETHDRMODE,        "DLCGETHDRMODE"},
546         {GDLCSETHDRMODE,        "GDLCSETHDRMODE"},
547         {GHONSLEEP,             "GHONSLEEP"},
548         {GHONSILENCE,           "GHONSILENCE"},
549         {GKWPSETPTIMES,         "GKWPSETPTIMES"},
550         {GKWPSETWTIMES,         "GKWPSETWTIMES"},
551         {GKWPDOWAKEUP,          "GKWPDOWAKEUP"},
552         {GKWPGETBITTIME,        "GKWPGETBITTIME"},
553         {GKWPSETBITTIME,        "GKWPSETBITTIME"},
554         {GKWPSETNODEADDR,       "GKWPSETNODEADDR"},
555         {GKWPGETNODETYPE,       "GKWPGETNODETYPE"},
556         {GKWPSETNODETYPE,       "GKWPSETNODETYPE"},
557         {GKWPSETWAKETYPE,       "GKWPSETWAKETYPE"},
558         {GKWPSETTARGADDR,       "GKWPSETTARGADDR"},
559         {GKWPSETKEYBYTES,       "GKWPSETKEYBYTES"},
560         {GKWPSETSTARTREQ,       "GKWPSETSTARTREQ"},
561         {GKWPSETSTARTRESP,      "GKWPSETSTARTRESP"},
562         {GKWPSETPROTOCOL,       "GKWPSETPROTOCOL"},
563         {GKWPGETLASTKEYBYTES,   "GKWPGETLASTKEYBYTES"},
564         {GKWPSETLASTKEYBYTES,   "GKWPSETLASTKEYBYTES"},
565         {GSCPGETBBR,            "GSCPGETBBR"},
566         {GSCPSETBBR,            "GSCPSETBBR"},
567         {GSCPGETID,             "GSCPGETID"},
568         {GSCPSETID,             "GSCPSETID"},
569         {GSCPADDFUNCID,         "GSCPADDFUNCID"},
570         {GSCPCLRFUNCID,         "GSCPCLRFUNCID"},
571         {GUBPGETBITRATE,        "GUBPGETBITRATE"},
572         {GUBPSETBITRATE,        "GUBPSETBITRATE"},
573         {GUBPGETINTERBYTE,      "GUBPGETINTERBYTE"},
574         {GUBPSETINTERBYTE,      "GUBPSETINTERBYTE"},
575         {GUBPGETNACKMODE,       "GUBPGETNACKMODE"},
576         {GUBPSETNACKMODE,       "GUBPSETNACKMODE"},
577         {GUBPGETRETRYDELAY,     "GUBPGETRETRYDELAY"},
578         {GUBPSETRETRYDELAY,     "GUBPSETRETRYDELAY"},
579         {GRESETHC08,            "GRESETHC08: Reset the HC08 processor"},
580         {GTESTHC08COP,          "GTESTHC08COP: Stop updating the HC08 watchdog timer"},
581         {GSJAGETLISTEN,         "GSJAGETLISTEN"},
582         {GSJASETLISTEN,         "GSJASETLISTEN"},
583         {GSJAGETSELFTEST,       "GSJAGETSELFTEST"},
584         {GSJASETSELFTEST,       "GSJASETSELFTEST"},
585         {GSJAGETXMITONCE,       "GSJAGETXMITONCE"},
586         {GSJASETXMITONCE,       "GSJASETXMITONCE"},
587         {GSJAGETTRIGSTATE,      "GSJAGETTRIGSTATE"},
588         {GSJASETTRIGCTRL,       "GSJASETTRIGCTRL"},
589         {GSJAGETTRIGCTRL,       "GSJAGETTRIGCTRL"},
590         {GSJAGETOUTSTATE,       "GSJAGETOUTSTATE"},
591         {GSJASETOUTSTATE,       "GSJASETOUTSTATE"},
592         {GSJAGETFILTER,         "GSJAGETFILTER"},
593         {GSJASETFILTER,         "GSJASETFILTER"},
594         {GSJAGETMASK,           "GSJAGETMASK"},
595         {GSJASETMASK,           "GSJASETMASK"},
596         {GSJAGETINTTERM,        "GSJAGETINTTERM"},
597         {GSJASETINTTERM,        "GSJASETINTTERM"},
598         {GSJAGETFTTRANS,        "GSJAGETFTTRANS"},
599         {GSJASETFTTRANS,        "GSJASETFTTRANS"},
600         {GSJAGETFTERROR,        "GSJAGETFTERROR"},
601         {GLINGETBITRATE,        "GLINGETBITRATE: Get the current bit rate"},
602         {GLINSETBITRATE,        "GLINSETBITRATE: Set the bit rate"},
603         {GLINGETBRKSPACE,       "GLINGETBRKSPACE"},
604         {GLINSETBRKSPACE,       "GLINSETBRKSPACE"},
605         {GLINGETBRKMARK,        "GLINGETBRKMARK"},
606         {GLINSETBRKMARK,        "GLINSETBRKMARK"},
607         {GLINGETIDDELAY,        "GLINGETIDDELAY"},
608         {GLINSETIDDELAY,        "GLINSETIDDELAY"},
609         {GLINGETRESPDELAY,      "GLINGETRESPDELAY"},
610         {GLINSETRESPDELAY,      "GLINSETRESPDELAY"},
611         {GLINGETINTERBYTE,      "GLINGETINTERBYTE"},
612         {GLINSETINTERBYTE,      "GLINSETINTERBYTE"},
613         {GLINGETWAKEUPDELAY,    "GLINGETWAKEUPDELAY"},
614         {GLINSETWAKEUPDELAY,    "GLINSETWAKEUPDELAY"},
615         {GLINGETWAKEUPTIMEOUT,  "GLINGETWAKEUPTIMEOUT"},
616         {GLINSETWAKEUPTIMEOUT,  "GLINSETWAKEUPTIMEOUT"},
617         {GLINGETWUTIMOUT3BR,    "GLINGETWUTIMOUT3BR"},
618         {GLINSETWUTIMOUT3BR,    "GLINSETWUTIMOUT3BR"},
619         {GLINSENDWAKEUP,        "GLINSENDWAKEUP"},
620         {GLINGETMODE,           "GLINGETMODE"},
621         {GLINSETMODE,           "GLINSETMODE"},
622         {GINPGETINP,            "GINPGETINP: Read current digital inputs"},
623         {GINPGETLATCH,          "GINPGETLATCH: Read latched digital inputs"},
624         {GINPCLRLATCH,          "GINPCLRLATCH: Read and clear latched digital inputs"},
625         {GOUTGET,               "GOUTGET: Read digital outputs"},
626         {GOUTSET,               "GOUTSET: Write digital outputs"},
627         {GOUTSETBIT,            "GOUTSETBIT: Set digital output bits"},
628         {GOUTCLEARBIT,          "GOUTCLEARBIT"},
629         {GPWRGETWHICH,          "GPWRGETWHICH"},
630         {GPWROFF,               "GPWROFF"},
631         {GPWROFFRESET,          "GPWROFFRESET"},
632         {GPWRRESET,             "GPWRRESET"},
633
634
635
636         {0,                     NULL},
637         };
638
639
640 static int
641 decode_command(tvbuff_t *tvb, int offset, int dst, proto_tree *pt)
642 {
643     int             cmd, padding, msglen;
644     unsigned int    i;
645     proto_tree      *ft;
646     proto_item      *ti;
647     proto_item      *hi;
648
649     msglen = tvb_reported_length_remaining(tvb, offset);
650     cmd = tvb_get_guint8(tvb, offset);
651     hi = proto_tree_add_uint(pt, hf_gryphon_cmd, tvb, offset, 1, cmd);
652         PROTO_ITEM_SET_HIDDEN(hi);
653     if (cmd > 0x3F)
654         cmd += dst * 256;
655
656     for (i = 0; i < SIZEOF(cmds); i++) {
657         if (cmds[i].value == cmd)
658             break;
659     }
660     if (i >= SIZEOF(cmds) && dst >= SD_KNOWN) {
661         cmd = (cmd & 0xFF) + SD_CARD * 256;
662         for (i = 0; i < SIZEOF(cmds); i++) {
663             if (cmds[i].value == cmd)
664                 break;
665         }
666     }
667     if (i >= SIZEOF(cmds))
668         i = SIZEOF(cmds) - 1;
669
670     proto_tree_add_text (pt, tvb, offset, 4, "Command: %s", cmds[i].strptr);
671     offset += 4;
672     msglen -= 4;
673
674     if (cmds[i].cmd_fnct && msglen > 0) {
675         padding = 3 - (msglen + 3) % 4;
676         ti = proto_tree_add_text(pt, tvb, offset, -1, "Data: (%d byte%s)",
677                 msglen, msglen == 1 ? "" : "s");
678         ft = proto_item_add_subtree(ti, ett_gryphon_command_data);
679         offset = (*(cmds[i].cmd_fnct)) (tvb, offset, ft);
680     }
681     return offset;
682 }
683
684 static int
685 decode_response(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
686 {
687     int             cmd, msglen;
688     unsigned int    i, resp;
689     proto_tree      *ft;
690     proto_item      *ti;
691
692     msglen = tvb_reported_length_remaining(tvb, offset);
693     cmd = tvb_get_guint8(tvb, offset);
694     if (cmd > 0x3F)
695         cmd += src * 256;
696
697     for (i = 0; i < SIZEOF(cmds); i++) {
698         if (cmds[i].value == cmd)
699             break;
700     }
701     if (i >= SIZEOF(cmds) && src >= SD_KNOWN) {
702         cmd = (cmd & 0xFF) + SD_CARD * 256;
703         for (i = 0; i < SIZEOF(cmds); i++) {
704             if (cmds[i].value == cmd)
705                 break;
706         }
707     }
708     if (i >= SIZEOF(cmds))
709         i = SIZEOF(cmds) - 1;
710     proto_tree_add_text (pt, tvb, offset, 4, "Command: %s", cmds[i].strptr);
711     offset += 4;
712     msglen -= 4;
713
714     resp = tvb_get_ntohl (tvb, offset);
715     proto_tree_add_text (pt, tvb, offset, 4, "Status: %s",
716         val_to_str(resp, responses, "Unknown (0x%08x)"));
717     offset += 4;
718     msglen -= 4;
719
720     if (cmds[i].rsp_fnct && msglen > 0) {
721         ti = proto_tree_add_text(pt, tvb, offset, msglen, "Data: (%d byte%s)",
722                 msglen, msglen == 1 ? "" : "s");
723         ft = proto_item_add_subtree(ti, ett_gryphon_response_data);
724         offset = (*(cmds[i].rsp_fnct)) (tvb, offset, ft);
725     }
726     return offset;
727 }
728
729 static int
730 decode_data(tvbuff_t *tvb, int offset, proto_tree *pt)
731 {
732     proto_item  *item, *item1;
733     proto_tree  *tree, *tree1;
734     int     hdrsize, datasize, extrasize, hdrbits, msgsize, padding, mode;
735     int     hours, minutes, seconds, fraction;
736     unsigned long   timestamp;
737
738     hdrsize = tvb_get_guint8(tvb, offset+0);
739     hdrbits = tvb_get_guint8(tvb, offset+1);
740     datasize = tvb_get_ntohs(tvb, offset+2);
741     extrasize = tvb_get_guint8(tvb, offset+4);
742     padding = 3 - (hdrsize + datasize + extrasize + 3) % 4;
743     msgsize = hdrsize + datasize + extrasize + padding + 16;
744
745     item = proto_tree_add_text(pt, tvb, offset, 16, "Message header");
746     tree = proto_item_add_subtree (item, ett_gryphon_data_header);
747     proto_tree_add_text(tree, tvb, offset, 2, "Header length: %d byte%s, %d bits",
748             hdrsize, plurality(hdrsize, "", "s"), hdrbits);
749     proto_tree_add_text(tree, tvb, offset+2, 2, "Data length: %d byte%s",
750             datasize, plurality(datasize, "", "s"));
751     proto_tree_add_text(tree, tvb, offset+4, 1, "Extra data length: %d byte%s",
752             extrasize, plurality(extrasize, "", "s"));
753     mode = tvb_get_guint8(tvb, offset+5);
754     item1 = proto_tree_add_text(tree, tvb, offset+5, 1, "Mode: %d", mode);
755     if (mode) {
756         tree1 = proto_item_add_subtree (item1, ett_gryphon_flags);
757         if (mode & 0x80) {
758             proto_tree_add_text(tree1, tvb, offset+5, 1, "%s",
759                 decode_boolean_bitfield(mode, 0x80, 8,
760                     "Transmitted message", NULL));
761         }
762         if (mode & 0x40) {
763             proto_tree_add_text(tree1, tvb, offset+5, 1, "%s",
764                 decode_boolean_bitfield(mode, 0x40, 8,
765                     "Received message", NULL));
766         }
767         if (mode & 0x20) {
768             proto_tree_add_text(tree1, tvb, offset+5, 1, "%s",
769                 decode_boolean_bitfield(mode, 0x20, 8,
770                     "Local message", NULL));
771         }
772         if (mode & 0x10) {
773             proto_tree_add_text(tree1, tvb, offset+5, 1, "%s",
774                 decode_boolean_bitfield(mode, 0x10, 8,
775                     "Remote message", NULL));
776         }
777         if (mode & 0x01) {
778             proto_tree_add_text(tree1, tvb, offset+5, 1, "%s",
779                 decode_boolean_bitfield(mode, 0x01, 8,
780                     "Internal message", NULL));
781         }
782     }
783     proto_tree_add_text(tree, tvb, offset+6, 1, "Priority: %u",
784         tvb_get_guint8(tvb, offset+6));
785     proto_tree_add_text(tree, tvb, offset+7, 1, "Error status: %u",
786         tvb_get_guint8(tvb, offset+7));
787     timestamp = tvb_get_ntohl(tvb, offset+8);
788     hours = timestamp /(100000 * 60 *60);
789     minutes = (timestamp / (100000 * 60)) % 60;
790     seconds = (timestamp / 100000) % 60;
791     fraction = timestamp % 100000;
792     proto_tree_add_text(tree, tvb, offset+8, 4, "Timestamp: %d:%02d:%02d.%05d", hours, minutes, seconds, fraction);
793     proto_tree_add_text(tree, tvb, offset+12, 1, "Context: %u",
794         tvb_get_guint8(tvb, offset+12));
795     proto_tree_add_text(tree, tvb, offset+13, 3, "reserved:");
796     offset += 16;
797     item = proto_tree_add_text(pt, tvb, offset, msgsize-16-padding, "Message Body");
798     tree = proto_item_add_subtree (item, ett_gryphon_data_body);
799     if (hdrsize) {
800         proto_tree_add_text(tree, tvb, offset, hdrsize, "Header");
801         offset += hdrsize;
802     }
803     if (datasize) {
804         proto_tree_add_text(tree, tvb, offset, datasize, "Data");
805         offset += datasize;
806     }
807     if (extrasize) {
808         proto_tree_add_text(tree, tvb, offset, extrasize, "Extra data");
809         offset += extrasize;
810     }
811     if (padding) {
812         proto_tree_add_text(pt, tvb, offset, padding, "padding");
813         offset += padding;
814     }
815     return offset;
816 }
817
818 static int
819 decode_event(tvbuff_t *tvb, int offset, proto_tree *pt)
820 {
821     int             msglen;
822     int             hours, minutes, seconds, fraction, padding, length;
823     unsigned long   timestamp;
824     int             msgend;
825
826     msglen = tvb_reported_length_remaining(tvb, offset);
827     padding = 3 - (msglen + 3) % 4;
828     msgend = offset + msglen;
829     proto_tree_add_text(pt, tvb, offset, 1, "Event ID: %u",
830         tvb_get_guint8(tvb, offset));
831     proto_tree_add_text(pt, tvb, offset+1, 1, "Event context: %u",
832         tvb_get_guint8(tvb, offset+1));
833     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
834     offset += 4;
835     timestamp = tvb_get_ntohl(tvb, offset);
836     hours = timestamp /(100000 * 60 *60);
837     minutes = (timestamp / (100000 * 60)) % 60;
838     seconds = (timestamp / 100000) % 60;
839     fraction = timestamp % 100000;
840     proto_tree_add_text(pt, tvb, offset, 4, "Timestamp: %d:%02d:%02d.%05d", hours, minutes, seconds, fraction);
841     offset += 4;
842     if (offset < msgend) {
843         length = msgend - offset;
844         proto_tree_add_text (pt, tvb, offset, length, "Data (%d byte%s)",
845                 length, length == 1 ? "" : "s");
846         offset += length;
847     }
848     if (padding) {
849         proto_tree_add_text(pt, tvb, offset, padding, "padding");
850         offset += padding;
851     }
852     return offset;
853 }
854
855 static int
856 decode_misc (tvbuff_t *tvb, int offset, proto_tree *pt)
857 {
858     #define         LENGTH 120
859     int             padding, msglen;
860     gint            length;
861     unsigned char   local_data[LENGTH+1];
862
863     msglen = tvb_reported_length_remaining(tvb, offset);
864     padding = 3 - (msglen + 3) % 4;
865     length = tvb_get_nstringz0(tvb, offset, LENGTH, local_data);
866     proto_tree_add_text(pt, tvb, offset, msglen, "Data: %s", local_data);
867     offset += msglen;
868     if (padding) {
869         proto_tree_add_text (pt, tvb, offset, padding, "padding");
870         offset += padding;
871     }
872     return offset;
873 }
874
875 static int
876 cmd_init(tvbuff_t *tvb, int offset, proto_tree *pt)
877 {
878     const char          *ptr;
879
880     if (tvb_get_guint8(tvb, offset) == 0)
881         ptr = "Always initialize";
882     else
883         ptr = "Initialize if not previously initialized";
884     proto_tree_add_text(pt, tvb, offset, 1, "Mode: %s", ptr);
885     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
886     offset += 4;
887     return offset;
888 }
889
890 static int
891 eventnum(tvbuff_t *tvb, int offset, proto_tree *pt)
892 {
893     guint8      event = tvb_get_guint8(tvb, offset);
894
895     if (event)
896         proto_tree_add_text(pt, tvb, offset, 1, "Event number: %u", event);
897     else
898         proto_tree_add_text(pt, tvb, offset, 1, "Event numbers: All");
899     proto_tree_add_text(pt, tvb, offset+1, 3, "padding");
900     offset += 4;
901     return offset;
902 }
903
904 static int
905 resp_time(tvbuff_t *tvb, int offset, proto_tree *pt)
906 {
907     guint64 ts;
908     time_t  timestamp;
909     struct tm *tmp;
910     static const char *mon_names[12] = {
911         "Jan",
912         "Feb",
913         "Mar",
914         "Apr",
915         "May",
916         "Jun",
917         "Jul",
918         "Aug",
919         "Sep",
920         "Oct",
921         "Nov",
922         "Dec"
923     };
924
925     ts = tvb_get_ntoh64(tvb, offset);
926     timestamp = (time_t) (ts / 100000);
927     tmp = localtime(&timestamp);
928     proto_tree_add_text(pt, tvb, offset, 8,
929         "Date/Time: %s %d, %d %02d:%02d:%02d.%05u",
930         mon_names[tmp->tm_mon],
931         tmp->tm_mday,
932         tmp->tm_year + 1900,
933         tmp->tm_hour,
934         tmp->tm_min,
935         tmp->tm_sec,
936         (guint) (ts % 100000));
937     offset += 8;
938     return offset;
939 }
940
941 static int
942 cmd_setfilt(tvbuff_t *tvb, int offset, proto_tree *pt)
943 {
944     int             flag = tvb_get_ntohl(tvb, offset);
945     int             length, padding;
946     char   mode[30];
947
948     length =  tvb_get_guint8(tvb, offset+4) + tvb_get_guint8(tvb, offset+5)
949         + tvb_get_ntohs(tvb, offset+6);
950     if (flag)
951        g_strlcpy (mode, "Pass", 30);
952     else
953        g_strlcpy (mode, "Block", 30);
954     if (length == 0)
955        g_strlcat (mode, " all", 30);
956     proto_tree_add_text(pt, tvb, offset, 4, "Pass/Block flag: %s", mode);
957     proto_tree_add_text(pt, tvb, offset+4, 4, "Length of Pattern & Mask: %d", length);
958     offset += 8;
959     if (length) {
960         proto_tree_add_text(pt, tvb, offset, length * 2, "discarded data");
961         offset += length * 2;
962     }
963     padding = 3 - (length * 2 + 3) % 4;
964     if (padding) {
965         proto_tree_add_text(pt, tvb, offset+1, 3, "padding");
966         offset += padding;
967     }
968     return offset;
969 }
970
971 static int
972 cmd_ioctl(tvbuff_t *tvb, int offset, proto_tree *pt)
973 {
974     int             msglen;
975     unsigned int    ioctl;
976
977     msglen = tvb_reported_length_remaining(tvb, offset);
978     ioctl = tvb_get_ntohl(tvb, offset);
979     proto_tree_add_text(pt, tvb, offset, 4, "IOCTL: %s",
980         val_to_str(ioctl, ioctls, "Unknown (0x%08x)"));
981     offset += 4;
982     msglen -= 4;
983     if (msglen > 0) {
984         proto_tree_add_text(pt, tvb, offset, msglen, "Data");
985         offset += msglen;
986     }
987     return offset;
988 }
989
990 static int
991 cmd_addfilt(tvbuff_t *tvb, int offset, proto_tree *pt)
992 {
993     proto_item  *item;
994     proto_tree  *tree;
995     guint8      flags;
996     int         blocks, i, length;
997
998     item = proto_tree_add_text(pt, tvb, offset, 1, "Flags");
999     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1000     flags = tvb_get_guint8(tvb, offset);
1001     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1002         decode_boolean_bitfield(flags, FILTER_PASS_FLAG, 8,
1003             "Conforming messages are passed",
1004             "Conforming messages are blocked"));
1005     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1006         decode_boolean_bitfield(flags, FILTER_ACTIVE_FLAG, 8,
1007             "The filter is active", "The filter is inactive"));
1008     offset += 1;
1009     blocks = tvb_get_guint8(tvb, offset);
1010     proto_tree_add_text(pt, tvb, offset, 1, "Number of filter blocks = %d", blocks);
1011     proto_tree_add_text(pt, tvb, offset+1, 6, "reserved");
1012     offset += 7;
1013     for (i = 1; i <= blocks; i++) {
1014         length = tvb_get_ntohs(tvb, offset+2) * 2 + 8;
1015         length += 3 - (length + 3) % 4;
1016         item = proto_tree_add_text(pt, tvb, offset, length, "Filter block %d", i);
1017         tree = proto_item_add_subtree (item, ett_gryphon_cmd_filter_block);
1018         offset = filter_block(tvb, offset, tree);
1019     }
1020     return offset;
1021 }
1022
1023 static int
1024 resp_addfilt(tvbuff_t *tvb, int offset, proto_tree *pt)
1025 {
1026     proto_tree_add_text(pt, tvb, offset, 1, "Filter handle: %u",
1027         tvb_get_guint8(tvb, offset));
1028     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1029     offset += 4;
1030     return offset;
1031 }
1032
1033 static int
1034 cmd_modfilt(tvbuff_t *tvb, int offset, proto_tree *pt)
1035 {
1036     guint8          filter_handle;
1037     unsigned char   action;
1038
1039     filter_handle = tvb_get_guint8(tvb, offset);
1040     if (filter_handle)
1041         proto_tree_add_text(pt, tvb, offset, 1, "Filter handle: %u",
1042             filter_handle);
1043     else
1044         proto_tree_add_text(pt, tvb, offset, 1, "Filter handles: all");
1045     action = tvb_get_guint8(tvb, offset + 1);
1046     proto_tree_add_text(pt, tvb, offset+1, 1, "Action: %s filter",
1047         val_to_str(action, filtacts, "Unknown (%u)"));
1048     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1049     offset += 4;
1050     return offset;
1051 }
1052
1053 static int
1054 resp_filthan(tvbuff_t *tvb, int offset, proto_tree *pt)
1055 {
1056     int         handles = tvb_get_guint8(tvb, offset);
1057     int         i, padding;
1058
1059     proto_tree_add_text(pt, tvb, offset, 1, "Number of filter handles: %d", handles);
1060     for (i = 1; i <= handles; i++){
1061         proto_tree_add_text(pt, tvb, offset+i, 1, "Handle %d: %u", i,
1062             tvb_get_guint8(tvb, offset+i));
1063     }
1064     padding = 3 - (handles + 1 + 3) % 4;
1065     if (padding)
1066         proto_tree_add_text(pt, tvb, offset+1+handles, padding, "padding");
1067     offset += 1+handles+padding;
1068     return offset;
1069 }
1070
1071 static int
1072 dfiltmode(tvbuff_t *tvb, int offset, proto_tree *pt)
1073 {
1074     unsigned char   mode;
1075
1076     mode = tvb_get_guint8(tvb, offset);
1077     proto_tree_add_text(pt, tvb, offset, 1, "Filter mode: %s",
1078         val_to_str(mode, dmodes, "Unknown (%u)"));
1079     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1080     offset += 4;
1081     return offset;
1082 }
1083
1084 static int
1085 filtmode(tvbuff_t *tvb, int offset, proto_tree *pt)
1086 {
1087     unsigned char   mode;
1088
1089     mode = tvb_get_guint8(tvb, offset);
1090     proto_tree_add_text(pt, tvb, offset, 1, "Filter mode: %s",
1091         val_to_str(mode, modes, "Unknown (%u)"));
1092     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1093     offset += 4;
1094     return offset;
1095 }
1096
1097 static int
1098 resp_events(tvbuff_t *tvb, int offset, proto_tree *pt)
1099 {
1100     int             msglen;
1101     unsigned int    i;
1102     proto_tree      *tree;
1103     proto_item      *item;
1104
1105     msglen = tvb_reported_length_remaining(tvb, offset);
1106     i = 1;
1107     while (msglen != 0) {
1108         item = proto_tree_add_text(pt, tvb, offset, 20, "Event %d:", i);
1109         tree = proto_item_add_subtree (item, ett_gryphon_cmd_events_data);
1110         proto_tree_add_text(tree, tvb, offset, 1, "Event ID: %u",
1111             tvb_get_guint8(tvb, offset));
1112         proto_tree_add_text(tree, tvb, offset+1, 19, "Event name: %.19s",
1113                 tvb_get_ptr(tvb, offset+1, 19));
1114         offset += 20;
1115         msglen -= 20;
1116         i++;
1117     }
1118     return offset;
1119 }
1120
1121 static int
1122 cmd_register(tvbuff_t *tvb, int offset, proto_tree *pt)
1123 {
1124     proto_tree_add_text(pt, tvb, offset, 16, "Username: %.16s",
1125         tvb_get_ptr(tvb, offset, 16));
1126     offset += 16;
1127     proto_tree_add_text(pt, tvb, offset, 32, "Password: %.32s",
1128         tvb_get_ptr(tvb, offset, 32));
1129     offset += 32;
1130     return offset;
1131 }
1132
1133 static int
1134 resp_register(tvbuff_t *tvb, int offset, proto_tree *pt)
1135 {
1136     proto_tree_add_text(pt, tvb, offset, 1, "Client ID: %u",
1137         tvb_get_guint8(tvb, offset));
1138     proto_tree_add_text(pt, tvb, offset+1, 1, "Privileges: %u",
1139         tvb_get_guint8(tvb, offset+1));
1140     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1141     offset += 4;
1142     return offset;
1143 }
1144
1145
1146 static int
1147 resp_getspeeds(tvbuff_t *tvb, int offset, proto_tree *pt)
1148 {
1149     int size;
1150     int number;
1151     int index;
1152
1153     proto_tree_add_text(pt, tvb, offset, 4, "Set Speed IOCTL");
1154     proto_tree_add_text(pt, tvb, offset+4, 4, "Get Speed IOCTL");
1155     size = tvb_get_guint8(tvb, offset+8);
1156     proto_tree_add_text(pt, tvb, offset+8, 1, "Speed data size is %d byte%s",
1157             size, size == 1 ? "" : "s");
1158     number = tvb_get_guint8(tvb, offset+9);
1159     proto_tree_add_text(pt, tvb, offset+9, 1, "There %s %d preset speed%s",
1160         number == 1 ? "is" : "are", number, number == 1 ? "" : "s");
1161     offset += 10;
1162     for (index = 0; index < number; index++) {
1163         proto_tree_add_text(pt, tvb, offset, size, "Data for preset %d",
1164             index+1);
1165         offset += size;
1166     }
1167     return offset;
1168 }
1169
1170 static int
1171 cmd_sort(tvbuff_t *tvb, int offset, proto_tree *pt)
1172 {
1173     const char  *which;
1174
1175     which = tvb_get_guint8(tvb, offset) ?
1176             "Sort into blocks of up to 16 messages" :
1177             "Do not sort messages";
1178     proto_tree_add_text(pt, tvb, offset, 1, "Set sorting: %s", which);
1179     offset += 1;
1180     return offset;
1181 }
1182
1183 static int
1184 cmd_optimize(tvbuff_t *tvb, int offset, proto_tree *pt)
1185 {
1186     const char  *which;
1187
1188     which = tvb_get_guint8(tvb, offset) ?
1189             "Optimize for latency (Nagle algorithm disabled)" :
1190             "Optimize for throughput (Nagle algorithm enabled)";
1191     proto_tree_add_text(pt, tvb, offset, 1, "Set optimization: %s", which);
1192     offset += 1;
1193     return offset;
1194 }
1195
1196 static int
1197 resp_config(tvbuff_t *tvb, int offset, proto_tree *pt)
1198 {
1199     proto_item  *ti, *item;
1200     proto_tree  *ft, *tree;
1201     int         devices;
1202     int         i;
1203     unsigned int j, x;
1204
1205     static const value_string protocol_types[] = {
1206         {GDUMMY * 256 + GDGDMARKONE,    "Dummy device driver"},
1207         {GCAN * 256 + G82527,           "CAN, 82527 subtype"},
1208         {GCAN * 256 + GSJA1000,         "CAN, SJA1000 subtype"},
1209         {GCAN * 256 + G82527SW,         "CAN, 82527 single wire subtype"},
1210         {GCAN * 256 + G82527ISO11992,   "CAN, 82527 ISO11992 subtype"},
1211         {GCAN * 256 + G82527_SINGLECHAN, "CAN, Fiber Optic 82527 subtype"},
1212         {GCAN * 256 + G82527SW_SINGLECHAN, "CAN, Fiber Optic 82527 single wire subtype"},
1213         {GCAN * 256 + G82527ISO11992_SINGLECHAN,        "CAN, Fiber Optic ISO11992 subtype"},
1214         {GCAN * 256 + GSJA1000FT,       "CAN, SJA1000 Fault Tolerant subtype"},
1215         {GCAN * 256 + GSJA1000C,        "CAN, SJA1000 onboard subtype"},
1216         {GCAN * 256 + GSJA1000FT_FO,    "CAN, SJA1000 Fiber Optic Fault Tolerant subtype"},
1217         {GJ1850 * 256 + GHBCCPAIR,      "J1850, HBCC subtype"},
1218         {GJ1850 * 256 + GDLC,           "J1850, GM DLC subtype"},
1219         {GJ1850 * 256 + GCHRYSLER,      "J1850, Chrysler subtype"},
1220         {GJ1850 * 256 + GDEHC12,        "J1850, DE HC12 KWP/BDLC subtype"},
1221         {GKWP2000 * 256 + GDEHC12KWP,   "Keyword protocol 2000/ISO 9141"},
1222         {GHONDA * 256 + GDGHC08,        "Honda UART, DG HC08 subtype"},
1223         {GFORDUBP * 256 + GDGUBP08,     "Ford UBP, DG HC08 subtype"},
1224         {GSCI * 256 + G16550SCI,        "Chrysler SCI, UART subtype"},
1225         {GCCD * 256 + G16550CDP68HC68,  "Chrysler C2D, UART / CDP68HC68S1 subtype"},
1226         {GLIN * 256 + GDGLIN08,         "LIN, DG HC08 subtype"},
1227         {0,                             NULL},
1228     };
1229
1230     proto_tree_add_text(pt, tvb, offset, 20, "Device name: %.20s",
1231         tvb_get_ptr(tvb, offset, 20));
1232     offset += 20;
1233
1234     proto_tree_add_text(pt, tvb, offset, 8, "Device version: %.8s",
1235         tvb_get_ptr(tvb, offset, 8));
1236     offset += 8;
1237
1238     proto_tree_add_text(pt, tvb, offset, 20, "Device serial number: %.20s",
1239         tvb_get_ptr(tvb, offset, 20));
1240     offset += 20;
1241
1242     devices = tvb_get_guint8(tvb, offset);
1243     proto_tree_add_text(pt, tvb, offset, 1, "Number of channels: %d", devices);
1244     proto_tree_add_text(pt, tvb, offset+1, 11, "Name & version extension: %.11s",
1245         tvb_get_ptr(tvb, offset+1, 11));
1246     proto_tree_add_text(pt, tvb, offset+12, 4, "reserved");
1247     offset += 16;
1248     for (i = 1; i <= devices; i++) {
1249         ti = proto_tree_add_text(pt, tvb, offset, 80, "Channel %d:", i);
1250         ft = proto_item_add_subtree(ti, ett_gryphon_cmd_config_device);
1251         proto_tree_add_text(ft, tvb, offset, 20, "Driver name: %.20s",
1252             tvb_get_ptr(tvb, offset, 20));
1253         offset += 20;
1254
1255         proto_tree_add_text(ft, tvb, offset, 8, "Driver version: %.8s",
1256             tvb_get_ptr(tvb, offset, 8));
1257         offset += 8;
1258
1259         proto_tree_add_text(ft, tvb, offset, 16, "Device security string: %.16s",
1260             tvb_get_ptr(tvb, offset, 16));
1261         offset += 16;
1262
1263         x = tvb_get_ntohl (tvb, offset);
1264         if (x) {
1265             item = proto_tree_add_text(ft, tvb, offset, 4, "Valid Header lengths");
1266             tree = proto_item_add_subtree (item, ett_gryphon_valid_headers);
1267             for (j = 0; ; j++) {
1268                 if (x & 1) {
1269                     proto_tree_add_text(tree, tvb, offset, 4, "%d byte%s", j,
1270                     j == 1 ? "" : "s");
1271                 }
1272                 if ((x >>= 1) == 0)
1273                     break;
1274             }
1275         }
1276         offset += 4;
1277
1278         x = tvb_get_ntohs (tvb, offset);
1279         proto_tree_add_text(ft, tvb, offset, 2, "Maximum data length = %d byte%s",
1280                 x, x == 1 ? "" : "s");
1281         offset += 2;
1282
1283         x = tvb_get_ntohs (tvb, offset);
1284         proto_tree_add_text(ft, tvb, offset, 2, "Minimum data length = %d byte%s",
1285                 x, x == 1 ? "" : "s");
1286         offset += 2;
1287
1288         proto_tree_add_text(ft, tvb, offset, 20, "Hardware serial number: %.20s",
1289             tvb_get_ptr(tvb, offset, 20));
1290         offset += 20;
1291
1292         x = tvb_get_ntohs(tvb, offset);
1293         proto_tree_add_text(ft, tvb, offset, 2, "Protocol type & subtype: %s",
1294             val_to_str(x, protocol_types, "Unknown (0x%04x)"));
1295         offset += 2;
1296
1297         proto_tree_add_text(ft, tvb, offset, 1, "Channel ID: %u",
1298             tvb_get_guint8(tvb, offset));
1299         offset++;
1300
1301         proto_tree_add_text(ft, tvb, offset, 1, "Card slot number: %u",
1302             tvb_get_guint8(tvb, offset));
1303         offset ++;
1304
1305         x = tvb_get_ntohs (tvb, offset);
1306         proto_tree_add_text(ft, tvb, offset, 2, "Maximum extra data = %d byte%s",
1307                 x, x == 1 ? "" : "s");
1308         offset += 2;
1309
1310         x = tvb_get_ntohs (tvb, offset);
1311         proto_tree_add_text(ft, tvb, offset, 2, "Minimum extra data = %d byte%s",
1312                 x, x == 1 ? "" : "s");
1313         offset += 2;
1314
1315     }
1316     return offset;
1317 }
1318
1319 static int
1320 cmd_sched(tvbuff_t *tvb, int offset, proto_tree *pt)
1321 {
1322     int             msglen;
1323     proto_item      *item, *item1;
1324     proto_tree      *tree, *tree1;
1325     int             save_offset;
1326     unsigned int    i, x, length;
1327     unsigned char   def_chan = tvb_get_guint8(tvb, offset-9);
1328
1329     msglen = tvb_reported_length_remaining(tvb, offset);
1330     x = tvb_get_ntohl(tvb, offset);
1331     if (x == 0xFFFFFFFF)
1332         proto_tree_add_text(pt, tvb, offset, 4, "Number of iterations: \"infinite\"");
1333     else
1334         proto_tree_add_text(pt, tvb, offset, 4, "Number of iterations: %u", x);
1335     offset += 4;
1336     msglen -= 4;
1337     x = tvb_get_ntohl(tvb, offset);
1338     item = proto_tree_add_text(pt, tvb, offset, 4, "Flags: 0x%08x", x);
1339     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1340     proto_tree_add_text(tree, tvb, offset, 4, "%s",
1341         decode_boolean_bitfield(x, 0x01, 32,
1342             "Critical scheduler", "Normal scheduler"));
1343     offset += 4;
1344     msglen -= 4;
1345     i = 1;
1346     while (msglen > 0) {
1347         length = 16 + tvb_get_guint8(tvb, offset+16) +
1348             tvb_get_ntohs(tvb, offset+18) + tvb_get_guint8(tvb, offset+20) + 16;
1349         length += 3 - (length + 3) % 4;
1350         item = proto_tree_add_text(pt, tvb, offset, length, "Message %d", i);
1351         tree = proto_item_add_subtree (item, ett_gryphon_cmd_sched_data);
1352         x = tvb_get_ntohl(tvb, offset);
1353         proto_tree_add_text(tree, tvb, offset, 4, "Sleep: %u milliseconds", x);
1354         offset += 4;
1355         msglen -= 4;
1356         x = tvb_get_ntohl(tvb, offset);
1357         proto_tree_add_text(tree, tvb, offset, 4, "Transmit count: %u", x);
1358         offset += 4;
1359         msglen -= 4;
1360         x = tvb_get_ntohl(tvb, offset);
1361         proto_tree_add_text(tree, tvb, offset, 4, "Transmit period: %u milliseconds", x);
1362         offset += 4;
1363         msglen -= 4;
1364         x = tvb_get_ntohs(tvb, offset);
1365         item1 = proto_tree_add_text(tree, tvb, offset, 2, "Flags");
1366         tree1 = proto_item_add_subtree (item1, ett_gryphon_flags);
1367         proto_tree_add_text(tree1, tvb, offset, 2, "%s%s",
1368                 decode_boolean_bitfield(x, 1, 16, "S", "Do not s"),
1369                 "kip the last \"Transmit period\"");
1370         if (i == 1) {
1371             proto_tree_add_text(tree1, tvb, offset, 2, "%s%s",
1372                     decode_boolean_bitfield(x, 2, 16, "S", "Do not s"),
1373                     "kip the first \"Sleep\" value");
1374         }
1375         x = tvb_get_guint8(tvb, offset+2);
1376         if (x == 0)
1377             x = def_chan;
1378         proto_tree_add_text(tree, tvb, offset+2, 1, "Channel: %u", x);
1379         proto_tree_add_text(tree, tvb, offset+3, 1, "reserved");
1380         offset += 4;
1381         msglen -= 4;
1382         item1 = proto_tree_add_text(tree, tvb, offset, length, "Message");
1383         tree1 = proto_item_add_subtree (item1, ett_gryphon_cmd_sched_cmd);
1384         save_offset = offset;
1385         offset = decode_data(tvb, offset, tree1);
1386         msglen -= offset - save_offset;
1387         i++;
1388     }
1389     return offset;
1390 }
1391
1392 static int
1393 cmd_sched_rep(tvbuff_t *tvb, int offset, proto_tree *pt)
1394 {
1395     int             msglen;
1396     proto_item      *item;
1397     int             save_offset;
1398     unsigned int    x;
1399     const char      *type;
1400
1401     msglen = tvb_reported_length_remaining(tvb, offset);
1402     x = tvb_get_ntohl(tvb, offset);
1403     if (x & 0x80000000)
1404         type = "Critical";
1405     else
1406         type = "Normal";
1407     proto_tree_add_text(pt, tvb, offset, 4, "%s schedule ID: %u", type, x);
1408     offset += 4;
1409     msglen -= 4;
1410     x= tvb_get_guint8(tvb, offset);
1411     item = proto_tree_add_text(pt, tvb, offset, 1, "Message index: %d", x);
1412     item = proto_tree_add_text(pt, tvb, offset + 1, 3, "reserved");
1413     offset += 4;
1414     msglen -= 4;
1415     save_offset = offset;
1416     offset = decode_data(tvb, offset, pt);
1417     msglen -= offset - save_offset;
1418     return offset;
1419 }
1420
1421 static int
1422 resp_blm_data(tvbuff_t *tvb, int offset, proto_tree *pt)
1423 {
1424     unsigned int      i;
1425     int               hours, minutes, seconds, fraction, x, fract;
1426     unsigned long     timestamp;
1427     static const char *fields[] = {
1428         "Bus load average: %d.%02d%%",
1429         "Current bus load: %d.%02d%%",
1430         "Peak bus load: %d.%02d%%",
1431         "Historic peak bus load: %d.%02d%%"
1432     };
1433
1434     timestamp = tvb_get_ntohl(tvb, offset);
1435     hours = timestamp /(100000 * 60 *60);
1436     minutes = (timestamp / (100000 * 60)) % 60;
1437     seconds = (timestamp / 100000) % 60;
1438     fraction = timestamp % 100000;
1439     proto_tree_add_text(pt, tvb, offset, 4, "Timestamp: %d:%02d:%02d.%05d", hours, minutes, seconds, fraction);
1440     offset += 4;
1441     for (i = 0; i < SIZEOF(fields); i++){
1442         x = tvb_get_ntohs(tvb, offset);
1443         fract = x % 100;
1444         x /= 100;
1445         proto_tree_add_text(pt, tvb, offset, 2, fields[i], x, fract);
1446         offset += 2;
1447     }
1448     return offset;
1449 }
1450
1451 static int
1452 resp_blm_stat(tvbuff_t *tvb, int offset, proto_tree *pt)
1453 {
1454     unsigned int    x, i;
1455     const char      *fields[] = {
1456         "Receive frame count: %u",
1457         "Transmit frame count: %u",
1458         "Receive dropped frame count: %u",
1459         "Transmit dropped frame count: %u",
1460         "Receive error count: %u",
1461         "Transmit error count: %u",
1462     };
1463
1464     offset = resp_blm_data(tvb, offset, pt);
1465     for (i = 0; i < SIZEOF(fields); i++){
1466         x = tvb_get_ntohl(tvb, offset);
1467         proto_tree_add_text(pt, tvb, offset, 4, fields[i], x);
1468         offset += 4;
1469     }
1470     return offset;
1471 }
1472
1473 static const value_string action_vals[] = {
1474     { FR_RESP_AFTER_EVENT,  "Send response(s) for each conforming message" },
1475     { FR_RESP_AFTER_PERIOD, "Send response(s) after the specified period expires following a conforming message" },
1476     { FR_IGNORE_DURING_PER, "Send response(s) for a conforming message and ignore\nfurther messages until the specified period expires" },
1477     { 0,                    NULL }
1478 };
1479
1480 static const value_string deact_on_event_vals[] = {
1481     { FR_DEACT_ON_EVENT,
1482         "Deactivate this response for a conforming message" },
1483     { FR_DELETE|FR_DEACT_ON_EVENT,
1484         "Delete this response for a conforming message" },
1485     { 0,
1486         NULL }
1487 };
1488
1489 static const value_string deact_after_per_vals[] = {
1490     { FR_DEACT_AFTER_PER,
1491         "Deactivate this response after the specified period following a conforming message" },
1492     { FR_DELETE|FR_DEACT_AFTER_PER,
1493         "Delete this response after the specified period following a conforming message" },
1494     { 0,
1495         NULL }
1496 };
1497
1498 static int
1499 cmd_addresp(tvbuff_t *tvb, int offset, proto_tree *pt)
1500 {
1501     proto_item  *item;
1502     proto_tree  *tree;
1503     guint8      flags;
1504     int         blocks, responses, old_handle, i, msglen, length;
1505     int         action, actionType, actionValue;
1506     tvbuff_t    *next_tvb;
1507
1508     actionType = 0;
1509     flags = tvb_get_guint8(tvb, offset);
1510     item = proto_tree_add_text(pt, tvb, offset, 1, "Flags: 0x%02x", flags);
1511     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1512     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1513         decode_boolean_bitfield(flags, FILTER_ACTIVE_FLAG, 8,
1514                 "The response is active", "The response is inactive"));
1515     offset += 1;
1516     blocks = tvb_get_guint8(tvb, offset);
1517     proto_tree_add_text(pt, tvb, offset, 1, "Number of filter blocks = %d", blocks);
1518     offset += 1;
1519     responses = tvb_get_guint8(tvb, offset);
1520     proto_tree_add_text(pt, tvb, offset, 1, "Number of response blocks = %d", responses);
1521     offset += 1;
1522     old_handle = tvb_get_guint8(tvb, offset);
1523     proto_tree_add_text(pt, tvb, offset, 1, "Old handle = %d", old_handle);
1524     offset += 1;
1525     action = tvb_get_guint8(tvb, offset);
1526     item = proto_tree_add_text(pt, tvb, offset, 1, "Action: %s",
1527         val_to_str(action & 0x07, action_vals, "Unknown (%u)"));
1528     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1529     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1530         decode_enumerated_bitfield(action, 0x07, 8, action_vals, "%s"));
1531     actionValue = tvb_get_ntohs(tvb, offset+2);
1532     if (actionValue) {
1533         if (action & FR_PERIOD_MSGS) {
1534             actionType = 1;
1535         } else {
1536             actionType = 0;
1537         }
1538         proto_tree_add_text(tree, tvb, offset, 1, "%s",
1539             decode_boolean_bitfield(action, FR_PERIOD_MSGS, 8,
1540                 "The period is in frames", "The period is in 0.01 seconds"));
1541     }
1542     if (action & FR_DEACT_ON_EVENT) {
1543         proto_tree_add_text(tree, tvb, offset, 1, "%s",
1544             decode_enumerated_bitfield(action, FR_DELETE|FR_DEACT_ON_EVENT, 8,
1545                 deact_on_event_vals, "%s"));
1546     }
1547     if (action & FR_DEACT_AFTER_PER) {
1548         proto_tree_add_text(tree, tvb, offset, 1, "%s",
1549             decode_enumerated_bitfield(action, FR_DELETE|FR_DEACT_AFTER_PER, 8,
1550                 deact_after_per_vals, "%s"));
1551     }
1552     offset += 1;
1553     proto_tree_add_text(pt, tvb, offset, 1, "reserved");
1554     offset += 1;
1555     if (actionValue) {
1556         if (actionType == 1) {
1557             proto_tree_add_text(tree, tvb, offset, 2, "Period: %d messages", actionValue);
1558         } else {
1559             proto_tree_add_text(tree, tvb, offset, 2, "Period: %d.%02d seconds", actionValue/100, actionValue%100);
1560         }
1561     }
1562     offset += 2;
1563     for (i = 1; i <= blocks; i++) {
1564         length = tvb_get_ntohs(tvb, offset+2) * 2 + 8;
1565         length += 3 - (length + 3) % 4;
1566         item = proto_tree_add_text(pt, tvb, offset, length, "Filter block %d", i);
1567         tree = proto_item_add_subtree (item, ett_gryphon_cmd_filter_block);
1568         offset = filter_block(tvb, offset, tree);
1569     }
1570     for (i = 1; i <= responses; i++) {
1571         msglen = tvb_get_ntohs(tvb, offset+4) + 8;
1572         length = msglen + 3 - (msglen + 3) % 4;
1573         item = proto_tree_add_text(pt, tvb, offset, length, "Response block %d", i);
1574         tree = proto_item_add_subtree (item, ett_gryphon_cmd_response_block);
1575         next_tvb = tvb_new_subset(tvb, offset, msglen, msglen);
1576         dissect_gryphon_message(next_tvb, NULL, tree, TRUE);
1577         offset += length;
1578     }
1579     return offset;
1580 }
1581
1582 static int
1583 resp_addresp(tvbuff_t *tvb, int offset, proto_tree *pt)
1584 {
1585     proto_tree_add_text(pt, tvb, offset, 1, "Response handle: %u",
1586         tvb_get_guint8(tvb, offset));
1587     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1588     offset += 4;
1589     return offset;
1590 }
1591
1592 static int
1593 cmd_modresp(tvbuff_t *tvb, int offset, proto_tree *pt)
1594 {
1595     unsigned char   action;
1596     unsigned char   dest = tvb_get_guint8(tvb, offset-5);
1597     guint8          resp_handle;
1598
1599     resp_handle = tvb_get_guint8(tvb, offset);
1600     if (resp_handle)
1601         proto_tree_add_text(pt, tvb, offset, 1, "Response handle: %u",
1602             resp_handle);
1603     else if (dest)
1604         proto_tree_add_text(pt, tvb, offset, 1, "Response handles: all on channel %hd", dest);
1605     else
1606         proto_tree_add_text(pt, tvb, offset, 1, "Response handles: all");
1607     action = tvb_get_guint8(tvb, offset+1);
1608     proto_tree_add_text(pt, tvb, offset+1, 1, "Action: %s response",
1609         val_to_str(action, filtacts, "Unknown (%u)"));
1610     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1611     offset += 4;
1612     return offset;
1613 }
1614
1615 static int
1616 resp_resphan(tvbuff_t *tvb, int offset, proto_tree *pt)
1617 {
1618     int         handles = tvb_get_guint8(tvb, offset);
1619     int         i, padding;
1620
1621     proto_tree_add_text(pt, tvb, offset, 1, "Number of response handles: %d", handles);
1622     for (i = 1; i <= handles; i++){
1623         proto_tree_add_text(pt, tvb, offset+i, 1, "Handle %d: %u", i,
1624             tvb_get_guint8(tvb, offset+i));
1625     }
1626     padding = 3 - (handles + 1 + 3) % 4;
1627     if (padding)
1628         proto_tree_add_text(pt, tvb, offset+1+handles, padding, "padding");
1629     offset += 1+handles+padding;
1630     return offset;
1631 }
1632
1633 static int
1634 resp_sched(tvbuff_t *tvb, int offset, proto_tree *pt)
1635 {
1636     unsigned int    id = tvb_get_ntohl(tvb, offset);
1637
1638     proto_tree_add_text(pt, tvb, offset, 4, "Transmit schedule ID: %u", id);
1639     offset += 4;
1640     return offset;
1641 }
1642
1643 static int
1644 cmd_desc(tvbuff_t *tvb, int offset, proto_tree *pt)
1645 {
1646     proto_tree_add_text(pt, tvb, offset, 4, "Program size: %u bytes",
1647         tvb_get_ntohl(tvb, offset));
1648     offset += 4;
1649     proto_tree_add_text(pt, tvb, offset, 32, "Program name: %.32s",
1650         tvb_get_ptr(tvb, offset, 32));
1651     offset += 32;
1652     proto_tree_add_text(pt, tvb, offset, 80, "Program description: %.80s",
1653         tvb_get_ptr(tvb, offset, 80));
1654     offset += 80;
1655     return offset;
1656 }
1657
1658 static int
1659 resp_desc(tvbuff_t *tvb, int offset, proto_tree *pt)
1660 {
1661     proto_item  *item;
1662     proto_tree  *tree;
1663     guint8      flags;
1664
1665     flags = tvb_get_guint8(tvb, offset);
1666     item = proto_tree_add_text(pt, tvb, offset, 1, "Flags: 0x%02x", flags);
1667     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1668     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1669         decode_boolean_bitfield(flags, 0x01, 8,
1670                 "The program is already present",
1671                 "The program is not present"));
1672     proto_tree_add_text(pt, tvb, offset+1, 1, "Handle: %u",
1673         tvb_get_guint8(tvb, offset+1));
1674     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1675     offset += 4;
1676     return offset;
1677 }
1678
1679 static int
1680 cmd_upload(tvbuff_t *tvb, int offset, proto_tree *pt)
1681 {
1682     int             msglen;
1683     unsigned int    length;
1684
1685     msglen = tvb_reported_length_remaining(tvb, offset);
1686     proto_tree_add_text(pt, tvb, offset, 2, "Block number: %u",
1687         tvb_get_ntohs(tvb, offset));
1688     proto_tree_add_text(pt, tvb, offset+2, 1, "Handle: %u",
1689         tvb_get_guint8(tvb, offset+2));
1690     offset += 3;
1691     msglen -= 3;
1692     length = msglen;
1693     proto_tree_add_text(pt, tvb, offset, length, "Data (%u byte%s)",
1694             length, length == 1 ? "" : "s");
1695     offset += length;
1696     length = 3 - (length + 3) % 4;
1697     if (length) {
1698         proto_tree_add_text(pt, tvb, offset, length, "padding");
1699         offset += length;
1700     }
1701     return offset;
1702 }
1703
1704 static int
1705 cmd_delete(tvbuff_t *tvb, int offset, proto_tree *pt)
1706 {
1707     proto_tree_add_text(pt, tvb, offset, 32, "Program name: %.32s",
1708         tvb_get_ptr(tvb, offset, 32));
1709     offset += 32;
1710     return offset;
1711 }
1712
1713 static int
1714 cmd_list(tvbuff_t *tvb, int offset, proto_tree *pt)
1715 {
1716     proto_tree_add_text(pt, tvb, offset, 1, "Block number: %u",
1717         tvb_get_guint8(tvb, offset));
1718     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1719     offset += 4;
1720     return offset;
1721 }
1722
1723 static int
1724 resp_list(tvbuff_t *tvb, int offset, proto_tree *pt)
1725 {
1726     proto_item  *item;
1727     proto_tree  *tree;
1728     unsigned int    i, count;
1729
1730     count = tvb_get_guint8(tvb, offset);
1731     proto_tree_add_text(pt, tvb, offset, 1, "Number of programs in this response: %u", count);
1732     proto_tree_add_text(pt, tvb, offset+1, 1, "reserved");
1733     offset += 2;
1734     proto_tree_add_text(pt, tvb, offset, 2, "Number of remaining programs: %u",
1735         tvb_get_ntohs(tvb, offset));
1736     offset += 2;
1737     for (i = 1; i <= count; i++) {
1738         item = proto_tree_add_text(pt, tvb, offset, 112, "Program %u", i);
1739         tree = proto_item_add_subtree (item, ett_gryphon_pgm_list);
1740         proto_tree_add_text(tree, tvb, offset, 32, "Name: %.32s",
1741             tvb_get_ptr(tvb, offset, 32));
1742         offset += 32;
1743         proto_tree_add_text(tree, tvb, offset, 80, "Description: %.80s",
1744             tvb_get_ptr(tvb, offset, 80));
1745         offset += 80;
1746     }
1747     return offset;
1748 }
1749
1750 static int
1751 cmd_start(tvbuff_t *tvb, int offset, proto_tree *pt)
1752 {
1753     guint8          *string;
1754     gint            length;
1755     int             msglen;
1756     int             hdr_stuff = offset;
1757
1758     msglen = tvb_reported_length_remaining(tvb, offset);
1759     offset = cmd_delete(tvb, offset, pt);       /* decode the name */
1760     if (offset < msglen + hdr_stuff) {
1761         string = tvb_get_stringz(tvb, offset, &length);
1762         if (length > 1) {
1763             proto_tree_add_text(pt, tvb, offset, length, "Arguments: %s", string);
1764             offset += length;
1765             length = 3 - (length + 3) % 4;
1766             if (length) {
1767                 proto_tree_add_text(pt, tvb, offset, length, "padding");
1768                 offset += length;
1769             }
1770         }
1771         g_free(string);
1772     }
1773     return offset;
1774 }
1775
1776 static int
1777 resp_start(tvbuff_t *tvb, int offset, proto_tree *pt)
1778 {
1779     int             msglen;
1780
1781     msglen = tvb_reported_length_remaining(tvb, offset);
1782     if (msglen > 0) {
1783         proto_tree_add_text(pt, tvb, offset, 1, "Channel (Client) number: %u",
1784             tvb_get_guint8(tvb, offset));
1785         proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1786         offset += 4;
1787     }
1788     return offset;
1789 }
1790
1791 static int
1792 resp_status(tvbuff_t *tvb, int offset, proto_tree *pt)
1793 {
1794     proto_item  *item;
1795     proto_tree  *tree;
1796     unsigned int    i, copies, length;
1797
1798     copies = tvb_get_guint8(tvb, offset);
1799     item = proto_tree_add_text(pt, tvb, offset, 1, "Number of running copies: %u", copies);
1800     tree = proto_item_add_subtree (item, ett_gryphon_pgm_status);
1801     offset += 1;
1802     if (copies) {
1803         for (i = 1; i <= copies; i++) {
1804             proto_tree_add_text(tree, tvb, offset, 1, "Program %u channel (client) number %u",
1805                 i, tvb_get_guint8(tvb, offset));
1806             offset += 1;
1807         }
1808     }
1809     length = 3 - (copies + 1 + 3) % 4;
1810     if (length) {
1811         proto_tree_add_text(pt, tvb, offset, length, "padding");
1812         offset += length;
1813     }
1814     return offset;
1815 }
1816
1817 static int
1818 cmd_options(tvbuff_t *tvb, int offset, proto_tree *pt)
1819 {
1820     int             msglen;
1821     proto_item      *item;
1822     proto_tree      *tree;
1823     unsigned int    i, size, padding, option, option_length, option_value;
1824     const char      *string, *string1;
1825
1826     msglen = tvb_reported_length_remaining(tvb, offset);
1827     item = proto_tree_add_text(pt, tvb, offset, 1, "Handle: %u",
1828         tvb_get_guint8(tvb, offset));
1829     item = proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1830     offset += 4;
1831     msglen -= 4;
1832     for (i = 1; msglen > 0; i++) {
1833         option_length = tvb_get_guint8(tvb, offset+1);
1834         size = option_length + 2;
1835         padding = 3 - ((size + 3) %4);
1836         item = proto_tree_add_text(pt, tvb, offset, size + padding, "Option number %u", i);
1837         tree = proto_item_add_subtree (item, ett_gryphon_pgm_options);
1838         option = tvb_get_guint8(tvb, offset);
1839         switch (option_length) {
1840         case 1:
1841             option_value = tvb_get_guint8(tvb, offset+2);
1842             break;
1843         case 2:
1844             option_value = tvb_get_ntohs(tvb, offset+2);
1845             break;
1846         case 4:
1847             option_value = tvb_get_ntohl(tvb, offset+2);
1848             break;
1849         default:
1850             option_value = 0;
1851         }
1852         string = "unknown option";
1853         string1 = "unknown option data";
1854         switch (option) {
1855         case PGM_CONV:
1856             string = "Type of data in the file";
1857             switch (option_value) {
1858             case PGM_BIN:
1859                 string1 = "Binary - Don't modify";
1860                 break;
1861             case PGM_ASCII:
1862                 string1 = "ASCII - Remove CR's";
1863                 break;
1864             }
1865             break;
1866         case PGM_TYPE:
1867             string = "Type of file";
1868             switch (option_value) {
1869             case PGM_PGM:
1870                 string1 = "Executable";
1871                 break;
1872             case PGM_DATA:
1873                 string1 = "Data";
1874                 break;
1875             }
1876             break;
1877         }
1878         proto_tree_add_text(tree, tvb, offset, 1, "%s", string);
1879         proto_tree_add_text(tree, tvb, offset+2, option_length, "%s", string1);
1880         if (padding)
1881             proto_tree_add_text(tree, tvb, offset+option_length+2, padding, "padding");
1882         offset += size + padding;
1883         msglen -= size + padding;
1884     }
1885     return offset;
1886 }
1887
1888 static int
1889 cmd_files(tvbuff_t *tvb, int offset, proto_tree *pt)
1890 {
1891     int          msglen;
1892     const gchar  *which;
1893
1894     msglen = tvb_reported_length_remaining(tvb, offset);
1895     if (tvb_get_guint8(tvb, offset) == 0)
1896         which = "First group of names";
1897     else
1898         which = "Subsequent group of names";
1899
1900     proto_tree_add_text(pt, tvb, offset, 1, "%s", which);
1901     proto_tree_add_text(pt, tvb, offset+1, msglen-1, "Directory: %.*s",
1902         msglen-1, tvb_get_ptr(tvb, offset+1, msglen-1));
1903     offset += msglen;
1904     return offset;
1905 }
1906
1907 static int
1908 resp_files(tvbuff_t *tvb, int offset, proto_tree *pt)
1909 {
1910     int                 msglen;
1911     const gchar         *flag;
1912
1913     msglen = tvb_reported_length_remaining(tvb, offset);
1914     flag = tvb_get_guint8(tvb, offset) ? "Yes": "No";
1915     proto_tree_add_text(pt, tvb, offset, 1, "More filenames to return: %s", flag);
1916     proto_tree_add_text(pt, tvb, offset+1, msglen-1, "File and directory names");
1917     offset += msglen;
1918     return offset;
1919 }
1920
1921 static int
1922 cmd_usdt(tvbuff_t *tvb, int offset, proto_tree *pt)
1923 {
1924     int         ids, id, remain, size, i, j, bytes;
1925     const gchar *desc;
1926     guint8      flags;
1927     proto_tree  *localTree;
1928     proto_item  *localItem;
1929     const gchar *actions[] = {
1930         "Use 11 bit headers only",
1931         "Use 29 bit headers only",
1932         "Use both 11 & 29 bit headers",
1933         "undefined"
1934     };
1935     const gchar *xmit_opts[] = {
1936         "Pad messages with less than 8 data bytes with 0x00's",
1937         "Pad messages with less than 8 data bytes with 0xFF's",
1938         "Do not pad messages with less than 8 data bytes",
1939         "undefined"
1940     };
1941     const gchar *recv_opts[] = {
1942         "Do not verify the integrity of long received messages and do not send them to the client",
1943         "Verify the integrity of long received messages and send them to the client",
1944         "Verify the integrity of long received messages but do not send them to the client",
1945         "undefined"
1946     };
1947     const gchar *block_desc[] = {"USDT request", "USDT response", "UUDT response"};
1948
1949     flags = tvb_get_guint8(tvb, offset);
1950     if (flags & 1)
1951         desc = "R";
1952     else
1953         desc = "Unr";
1954     proto_tree_add_text(pt, tvb, offset, 1, "%segister with gusdt", desc);
1955
1956     if (flags & 1) {
1957         localItem = proto_tree_add_text(pt, tvb, offset, 1, "Action flags");
1958         localTree = proto_item_add_subtree (localItem, ett_gryphon_flags);
1959         proto_tree_add_text(localTree, tvb, offset, 1, "%s%s",
1960             decode_boolean_bitfield (flags, 1, 8,
1961                 "R", "Unr"), "egister with gusdt");
1962         proto_tree_add_text(localTree, tvb, offset, 1, "%s = %s",
1963             decode_numeric_bitfield (flags, 6, 8, "%d"),
1964             actions[(flags >> 1) & 3]);
1965
1966         flags = tvb_get_guint8(tvb, offset+1);
1967         localItem = proto_tree_add_text(pt, tvb, offset+1, 1, "Transmit options");
1968         localTree = proto_item_add_subtree (localItem, ett_gryphon_flags);
1969         proto_tree_add_text(localTree, tvb, offset+1, 1, "%s%s",
1970             decode_boolean_bitfield (flags, 1, 8,
1971                 "E", "Do not e"),
1972                 "cho long transmit messages back to the client");
1973         proto_tree_add_text(localTree, tvb, offset+1, 1, "%s = %s",
1974             decode_numeric_bitfield (flags, 6, 8, "%d"),
1975             xmit_opts[(flags >> 1) & 3]);
1976         proto_tree_add_text(localTree, tvb, offset+1, 1, "%s%s",
1977             decode_boolean_bitfield (flags, 8, 8,
1978                 "S", "Do not s"),
1979                 "end a USDT_DONE event when the last frame of a multi-frame USDT message is transmitted");
1980
1981         flags = tvb_get_guint8(tvb, offset+2);
1982         localItem = proto_tree_add_text(pt, tvb, offset+2, 1, "Receive options");
1983         localTree = proto_item_add_subtree (localItem, ett_gryphon_flags);
1984         proto_tree_add_text(localTree, tvb, offset+2, 1, "%s = %s",
1985             decode_numeric_bitfield (flags, 3, 8, "%d"),
1986             recv_opts[flags & 3]);
1987         proto_tree_add_text(localTree, tvb, offset+2, 1, "%s%s",
1988             decode_boolean_bitfield (flags, 4, 8,
1989                 "S", "Do not s"),
1990                 "end a USDT_FIRSTFRAME event when the first frame of a multi-frame USDT message is received");
1991         proto_tree_add_text(localTree, tvb, offset+2, 1, "%s%s",
1992             decode_boolean_bitfield (flags, 8, 8,
1993                 "S", "Do not s"),
1994                 "end a USDT_LASTFRAME event when the last frame of a multi-frame USDT message is received");
1995
1996         if ((ids = tvb_get_guint8(tvb, offset+3))) {
1997             localItem = proto_tree_add_text(pt, tvb, offset+3, 1, "Using extended addressing for %d ID%s",
1998                     ids, ids == 1?"":"s");
1999             offset += 4;
2000             localTree = proto_item_add_subtree (localItem, ett_gryphon_usdt_data);
2001             while (ids) {
2002                 id = tvb_get_ntohl (tvb, offset);
2003                 proto_tree_add_text (localTree, tvb, offset, 4, "%04X", id);
2004                 offset += 4;
2005                 ids--;
2006             }
2007         } else {
2008             proto_tree_add_text(pt, tvb, offset+3, 1, "Using extended addressing for the single, internally defined, ID");
2009             offset += 4;
2010         }
2011         for (i = 0; i < 2; i++) {
2012             bytes = tvb_reported_length_remaining (tvb, offset);
2013             if (bytes <= 0)
2014                 break;
2015             localItem = proto_tree_add_text(pt, tvb, offset, 16, "%s block of USDT/UUDT IDs", i==0?"First":"Second");
2016             localTree = proto_item_add_subtree (localItem, ett_gryphon_usdt_data);
2017             size = tvb_get_ntohl (tvb, offset);
2018             if (size == 0) {
2019                 proto_tree_add_text (localTree, tvb, offset, 16, "No IDs in the block");
2020                 offset += 16;
2021             } else if (size == 1) {
2022                 proto_tree_add_text (localTree, tvb, offset, 4, "1 ID in the block");
2023                 offset += 4;
2024                 for (j = 0; j < 3; j++){
2025                     id = tvb_get_ntohl (tvb, offset);
2026                     proto_tree_add_text (localTree, tvb, offset, 4,
2027                             "%s ID: %04X", block_desc[j], id);
2028                     offset += 4;
2029                 }
2030             } else {
2031                 proto_tree_add_text (localTree, tvb, offset, 4, "%d IDs in the block", size);
2032                 offset += 4;
2033                 for (j = 0; j < 3; j++){
2034                     id = tvb_get_ntohl (tvb, offset);
2035                     proto_tree_add_text (localTree, tvb, offset, 4,
2036                             "%s IDs from %04X through %04X", block_desc[j], id, id+size-1);
2037                     offset += 4;
2038                 }
2039             }
2040         }
2041     } else {
2042         proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
2043         offset += 4;
2044     }
2045
2046     if ((remain = tvb_reported_length_remaining(tvb, offset))) {
2047         proto_tree_add_text(pt, tvb, offset, remain, "%d ignored byte%s",
2048                 remain, remain == 1 ? "" : "s");
2049         offset += remain;
2050     }
2051
2052     return offset;
2053 }
2054
2055 static int
2056 cmd_bits_in (tvbuff_t *tvb, int offset, proto_tree *pt)
2057 {
2058     proto_item  *item;
2059     proto_tree  *tree;
2060     unsigned int i;
2061     int         msglen, mask, value;
2062     const char  *decode[] = {"Input 1", "Input 2", "Input 3", "Pushbutton"};
2063
2064     msglen = tvb_reported_length_remaining(tvb, offset);
2065     value = tvb_get_guint8(tvb, offset);
2066     if (value) {
2067         item = proto_tree_add_text(pt, tvb, offset, 1, "Digital values set");
2068         tree = proto_item_add_subtree (item, ett_gryphon_digital_data);
2069         for (i = 0, mask = 1; i < SIZEOF (decode); mask <<= 1, i++) {
2070             if (value & mask) {
2071                 proto_tree_add_text(tree, tvb, offset, 1, "%s is set",
2072                         decode[i]);
2073             }
2074         }
2075     } else {
2076         proto_tree_add_text(pt, tvb, offset, 1, "No digital values are set");
2077     }
2078             
2079     offset++;
2080     msglen--;
2081     return offset;
2082 }
2083
2084 static int
2085 cmd_bits_out (tvbuff_t *tvb, int offset, proto_tree *pt)
2086 {
2087     proto_item  *item;
2088     proto_tree  *tree;
2089     unsigned int i;
2090     int         msglen, mask, value;
2091     const char  *decode[] = {"Output 1", "Output 2"};
2092
2093     msglen = tvb_reported_length_remaining(tvb, offset);
2094     value = tvb_get_guint8(tvb, offset);
2095     if (value) {
2096         item = proto_tree_add_text(pt, tvb, offset, 1, "Digital values set");
2097         tree = proto_item_add_subtree (item, ett_gryphon_digital_data);
2098         for (i = 0, mask = 1; i < SIZEOF (decode); mask <<= 1, i++) {
2099             if (value & mask) {
2100                 proto_tree_add_text(tree, tvb, offset, 1, "%s is set",
2101                         decode[i]);
2102             }
2103         }
2104     } else {
2105         proto_tree_add_text(pt, tvb, offset, 1, "No digital values are set");
2106     }
2107             
2108     offset++;
2109     msglen--;
2110     return offset;
2111 }
2112
2113 static int
2114 cmd_init_strat (tvbuff_t *tvb, int offset, proto_tree *pt)
2115 {
2116     int     msglen, index;
2117     float   value;
2118
2119     msglen = tvb_reported_length_remaining(tvb, offset);
2120     proto_tree_add_text(pt, tvb, offset, 4, "Reset Limit = %u messages",
2121         tvb_get_ntohl(tvb, offset));
2122     offset += 4;
2123     msglen -= 4;
2124     for (index = 1; msglen; index++, offset++, msglen--) {
2125         value = tvb_get_guint8(tvb, offset);
2126         if (value) {
2127             value /= 4;
2128             proto_tree_add_text(pt, tvb, offset, 1, "Delay %d = %.2f seconds",
2129                 index, value);
2130         } else {
2131             proto_tree_add_text(pt, tvb, offset, 1, "Delay %d = infinite",
2132                 index);
2133         }
2134     }
2135     return offset;
2136 }
2137
2138 static int
2139 speed(tvbuff_t *tvb, int offset, proto_tree *pt)
2140 {
2141     proto_tree_add_text(pt, tvb, offset, 1, "Baud rate index: %u",
2142         tvb_get_guint8(tvb, offset));
2143     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
2144     offset += 4;
2145     return offset;
2146 }
2147
2148 static int
2149 filter_block(tvbuff_t *tvb, int offset, proto_tree *pt)
2150 {
2151     unsigned int    type, operator;
2152     int     length, padding;
2153
2154     proto_tree_add_text(pt, tvb, offset, 2, "Filter field starts at byte %u",
2155         tvb_get_ntohs(tvb, offset));
2156     length = tvb_get_ntohs(tvb, offset+2);
2157     proto_tree_add_text(pt, tvb, offset+2, 2, "Filter field is %d byte%s long",
2158             length, length == 1 ? "" : "s");
2159     type = tvb_get_guint8(tvb, offset+4);
2160     proto_tree_add_text(pt, tvb, offset+4, 1, "Filtering on %s",
2161         val_to_str(type, filter_data_types, "Unknown (0x%02x)"));
2162
2163     operator = tvb_get_guint8(tvb, offset+5);
2164     proto_tree_add_text(pt, tvb, offset+5, 1, "Type of comparison: %s",
2165         val_to_str(operator, operators, "Unknown (%u)"));
2166     proto_tree_add_text(pt, tvb, offset+6, 2, "reserved");
2167     offset += 8;
2168
2169     if (operator == BIT_FIELD_CHECK) {
2170         proto_tree_add_text(pt, tvb, offset, length, "Pattern");
2171         proto_tree_add_text(pt, tvb, offset+length, length, "Mask");
2172     } else {
2173         switch (length) {
2174         case 1:
2175             proto_tree_add_text(pt, tvb, offset, 1, "Value: %u",
2176                 tvb_get_guint8(tvb, offset));
2177             break;
2178         case 2:
2179             proto_tree_add_text(pt, tvb, offset, 2, "Value: %u",
2180                 tvb_get_ntohs(tvb, offset));
2181             break;
2182         case 4:
2183             proto_tree_add_text(pt, tvb, offset, 4, "Value: %u",
2184                 tvb_get_ntohl(tvb, offset));
2185             break;
2186         default:
2187             proto_tree_add_text(pt, tvb, offset, length, "Value");
2188         }
2189     }
2190     offset += length * 2;
2191     padding = 3 - (length * 2 + 3) % 4;
2192     if (padding) {
2193         proto_tree_add_text(pt, tvb, offset, padding, "padding");
2194         offset += padding;
2195     }
2196     return offset;
2197 }
2198
2199 static int
2200 blm_mode(tvbuff_t *tvb, int offset, proto_tree *pt)
2201 {
2202     const char    *mode;
2203     char line[50];
2204     int     x, y, seconds;
2205
2206     x = tvb_get_ntohl(tvb, offset);
2207     y = tvb_get_ntohl(tvb, offset+4);
2208     switch (x) {
2209     case 0:
2210         mode = "Off";
2211         g_snprintf (line, 50, "reserved");
2212         break;
2213     case 1:
2214         mode = "Average over time";
2215         seconds = y / 1000;
2216         y = y % 1000;
2217         g_snprintf (line, 50, "Averaging period: %d.%03d seconds", seconds, y);
2218         break;
2219     case 2:
2220         mode = "Average over frame count";
2221         g_snprintf (line, 50, "Averaging period: %d frames", y);
2222         break;
2223     default:
2224         mode = "- unknown -";
2225         g_snprintf (line, 50, "reserved");
2226     }
2227     proto_tree_add_text(pt, tvb, offset, 4, "Mode: %s", mode);
2228     offset += 4;
2229     proto_tree_add_text(pt, tvb, offset, 4, line, NULL);
2230     offset += 4;
2231     return offset;
2232 }
2233
2234 void
2235 proto_register_gryphon(void)
2236 {
2237     static hf_register_info hf[] = {
2238         { &hf_gryphon_src,
2239         { "Source",           "gryphon.src", FT_UINT8, BASE_HEX, VALS(src_dest), 0x0,
2240                 NULL, HFILL }},
2241         { &hf_gryphon_srcchan,
2242         { "Source channel",   "gryphon.srcchan", FT_UINT8, BASE_DEC, NULL, 0x0,
2243                 NULL, HFILL }},
2244         { &hf_gryphon_dest,
2245         { "Destination",      "gryphon.dest", FT_UINT8, BASE_HEX, VALS(src_dest), 0x0,
2246                 NULL, HFILL }},
2247         { &hf_gryphon_destchan,
2248         { "Destination channel", "gryphon.destchan", FT_UINT8, BASE_DEC, NULL, 0x0,
2249                 NULL, HFILL }},
2250         { &hf_gryphon_type,
2251         { "Frame type",       "gryphon.type", FT_UINT8, BASE_DEC, NULL, 0x0,
2252                 NULL, HFILL }},
2253         { &hf_gryphon_cmd,
2254         { "Command",          "gryphon.cmd", FT_UINT8, BASE_DEC, NULL, 0x0,
2255                 NULL, HFILL }},
2256     };
2257
2258     static gint *ett[] = {
2259         &ett_gryphon,
2260         &ett_gryphon_header,
2261         &ett_gryphon_body,
2262         &ett_gryphon_command_data,
2263         &ett_gryphon_response_data,
2264         &ett_gryphon_data_header,
2265         &ett_gryphon_flags,
2266         &ett_gryphon_data_body,
2267         &ett_gryphon_cmd_filter_block,
2268         &ett_gryphon_cmd_events_data,
2269         &ett_gryphon_cmd_config_device,
2270         &ett_gryphon_cmd_sched_data,
2271         &ett_gryphon_cmd_sched_cmd,
2272         &ett_gryphon_cmd_response_block,
2273         &ett_gryphon_pgm_list,
2274         &ett_gryphon_pgm_status,
2275         &ett_gryphon_pgm_options,
2276         &ett_gryphon_valid_headers,
2277         &ett_gryphon_usdt_data,
2278         &ett_gryphon_digital_data,
2279     };
2280     module_t *gryphon_module;
2281
2282     proto_gryphon = proto_register_protocol("DG Gryphon Protocol",
2283                                             "Gryphon",
2284                                             "gryphon");
2285     proto_register_field_array(proto_gryphon, hf, array_length(hf));
2286     proto_register_subtree_array(ett, array_length(ett));
2287
2288     gryphon_module = prefs_register_protocol(proto_gryphon, NULL);
2289     prefs_register_bool_preference(gryphon_module, "desegment",
2290         "Desegment all Gryphon messages spanning multiple TCP segments",
2291         "Whether the Gryphon dissector should desegment all messages spanning multiple TCP segments",
2292         &gryphon_desegment);
2293 }
2294
2295 void
2296 proto_reg_handoff_gryphon(void)
2297 {
2298     dissector_handle_t gryphon_handle;
2299
2300     gryphon_handle = create_dissector_handle(dissect_gryphon, proto_gryphon);
2301     dissector_add("tcp.port", 7000, gryphon_handle);
2302 }