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