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