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