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