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