Removed trailing whitespaces from .h and .c files using the
[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: packet-gryphon.c,v 1.35 2002/08/28 20:39:05 jmayer Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "plugins/plugin_api.h"
32
33 #include "moduleinfo.h"
34
35 #include <string.h>
36 #include <ctype.h>
37 #include <time.h>
38
39 #include <gmodule.h>
40 #include <epan/packet.h>
41 #include "packet-gryphon.h"
42 #include "packet-tcp.h"
43 #include "prefs.h"
44
45 #include "plugins/plugin_api_defs.h"
46
47 #ifndef __ETHEREAL_STATIC__
48 G_MODULE_EXPORT const gchar version[] = VERSION;
49 #endif
50
51 #ifndef G_HAVE_GINT64
52 #error "Sorry, this won't compile without 64-bit integer support"
53 #endif
54
55 /*
56  * See
57  *
58  *      http://www.dgtech.com/gryphon/docs/html/
59  */
60
61 static int proto_gryphon = -1;
62
63 static int hf_gryph_src = -1;
64 static int hf_gryph_srcchan = -1;
65 static int hf_gryph_dest = -1;
66 static int hf_gryph_destchan= -1;
67 static int hf_gryph_type = -1;
68 static int hf_gryph_cmd = -1;
69
70 static gint ett_gryphon = -1;
71 static gint ett_gryphon_header = -1;
72 static gint ett_gryphon_body = -1;
73 static gint ett_gryphon_command_data = -1;
74 static gint ett_gryphon_response_data = -1;
75 static gint ett_gryphon_data_header = -1;
76 static gint ett_gryphon_flags = -1;
77 static gint ett_gryphon_data_body = -1;
78 static gint ett_gryphon_cmd_filter_block = -1;
79 static gint ett_gryphon_cmd_events_data = -1;
80 static gint ett_gryphon_cmd_config_device = -1;
81 static gint ett_gryphon_cmd_sched_data = -1;
82 static gint ett_gryphon_cmd_sched_cmd = -1;
83 static gint ett_gryphon_cmd_response_block = -1;
84 static gint ett_gryphon_pgm_list = -1;
85 static gint ett_gryphon_pgm_status = -1;
86 static gint ett_gryphon_pgm_options = -1;
87
88 /* desegmentation of Gryphon */
89 static gboolean gryphon_desegment = TRUE;
90
91 static void dissect_gryphon_message(tvbuff_t *tvb, packet_info *pinfo,
92     proto_tree *tree, gboolean is_msgresp_add);
93 static int decode_command(tvbuff_t*, int, int, proto_tree*);
94 static int decode_response(tvbuff_t*, int, int, proto_tree*);
95 static int decode_data(tvbuff_t*, int, proto_tree*);
96 static int decode_event(tvbuff_t*, int, proto_tree*);
97 static int cmd_init(tvbuff_t*, int, proto_tree*);
98 static int resp_time(tvbuff_t*, int, proto_tree*);
99 static int cmd_setfilt(tvbuff_t*, int, proto_tree*);
100 static int cmd_ioctl(tvbuff_t*, int, proto_tree*);
101 static int cmd_addfilt(tvbuff_t*, int, proto_tree*);
102 static int resp_addfilt(tvbuff_t*, int, proto_tree*);
103 static int cmd_modfilt(tvbuff_t*, int, proto_tree*);
104 static int resp_filthan(tvbuff_t*, int, proto_tree*);
105 static int dfiltmode(tvbuff_t*, int, proto_tree*);
106 static int filtmode(tvbuff_t*, int, proto_tree*);
107 static int resp_events(tvbuff_t*, int, proto_tree*);
108 static int cmd_register(tvbuff_t*, int, proto_tree*);
109 static int resp_register(tvbuff_t*, int, proto_tree*);
110 static int resp_getspeeds(tvbuff_t*, int, proto_tree*);
111 static int cmd_sort(tvbuff_t*, int, proto_tree*);
112 static int cmd_optimize(tvbuff_t*, int, proto_tree*);
113 static int resp_config(tvbuff_t*, int, proto_tree*);
114 static int cmd_sched(tvbuff_t*, int, proto_tree*);
115 static int resp_blm_data(tvbuff_t*, int, proto_tree*);
116 static int resp_blm_stat(tvbuff_t*, int, proto_tree*);
117 static int cmd_addresp(tvbuff_t*, int, proto_tree*);
118 static int resp_addresp(tvbuff_t*, int, proto_tree*);
119 static int cmd_modresp(tvbuff_t*, int, proto_tree*);
120 static int resp_resphan(tvbuff_t*, int, proto_tree*);
121 static int resp_sched(tvbuff_t*, int, proto_tree*);
122 static int cmd_desc(tvbuff_t*, int, proto_tree*);
123 static int resp_desc(tvbuff_t*, int, proto_tree*);
124 static int cmd_upload(tvbuff_t*, int, proto_tree*);
125 static int cmd_delete(tvbuff_t*, int, proto_tree*);
126 static int cmd_list(tvbuff_t*, int, proto_tree*);
127 static int resp_list(tvbuff_t*, int, proto_tree*);
128 static int cmd_start(tvbuff_t*, int, proto_tree*);
129 static int resp_start(tvbuff_t*, int, proto_tree*);
130 static int resp_status(tvbuff_t*, int, proto_tree*);
131 static int cmd_options(tvbuff_t*, int, proto_tree*);
132 static int cmd_files(tvbuff_t*, int, proto_tree*);
133 static int resp_files(tvbuff_t*, int, proto_tree*);
134 static int eventnum(tvbuff_t*, int, proto_tree*);
135 static int speed(tvbuff_t*, int, proto_tree*);
136 static int filter_block(tvbuff_t*, int, proto_tree*);
137 static int blm_mode(tvbuff_t*, int, proto_tree*);
138 static int cmd_usdt(tvbuff_t*, int, proto_tree*);
139
140 static char *frame_type[] = {
141         "",
142         "Command request",
143         "Command response",
144         "Network (vehicle) data",
145         "Event",
146         "Miscellaneous",
147         "Text string"
148 };
149
150 /*
151  * Length of the frame header.
152  */
153 #define FRAME_HEADER_LEN        8
154
155 static guint
156 get_gryphon_pdu_len(tvbuff_t *tvb, int offset)
157 {
158     guint16 plen;
159     int padded_len;
160
161     /*
162      * Get the length of the Gryphon packet, and then get the length as
163      * padded to a 4-byte boundary.
164      */
165     plen = tvb_get_ntohs(tvb, offset + 4);
166     padded_len = plen + 3 - (plen + 3) % 4;
167
168     /*
169      * That length doesn't include the fixed-length part of the header;
170      * add that in.
171      */
172     return padded_len + FRAME_HEADER_LEN;
173 }
174
175 static void
176 dissect_gryphon_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
177 {
178     dissect_gryphon_message(tvb, pinfo, tree, FALSE);
179 }
180
181 static void
182 dissect_gryphon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
183 {
184     tcp_dissect_pdus(tvb, pinfo, tree, gryphon_desegment, FRAME_HEADER_LEN,
185         get_gryphon_pdu_len, dissect_gryphon_pdu);
186 }
187
188 static const value_string src_dest[] = {
189     {SD_CARD,           "Card"},
190     {SD_SERVER,         "Server"},
191     {SD_CLIENT,         "Client"},
192     {SD_SCHED,          "Scheduler"},
193     {SD_SCRIPT,         "Script Processor"},
194     {SD_PGM,            "Program Loader"},
195     {SD_USDT,           "USDT Server"},
196     {SD_BLM,            "Bus Load Monitoring"},
197     {SD_FLIGHT,         "Flight Recorder"},
198     {SD_RESP,           "Message Responder"},
199     {0,                 NULL}
200 };
201
202 static void
203 dissect_gryphon_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
204     gboolean is_msgresp_add)
205 {
206     int             offset = 0;
207     proto_tree      *gryphon_tree;
208     proto_item      *ti;
209     proto_tree      *header_tree, *body_tree, *localTree;
210     proto_item      *header_item, *body_item, *localItem;
211     int             start_offset, msgend;
212     int             msglen, msgpad;
213     unsigned int    src, dest, i, frmtyp;
214     guint8          flags;
215
216     if (!is_msgresp_add) {
217         if (check_col(pinfo->cinfo, COL_PROTOCOL))
218             col_set_str(pinfo->cinfo, COL_PROTOCOL, "Gryphon");
219         if (check_col(pinfo->cinfo, COL_INFO))
220             col_clear(pinfo->cinfo, COL_INFO);
221     }
222
223     if (!is_msgresp_add) {
224         ti = proto_tree_add_item(tree, proto_gryphon, tvb, 0, -1, FALSE);
225         gryphon_tree = proto_item_add_subtree(ti, ett_gryphon);
226     } else
227         gryphon_tree = tree;
228
229     src = tvb_get_guint8(tvb, offset + 0);
230     dest = tvb_get_guint8(tvb, offset + 2);
231     msglen = tvb_get_ntohs(tvb, offset + 4);
232     flags = tvb_get_guint8(tvb, offset + 6);
233     frmtyp = flags & ~RESPONSE_FLAGS;
234
235     if (!is_msgresp_add) {
236         /*
237          * This tvbuff includes padding to make its length a multiple
238          * of 4 bytes; set it to the actual length.
239          */
240         set_actual_length(tvb, msglen + FRAME_HEADER_LEN);
241
242         if (check_col(pinfo->cinfo, COL_INFO)) {
243             /*
244              * Indicate what kind of message this is.
245              */
246             if (frmtyp >= SIZEOF (frame_type))
247                 col_set_str(pinfo->cinfo, COL_INFO, "- Invalid -");
248             else
249                 col_set_str(pinfo->cinfo, COL_INFO, frame_type[frmtyp]);
250         }
251     }
252
253     if (tree == NULL)
254         return;
255
256     if (frmtyp >= SIZEOF (frame_type)) {
257         /*
258          * Unknown message type.
259          */
260         proto_tree_add_text(gryphon_tree, tvb, offset, msglen, "Data");
261         return;
262     }
263
264     header_item = proto_tree_add_text(gryphon_tree, tvb, offset, MSG_HDR_SZ, "Header");
265     header_tree = proto_item_add_subtree(header_item, ett_gryphon_header);
266     proto_tree_add_text(header_tree, tvb, offset, 2,
267         "Source: %s, channel %u",
268         val_to_str(src, src_dest, "Unknown (0x%02x)"),
269         tvb_get_guint8(tvb, offset + 1));
270     proto_tree_add_uint_hidden(header_tree, hf_gryph_src, tvb,
271         offset, 1, src);
272     proto_tree_add_uint_hidden(header_tree, hf_gryph_srcchan, tvb,
273         offset+1, 1, tvb_get_guint8(tvb, offset + 1));
274
275     proto_tree_add_text(header_tree, tvb, offset+2, 2,
276         "Destination: %s, channel %u",
277         val_to_str(dest, src_dest, "Unknown (0x%02x)"),
278         tvb_get_guint8(tvb, offset + 3));
279     proto_tree_add_uint_hidden(header_tree, hf_gryph_dest, tvb,
280         offset+2, 1, dest);
281     proto_tree_add_uint_hidden(header_tree, hf_gryph_destchan, tvb,
282         offset+3, 1, tvb_get_guint8(tvb, offset + 3));
283
284     proto_tree_add_text(header_tree, tvb, offset+4, 2,
285         "Data length: %u bytes", msglen);
286     proto_tree_add_text(header_tree, tvb, offset+6, 1,
287         "Frame type: %s", frame_type[frmtyp]);
288     if (is_msgresp_add) {
289         localItem = proto_tree_add_text(header_tree, tvb, offset+6, 1, "Flags");
290         localTree = proto_item_add_subtree (localItem, ett_gryphon_flags);
291         proto_tree_add_text(localTree, tvb, offset+6, 1, "%s",
292             decode_boolean_bitfield(flags, DONT_WAIT_FOR_RESP, 8,
293                 "Don't wait for response",
294                 "Wait for response"));
295         proto_tree_add_text(localTree, tvb, offset+6, 1, "%s",
296             decode_boolean_bitfield(flags, WAIT_FOR_PREV_RESP, 8,
297                 "Wait for previous responses",
298                 "Don't wait for previous responses"));
299     }
300     proto_tree_add_text(header_tree, tvb, offset+7, 1, "reserved");
301
302     proto_tree_add_uint_hidden(header_tree, hf_gryph_type, tvb,
303         offset+6, 1, frmtyp);
304     msgpad = 3 - (msglen + 3) % 4;
305     msgend = offset + msglen + msgpad + MSG_HDR_SZ;
306
307     body_item = proto_tree_add_text(gryphon_tree, tvb, offset + MSG_HDR_SZ,
308         msglen + msgpad, "Body");
309     body_tree = proto_item_add_subtree(body_item, ett_gryphon_body);
310
311     start_offset = offset;
312     offset += MSG_HDR_SZ;
313     switch (frmtyp) {
314     case GY_FT_CMD:
315         offset = decode_command(tvb, offset, dest, body_tree);
316         break;
317     case GY_FT_RESP:
318         offset = decode_response(tvb, offset, src, body_tree);
319         break;
320     case GY_FT_DATA:
321         offset = decode_data(tvb, offset, body_tree);
322         break;
323     case GY_FT_EVENT:
324         offset = decode_event(tvb, offset, body_tree);
325         break;
326     case GY_FT_MISC:
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_GET_RXDROP,        "Get number of dropped RX messages", NULL, NULL},
354         {CMD_RESET_RXDROP,      "Clear number of dropped RX messages", NULL, NULL},
355         {CMD_BCAST_ON,          "Set broadcasts on", NULL, NULL},
356         {CMD_BCAST_OFF,         "Set broadcasts off", NULL, NULL},
357         {CMD_CARD_SET_SPEED,    "Set channel baud rate", speed, NULL},
358         {CMD_CARD_GET_SPEED,    "Get channel baud rate", NULL, speed},
359         {CMD_CARD_SET_FILTER,   "Set filter (deprecated)", cmd_setfilt, NULL},
360         {CMD_CARD_GET_FILTER,   "Get filter", resp_addfilt, cmd_addfilt},
361         {CMD_CARD_TX,           "Transmit message", decode_data, NULL},
362         {CMD_CARD_TX_LOOP_ON,   "Set transmit loopback on", NULL, NULL},
363         {CMD_CARD_TX_LOOP_OFF,  "Set transmit loopback off", NULL, NULL},
364         {CMD_CARD_IOCTL,        "IOCTL pass-through", cmd_ioctl, NULL},
365         {CMD_CARD_ADD_FILTER,   "Add a filter", cmd_addfilt, resp_addfilt},
366         {CMD_CARD_MODIFY_FILTER, "Modify a filter", cmd_modfilt, NULL},
367         {CMD_CARD_GET_FILTER_HANDLES, "Get filter handles", NULL, resp_filthan},
368         {CMD_CARD_SET_DEFAULT_FILTER, "Set default filter", dfiltmode, NULL},
369         {CMD_CARD_GET_DEFAULT_FILTER, "Get default filter mode", NULL, dfiltmode},
370         {CMD_CARD_SET_FILTER_MODE, "Set filter mode", filtmode, NULL},
371         {CMD_CARD_GET_FILTER_MODE, "Get filter mode", NULL, filtmode},
372         {CMD_CARD_GET_EVNAMES,  "Get event names", NULL, resp_events},
373         {CMD_CARD_GET_SPEEDS,   "Get defined speeds", NULL, resp_getspeeds},
374         {CMD_SERVER_REG,        "Register with server", cmd_register, resp_register},
375         {CMD_SERVER_SET_SORT,   "Set the sorting behavior", cmd_sort, NULL},
376         {CMD_SERVER_SET_OPT,    "Set the type of optimization", cmd_optimize, NULL},
377         {CMD_BLM_SET_MODE,      "Set Bus Load Monitoring mode", blm_mode, NULL},
378         {CMD_BLM_GET_MODE,      "Get Bus Load Monitoring mode", NULL, blm_mode},
379         {CMD_BLM_GET_DATA,      "Get Bus Load data", NULL, resp_blm_data},
380         {CMD_BLM_GET_STATS,     "Get Bus Load statistics", NULL, resp_blm_stat},
381         {CMD_FLIGHT_GET_CONFIG, "Get flight recorder channel info", NULL, NULL},
382         {CMD_FLIGHT_START_MON,  "Start flight recorder monitoring", NULL, NULL},
383         {CMD_FLIGHT_STOP_MON,   "Stop flight recorder monitoring", NULL, NULL},
384         {CMD_MSGRESP_ADD,       "Add response message", cmd_addresp, resp_addresp},
385         {CMD_MSGRESP_GET,       "Get response message", resp_addresp, cmd_addresp},
386         {CMD_MSGRESP_MODIFY,    "Modify response message state", cmd_modresp, NULL},
387         {CMD_MSGRESP_GET_HANDLES, "Get response message handles", NULL, resp_resphan},
388         {CMD_PGM_DESC,          "Describe program to to uploaded", cmd_desc, resp_desc},
389         {CMD_PGM_UPLOAD,        "Upload a program to the Gryphon", cmd_upload, NULL},
390         {CMD_PGM_DELETE,        "Delete an uploaded program", cmd_delete, NULL},
391         {CMD_PGM_LIST,          "Get a list of uploaded programs", cmd_list, resp_list},
392         {CMD_PGM_START,         "Start an uploaded program", cmd_start, resp_start},
393         {CMD_PGM_STOP,          "Stop an uploaded program", resp_start, NULL},
394         {CMD_PGM_STATUS,        "Get status of an uploaded program", cmd_delete, resp_status},
395         {CMD_PGM_OPTIONS,       "Set program upload options", cmd_options, resp_status},
396         {CMD_PGM_FILES,         "Get a list of files & directories", cmd_files, resp_files},
397         {CMD_SCHED_TX,          "Schedule transmission of messages", cmd_sched, resp_sched},
398         {CMD_SCHED_KILL_TX,     "Stop and destroy a message transmission", NULL, NULL},
399         {CMD_SCHED_STOP_TX,     "Kill a message transmission (deprecated)", NULL, NULL},
400         {CMD_USDT_IOCTL,        "Register/Unregister with USDT server", cmd_usdt, NULL},
401         {-1,                    "- unknown -", NULL, NULL},
402         };
403
404 static const value_string responses[] = {
405         {RESP_OK,               "OK - no error"},
406         {RESP_UNKNOWN_ERR,      "Unknown error"},
407         {RESP_UNKNOWN_CMD,      "Unrecognised command"},
408         {RESP_UNSUPPORTED,      "Unsupported command"},
409         {RESP_INVAL_CHAN,       "Invalid channel specified"},
410         {RESP_INVAL_DST,        "Invalid destination"},
411         {RESP_INVAL_PARAM,      "Invalid parameter(s)"},
412         {RESP_INVAL_MSG,        "Invalid message"},
413         {RESP_INVAL_LEN,        "Invalid length field"},
414         {RESP_TX_FAIL,          "Transmit failed"},
415         {RESP_RX_FAIL,          "Receive failed"},
416         {RESP_AUTH_FAIL,        "Authorization failed"},
417         {RESP_MEM_ALLOC_ERR,    "Memory allocation error"},
418         {RESP_TIMEOUT,          "Command timed out"},
419         {RESP_UNAVAILABLE,      "Unavailable"},
420         {RESP_BUF_FULL,         "Buffer full"},
421         {RESP_NO_SUCH_JOB,      "No such job"},
422         {0,                     NULL},
423         };
424
425 static const value_string filter_data_types[] = {
426         {FILTER_DATA_TYPE_HEADER_FRAME, "frame header"},
427         {FILTER_DATA_TYPE_HEADER,       "data message header"},
428         {FILTER_DATA_TYPE_DATA,         "data message data"},
429         {FILTER_DATA_TYPE_EXTRA_DATA,   "data message extra data"},
430         {FILTER_EVENT_TYPE_HEADER,      "event message header"},
431         {FILTER_EVENT_TYPE_DATA,        "event message"},
432         {0,                             NULL},
433         };
434
435 static const value_string operators[] = {
436         {BIT_FIELD_CHECK,       "Bit field check"},
437         {SVALUE_GT,             "Greater than (signed)"},
438         {SVALUE_GE,             "Greater than or equal to (signed)"},
439         {SVALUE_LT,             "Less than (signed)"},
440         {SVALUE_LE,             "Less than or equal to (signed)"},
441         {VALUE_EQ,              "Equal to"},
442         {VALUE_NE,              "Not equal to"},
443         {UVALUE_GT,             "Greater than (unsigned)"},
444         {UVALUE_GE,             "Greater than or equal to (unsigned)"},
445         {UVALUE_LT,             "Less than (unsigned)"},
446         {UVALUE_LE,             "Less than or equal to (unsigned)"},
447         {DIG_LOW_TO_HIGH,       "Digital, low to high transistion"},
448         {DIG_HIGH_TO_LOW,       "Digital, high to low transistion"},
449         {DIG_TRANSITION,        "Digital, change of state"},
450         {0,                     NULL},
451         };
452
453 static const value_string modes[] = {
454         {FILTER_OFF_PASS_ALL,   "Filter off, pass all messages"},
455         {FILTER_OFF_BLOCK_ALL,  "Filter off, block all messages"},
456         {FILTER_ON,             "Filter on"},
457         {0,                     NULL},
458         };
459
460 static const value_string dmodes[] = {
461         {DEFAULT_FILTER_BLOCK,  "Block"},
462         {DEFAULT_FILTER_PASS,   "Pass"},
463         {0,                     NULL},
464         };
465
466 static const value_string filtacts[] = {
467         {DELETE_FILTER,         "Delete"},
468         {ACTIVATE_FILTER,       "Activate"},
469         {DEACTIVATE_FILTER,     "Deactivate"},
470         {0,                     NULL},
471         };
472
473 static const value_string ioctls[] = {
474         {GINIT,                 "GINIT: Initialize"},
475         {GLOOPON,               "GLOOPON: Loop on"},
476         {GLOOPOFF,              "GLOOPOFF: Loop off"},
477         {GGETHWTYPE,            "GGETHWTYPE: Get hardware type"},
478         {GGETREG,               "GGETREG: Get register"},
479         {GSETREG,               "GSETREG: Set register"},
480         {GGETRXCOUNT,           "GGETRXCOUNT: Get the receive message counter"},
481         {GSETRXCOUNT,           "GSETRXCOUNT: Set the receive message counter"},
482         {GGETTXCOUNT,           "GGETTXCOUNT: Get the transmit message counter"},
483         {GSETTXCOUNT,           "GSETTXCOUNT: Set the transmit message counter"},
484         {GGETRXDROP,            "GGETRXDROP: Get the number of dropped receive messages"},
485         {GSETRXDROP,            "GSETRXDROP: Set the number of dropped receive messages"},
486         {GGETTXDROP,            "GGETTXDROP: Get the number of dropped transmit messages"},
487         {GSETTXDROP,            "GSETTXDROP: Set the number of dropped transmit messages"},
488         {GGETRXBAD,             "GGETRXBAD: Get the number of bad receive messages"},
489         {GGETTXBAD,             "GGETTXBAD: Get the number of bad transmit messages"},
490         {GGETCOUNTS,            "GGETCOUNTS: Get total message counter"},
491         {GGETBLMON,             "GGETBLMON: Get bus load monitoring status"},
492         {GSETBLMON,             "GSETBLMON: Set bus load monitoring status (turn on/off)"},
493         {GGETERRLEV,            "GGETERRLEV: Get error level"},
494         {GSETERRLEV,            "GSETERRLEV: Set error level"},
495         {GGETBITRATE,           "GGETBITRATE: Get bit rate"},
496         {GGETRAM,               "GGETRAM: Read value from RAM"},
497         {GSETRAM,               "GSETRAM: Write value to RAM"},
498         {GCANGETBTRS,           "GCANGETBTRS: Read CAN bit timing registers"},
499         {GCANSETBTRS,           "GCANSETBTRS: Write CAN bit timing registers"},
500         {GCANGETBC,             "GCANGETBC: Read CAN byte count"},
501         {GCANSETBC,             "GCANSETBC: Write CAN byte count"},
502         {GCANGETMODE,           "GCANGETMODE"},
503         {GCANSETMODE,           "GCANSETMODE"},
504         {GCANGETTRANS,          "GCANGETTRANS"},
505         {GCANSETTRANS,          "GCANSETTRANS"},
506         {GCANSENDERR,           "GCANSENDERR"},
507         {GCANRGETOBJ,           "GCANRGETOBJ"},
508         {GCANRSETSTDID,         "GCANRSETSTDID"},
509         {GCANRSETEXTID,         "GCANRSETEXTID"},
510         {GCANRSETDATA,          "GCANRSETDATA"},
511         {GCANRENABLE,           "GCANRENABLE"},
512         {GCANRDISABLE,          "GCANRDISABLE"},
513         {GCANRGETMASKS,         "GCANRGETMASKS"},
514         {GCANRSETMASKS,         "GCANRSETMASKS"},
515         {GCANSWGETMODE,         "GCANSWGETMODE"},
516         {GCANSWSETMODE,         "GCANSWSETMODE"},
517         {GDLCGETFOURX,          "GDLCGETFOURX"},
518         {GDLCSETFOURX,          "GDLCSETFOURX"},
519         {GDLCGETLOAD,           "GDLCGETLOAD"},
520         {GDLCSETLOAD,           "GDLCSETLOAD"},
521         {GDLCSENDBREAK,         "GDLCSENDBREAK"},
522         {GDLCABORTTX,           "GDLCABORTTX"},
523         {GDLCGETHDRMODE,        "DLCGETHDRMODE"},
524         {GDLCSETHDRMODE,        "GDLCSETHDRMODE"},
525         {GHONSLEEP,             "GHONSLEEP"},
526         {GHONSILENCE,           "GHONSILENCE"},
527         {GKWPSETPTIMES,         "GKWPSETPTIMES"},
528         {GKWPSETWTIMES,         "GKWPSETWTIMES"},
529         {GKWPDOWAKEUP,          "GKWPDOWAKEUP"},
530         {GKWPGETBITTIME,        "GKWPGETBITTIME"},
531         {GKWPSETBITTIME,        "GKWPSETBITTIME"},
532         {GKWPSETNODEADDR,       "GKWPSETNODEADDR"},
533         {GKWPGETNODETYPE,       "GKWPGETNODETYPE"},
534         {GKWPSETNODETYPE,       "GKWPSETNODETYPE"},
535         {GKWPSETWAKETYPE,       "GKWPSETWAKETYPE"},
536         {GKWPSETTARGADDR,       "GKWPSETTARGADDR"},
537         {GKWPSETKEYBYTES,       "GKWPSETKEYBYTES"},
538         {GKWPSETSTARTREQ,       "GKWPSETSTARTREQ"},
539         {GKWPSETSTARTRESP,      "GKWPSETSTARTRESP"},
540         {GKWPSETPROTOCOL,       "GKWPSETPROTOCOL"},
541         {GKWPGETLASTKEYBYTES,   "GKWPGETLASTKEYBYTES"},
542         {GKWPSETLASTKEYBYTES,   "GKWPSETLASTKEYBYTES"},
543         {GSCPGETBBR,            "GSCPGETBBR"},
544         {GSCPSETBBR,            "GSCPSETBBR"},
545         {GSCPGETID,             "GSCPGETID"},
546         {GSCPSETID,             "GSCPSETID"},
547         {GSCPADDFUNCID,         "GSCPADDFUNCID"},
548         {GSCPCLRFUNCID,         "GSCPCLRFUNCID"},
549         {GUBPGETBITRATE,        "GUBPGETBITRATE"},
550         {GUBPSETBITRATE,        "GUBPSETBITRATE"},
551         {GUBPGETINTERBYTE,      "GUBPGETINTERBYTE"},
552         {GUBPSETINTERBYTE,      "GUBPSETINTERBYTE"},
553         {GUBPGETNACKMODE,       "GUBPGETNACKMODE"},
554         {GUBPSETNACKMODE,       "GUBPSETNACKMODE"},
555         {0,                     NULL},
556         };
557
558
559 static int
560 decode_command(tvbuff_t *tvb, int offset, int dst, proto_tree *pt)
561 {
562     int             cmd, padding, msglen;
563     unsigned int    i;
564     proto_tree      *ft;
565     proto_item      *ti;
566
567     msglen = tvb_reported_length_remaining(tvb, offset);
568     cmd = tvb_get_guint8(tvb, offset);
569     proto_tree_add_uint_hidden(pt, hf_gryph_cmd, tvb, offset, 1, cmd);
570     if (cmd > 0x3F)
571         cmd += dst * 256;
572
573     for (i = 0; i < SIZEOF(cmds); i++) {
574         if (cmds[i].value == cmd)
575             break;
576     }
577     if (i >= SIZEOF(cmds) && dst >= SD_KNOWN) {
578         cmd = (cmd & 0xFF) + SD_CARD * 256;
579         for (i = 0; i < SIZEOF(cmds); i++) {
580             if (cmds[i].value == cmd)
581                 break;
582         }
583     }
584     if (i >= SIZEOF(cmds))
585         i = SIZEOF(cmds) - 1;
586
587     proto_tree_add_text (pt, tvb, offset, 4, "Command: %s", cmds[i].strptr);
588     offset += 4;
589     msglen -= 4;
590
591     if (cmds[i].cmd_fnct && msglen > 0) {
592         padding = 3 - (msglen + 3) % 4;
593         ti = proto_tree_add_text(pt, tvb, offset, -1, "Data: (%d bytes)", msglen);
594         ft = proto_item_add_subtree(ti, ett_gryphon_command_data);
595         offset = (*(cmds[i].cmd_fnct)) (tvb, offset, ft);
596     }
597     return offset;
598 }
599
600 static int
601 decode_response(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
602 {
603     int             cmd, msglen;
604     unsigned int    i, resp;
605     proto_tree      *ft;
606     proto_item      *ti;
607
608     msglen = tvb_reported_length_remaining(tvb, offset);
609     cmd = tvb_get_guint8(tvb, offset);
610     if (cmd > 0x3F)
611         cmd += src * 256;
612
613     for (i = 0; i < SIZEOF(cmds); i++) {
614         if (cmds[i].value == cmd)
615             break;
616     }
617     if (i >= SIZEOF(cmds) && src >= SD_KNOWN) {
618         cmd = (cmd & 0xFF) + SD_CARD * 256;
619         for (i = 0; i < SIZEOF(cmds); i++) {
620             if (cmds[i].value == cmd)
621                 break;
622         }
623     }
624     if (i >= SIZEOF(cmds))
625         i = SIZEOF(cmds) - 1;
626     proto_tree_add_text (pt, tvb, offset, 4, "Command: %s", cmds[i].strptr);
627     offset += 4;
628     msglen -= 4;
629
630     resp = tvb_get_ntohl (tvb, offset);
631     proto_tree_add_text (pt, tvb, offset, 4, "Status: %s",
632         val_to_str(resp, responses, "Unknown (0x%08x)"));
633     offset += 4;
634     msglen -= 4;
635
636     if (cmds[i].rsp_fnct && msglen > 0) {
637         ti = proto_tree_add_text(pt, tvb, offset, msglen, "Data: (%d bytes)", msglen);
638         ft = proto_item_add_subtree(ti, ett_gryphon_response_data);
639         offset = (*(cmds[i].rsp_fnct)) (tvb, offset, ft);
640     }
641     return offset;
642 }
643
644 static int
645 decode_data(tvbuff_t *tvb, int offset, proto_tree *pt)
646 {
647     proto_item  *item, *item1;
648     proto_tree  *tree, *tree1;
649     int     hdrsize, datasize, extrasize, hdrbits, msgsize, padding, mode;
650     int     hours, minutes, seconds, fraction;
651     unsigned long   timestamp;
652
653     hdrsize = tvb_get_guint8(tvb, offset+0);
654     hdrbits = tvb_get_guint8(tvb, offset+1);
655     datasize = tvb_get_ntohs(tvb, offset+2);
656     extrasize = tvb_get_guint8(tvb, offset+4);
657     padding = 3 - (hdrsize + datasize + extrasize + 3) % 4;
658     msgsize = hdrsize + datasize + extrasize + padding + 16;
659
660     item = proto_tree_add_text(pt, tvb, offset, 16, "Message header");
661     tree = proto_item_add_subtree (item, ett_gryphon_data_header);
662     proto_tree_add_text(tree, tvb, offset, 2, "Header length: %d bytes, %d bits", hdrsize, hdrbits);
663     proto_tree_add_text(tree, tvb, offset+2, 2, "Data length: %d bytes", datasize);
664     proto_tree_add_text(tree, tvb, offset+4, 1, "Extra data length: %d bytes", extrasize);
665     mode = tvb_get_guint8(tvb, offset+5);
666     item1 = proto_tree_add_text(tree, tvb, offset+5, 1, "Mode: %d", mode);
667     if (mode) {
668         tree1 = proto_item_add_subtree (item1, ett_gryphon_flags);
669         if (mode & 0x80) {
670             proto_tree_add_text(tree1, tvb, offset+5, 1, "%s",
671                 decode_boolean_bitfield(mode, 0x80, 8,
672                     "Transmitted message", NULL));
673         }
674         if (mode & 0x40) {
675             proto_tree_add_text(tree1, tvb, offset+5, 1, "%s",
676                 decode_boolean_bitfield(mode, 0x40, 8,
677                     "Received message", NULL));
678         }
679         if (mode & 0x20) {
680             proto_tree_add_text(tree1, tvb, offset+5, 1, "%s",
681                 decode_boolean_bitfield(mode, 0x20, 8,
682                     "Local message", NULL));
683         }
684         if (mode & 0x10) {
685             proto_tree_add_text(tree1, tvb, offset+5, 1, "%s",
686                 decode_boolean_bitfield(mode, 0x10, 8,
687                     "Remote message", NULL));
688         }
689         if (mode & 0x01) {
690             proto_tree_add_text(tree1, tvb, offset+5, 1, "%s",
691                 decode_boolean_bitfield(mode, 0x01, 8,
692                     "Internal message", NULL));
693         }
694     }
695     proto_tree_add_text(tree, tvb, offset+6, 1, "Priority: %u",
696         tvb_get_guint8(tvb, offset+6));
697     proto_tree_add_text(tree, tvb, offset+7, 1, "Error status: %u",
698         tvb_get_guint8(tvb, offset+7));
699     timestamp = tvb_get_ntohl(tvb, offset+8);
700     hours = timestamp /(100000 * 60 *60);
701     minutes = (timestamp / (100000 * 60)) % 60;
702     seconds = (timestamp / 100000) % 60;
703     fraction = timestamp % 100000;
704     proto_tree_add_text(tree, tvb, offset+8, 4, "Timestamp: %d:%02d:%02d.%05d", hours, minutes, seconds, fraction);
705     proto_tree_add_text(tree, tvb, offset+12, 1, "Context: %u",
706         tvb_get_guint8(tvb, offset+12));
707     proto_tree_add_text(tree, tvb, offset+13, 3, "reserved:");
708     offset += 16;
709     item = proto_tree_add_text(pt, tvb, offset, msgsize-16-padding, "Message Body");
710     tree = proto_item_add_subtree (item, ett_gryphon_data_body);
711     if (hdrsize) {
712         proto_tree_add_text(tree, tvb, offset, hdrsize, "Header");
713         offset += hdrsize;
714     }
715     if (datasize) {
716         proto_tree_add_text(tree, tvb, offset, datasize, "Data");
717         offset += datasize;
718     }
719     if (extrasize) {
720         proto_tree_add_text(tree, tvb, offset, extrasize, "Extra data");
721         offset += extrasize;
722     }
723     if (padding) {
724         proto_tree_add_text(pt, tvb, offset, padding, "padding");
725         offset += padding;
726     }
727     return offset;
728 }
729
730 static int
731 decode_event(tvbuff_t *tvb, int offset, proto_tree *pt)
732 {
733     int             msglen;
734     int             hours, minutes, seconds, fraction, padding, length;
735     unsigned long   timestamp;
736     int             msgend;
737
738     msglen = tvb_reported_length_remaining(tvb, offset);
739     padding = 3 - (msglen + 3) % 4;
740     msgend = offset + msglen;
741     proto_tree_add_text(pt, tvb, offset, 1, "Event ID: %u",
742         tvb_get_guint8(tvb, offset));
743     proto_tree_add_text(pt, tvb, offset+1, 1, "Event context: %u",
744         tvb_get_guint8(tvb, offset+1));
745     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
746     offset += 4;
747     timestamp = tvb_get_ntohl(tvb, offset);
748     hours = timestamp /(100000 * 60 *60);
749     minutes = (timestamp / (100000 * 60)) % 60;
750     seconds = (timestamp / 100000) % 60;
751     fraction = timestamp % 100000;
752     proto_tree_add_text(pt, tvb, offset, 4, "Timestamp: %d:%02d:%02d.%05d", hours, minutes, seconds, fraction);
753     offset += 4;
754     if (offset < msgend) {
755         length = msgend - offset;
756         proto_tree_add_text (pt, tvb, offset, length, "Data (%d bytes)", length);
757         offset += length;
758     }
759     if (padding) {
760         proto_tree_add_text(pt, tvb, offset, padding, "padding");
761         offset += padding;
762     }
763     return offset;
764 }
765
766 static int
767 cmd_init(tvbuff_t *tvb, int offset, proto_tree *pt)
768 {
769     char        *ptr;
770
771     if (tvb_get_guint8(tvb, offset) == 0)
772         ptr = "Always initialize";
773     else
774         ptr = "Initialize if not previously initialized";
775     proto_tree_add_text(pt, tvb, offset, 1, "Mode: %s", ptr);
776     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
777     offset += 4;
778     return offset;
779 }
780
781 static int
782 eventnum(tvbuff_t *tvb, int offset, proto_tree *pt)
783 {
784     guint8      event = tvb_get_guint8(tvb, offset);
785
786     if (event)
787         proto_tree_add_text(pt, tvb, offset, 1, "Event number: %u", event);
788     else
789         proto_tree_add_text(pt, tvb, offset, 1, "Event numbers: All");
790     proto_tree_add_text(pt, tvb, offset+1, 3, "padding");
791     offset += 4;
792     return offset;
793 }
794
795 static int
796 resp_time(tvbuff_t *tvb, int offset, proto_tree *pt)
797 {
798     int     hours, minutes, seconds, fraction;
799     union {
800         unsigned int            lng[2];
801         guint64                 lnglng;
802     } ts;
803     unsigned int    timestamp;
804     unsigned char   date[45];
805
806     ts.lng[1] = tvb_get_ntohl(tvb, offset);
807     ts.lng[0] = tvb_get_ntohl(tvb, offset + 4);
808     timestamp = ts.lnglng / 100000L;
809     strncpy (date, ctime((time_t*)&timestamp), sizeof(date));
810     date[strlen(date)-1] = 0x00;
811     proto_tree_add_text(pt, tvb, offset, 8, "Date/Time: %s", date);
812     timestamp = ts.lng[0];
813     hours = timestamp /(100000 * 60 *60);
814     minutes = (timestamp / (100000 * 60)) % 60;
815     seconds = (timestamp / 100000) % 60;
816     fraction = timestamp % 100000;
817     proto_tree_add_text(pt, tvb, offset+4, 4, "Timestamp: %d:%02d:%02d.%05d", hours, minutes, seconds, fraction);
818     offset += 8;
819     return offset;
820 }
821
822 static int
823 cmd_setfilt(tvbuff_t *tvb, int offset, proto_tree *pt)
824 {
825     int             flag = tvb_get_ntohl(tvb, offset);
826     int             length, padding;
827     unsigned char   mode[30];
828
829     length =  tvb_get_guint8(tvb, offset+4) + tvb_get_guint8(tvb, offset+5)
830         + tvb_get_ntohs(tvb, offset+6);
831     if (flag)
832         strcpy (mode, "Pass");
833     else
834         strcpy (mode, "Block");
835     if (length == 0)
836         strcat (mode, " all");
837     proto_tree_add_text(pt, tvb, offset, 4, "Pass/Block flag: %s", mode);
838     proto_tree_add_text(pt, tvb, offset+4, 4, "Length of Pattern & Mask: %d", length);
839     offset += 8;
840     if (length) {
841         proto_tree_add_text(pt, tvb, offset, length * 2, "discarded data");
842         offset += length * 2;
843     }
844     padding = 3 - (length * 2 + 3) % 4;
845     if (padding) {
846         proto_tree_add_text(pt, tvb, offset+1, 3, "padding");
847         offset += padding;
848     }
849     return offset;
850 }
851
852 static int
853 cmd_ioctl(tvbuff_t *tvb, int offset, proto_tree *pt)
854 {
855     int             msglen;
856     unsigned int    ioctl;
857
858     msglen = tvb_reported_length_remaining(tvb, offset);
859     ioctl = tvb_get_ntohl(tvb, offset);
860     proto_tree_add_text(pt, tvb, offset, 4, "IOCTL: %s",
861         val_to_str(ioctl, ioctls, "Unknown (0x%08x)"));
862     offset += 4;
863     msglen -= 4;
864     if (msglen > 0) {
865         proto_tree_add_text(pt, tvb, offset, msglen, "Data");
866         offset += msglen;
867     }
868     return offset;
869 }
870
871 static int
872 cmd_addfilt(tvbuff_t *tvb, int offset, proto_tree *pt)
873 {
874     proto_item  *item;
875     proto_tree  *tree;
876     guint8      flags;
877     int         blocks, i, length;
878
879     item = proto_tree_add_text(pt, tvb, offset, 1, "Flags");
880     tree = proto_item_add_subtree (item, ett_gryphon_flags);
881     flags = tvb_get_guint8(tvb, offset);
882     proto_tree_add_text(tree, tvb, offset, 1, "%s",
883         decode_boolean_bitfield(flags, FILTER_PASS_FLAG, 8,
884             "Conforming messages are passed",
885             "Conforming messages are blocked"));
886     proto_tree_add_text(tree, tvb, offset, 1, "%s",
887         decode_boolean_bitfield(flags, FILTER_ACTIVE_FLAG, 8,
888             "The filter is active", "The filter is inactive"));
889     offset += 1;
890     blocks = tvb_get_guint8(tvb, offset);
891     proto_tree_add_text(pt, tvb, offset, 1, "Number of filter blocks = %d", blocks);
892     proto_tree_add_text(pt, tvb, offset+1, 6, "reserved");
893     offset += 7;
894     for (i = 1; i <= blocks; i++) {
895         length = tvb_get_ntohs(tvb, offset+2) * 2 + 8;
896         length += 3 - (length + 3) % 4;
897         item = proto_tree_add_text(pt, tvb, offset, length, "Filter block %d", i);
898         tree = proto_item_add_subtree (item, ett_gryphon_cmd_filter_block);
899         offset = filter_block(tvb, offset, tree);
900     }
901     return offset;
902 }
903
904 static int
905 resp_addfilt(tvbuff_t *tvb, int offset, proto_tree *pt)
906 {
907     proto_tree_add_text(pt, tvb, offset, 1, "Filter handle: %u",
908         tvb_get_guint8(tvb, offset));
909     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
910     offset += 4;
911     return offset;
912 }
913
914 static int
915 cmd_modfilt(tvbuff_t *tvb, int offset, proto_tree *pt)
916 {
917     guint8          filter_handle;
918     unsigned char   action;
919
920     filter_handle = tvb_get_guint8(tvb, offset);
921     if (filter_handle)
922         proto_tree_add_text(pt, tvb, offset, 1, "Filter handle: %u",
923             filter_handle);
924     else
925         proto_tree_add_text(pt, tvb, offset, 1, "Filter handles: all");
926     action = tvb_get_guint8(tvb, offset + 1);
927     proto_tree_add_text(pt, tvb, offset+1, 1, "Action: %s filter",
928         val_to_str(action, filtacts, "Unknown (%u)"));
929     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
930     offset += 4;
931     return offset;
932 }
933
934 static int
935 resp_filthan(tvbuff_t *tvb, int offset, proto_tree *pt)
936 {
937     int         handles = tvb_get_guint8(tvb, offset);
938     int         i, padding;
939
940     proto_tree_add_text(pt, tvb, offset, 1, "Number of filter handles: %d", handles);
941     for (i = 1; i <= handles; i++){
942         proto_tree_add_text(pt, tvb, offset+i, 1, "Handle %d: %u", i,
943             tvb_get_guint8(tvb, offset+i));
944     }
945     padding = 3 - (handles + 1 + 3) % 4;
946     if (padding)
947         proto_tree_add_text(pt, tvb, offset+1+handles, padding, "padding");
948     offset += 1+handles+padding;
949     return offset;
950 }
951
952 static int
953 dfiltmode(tvbuff_t *tvb, int offset, proto_tree *pt)
954 {
955     unsigned char   mode;
956
957     mode = tvb_get_guint8(tvb, offset);
958     proto_tree_add_text(pt, tvb, offset, 1, "Filter mode: %s",
959         val_to_str(mode, dmodes, "Unknown (%u)"));
960     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
961     offset += 4;
962     return offset;
963 }
964
965 static int
966 filtmode(tvbuff_t *tvb, int offset, proto_tree *pt)
967 {
968     unsigned char   mode;
969
970     mode = tvb_get_guint8(tvb, offset);
971     proto_tree_add_text(pt, tvb, offset, 1, "Filter mode: %s",
972         val_to_str(mode, dmodes, "Unknown (%u)"));
973     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
974     offset += 4;
975     return offset;
976 }
977
978 static int
979 resp_events(tvbuff_t *tvb, int offset, proto_tree *pt)
980 {
981     int             msglen;
982     unsigned int    i;
983     proto_tree      *tree;
984     proto_item      *item;
985
986     msglen = tvb_reported_length_remaining(tvb, offset);
987     i = 1;
988     while (msglen != 0) {
989         item = proto_tree_add_text(pt, tvb, offset, 20, "Event %d:", i);
990         tree = proto_item_add_subtree (item, ett_gryphon_cmd_events_data);
991         proto_tree_add_text(tree, tvb, offset, 1, "Event ID: %u",
992             tvb_get_guint8(tvb, offset));
993         proto_tree_add_text(tree, tvb, offset+1, 19, "Event name: %.19s",
994                 tvb_get_ptr(tvb, offset+1, 19));
995         offset += 20;
996         msglen -= 20;
997         i++;
998     }
999     return offset;
1000 }
1001
1002 static int
1003 cmd_register(tvbuff_t *tvb, int offset, proto_tree *pt)
1004 {
1005     proto_tree_add_text(pt, tvb, offset, 16, "Username: %.16s",
1006         tvb_get_ptr(tvb, offset, 16));
1007     offset += 16;
1008     proto_tree_add_text(pt, tvb, offset, 32, "Password: %.32s",
1009         tvb_get_ptr(tvb, offset, 32));
1010     offset += 32;
1011     return offset;
1012 }
1013
1014 static int
1015 resp_register(tvbuff_t *tvb, int offset, proto_tree *pt)
1016 {
1017     proto_tree_add_text(pt, tvb, offset, 1, "Client ID: %u",
1018         tvb_get_guint8(tvb, offset));
1019     proto_tree_add_text(pt, tvb, offset+1, 1, "Privileges: %u",
1020         tvb_get_guint8(tvb, offset+1));
1021     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1022     offset += 4;
1023     return offset;
1024 }
1025
1026
1027 static int
1028 resp_getspeeds(tvbuff_t *tvb, int offset, proto_tree *pt)
1029 {
1030     int size;
1031     int number;
1032     int index;
1033
1034     proto_tree_add_text(pt, tvb, offset, 4, "Set Speed IOCTL");
1035     proto_tree_add_text(pt, tvb, offset+4, 4, "Get Speed IOCTL");
1036     size = tvb_get_guint8(tvb, offset+8);
1037     proto_tree_add_text(pt, tvb, offset+8, 1, "Speed data size is %d bytes", size);
1038     number = tvb_get_guint8(tvb, offset+9);
1039     proto_tree_add_text(pt, tvb, offset+9, 1, "There are %d preset speeds", number);
1040     offset += 10;
1041     for (index = 0; index < number; index++) {
1042         proto_tree_add_text(pt, tvb, offset, size, "Data for preset %d",
1043             index+1);
1044         offset += size;
1045     }
1046     return offset;
1047 }
1048
1049 static int
1050 cmd_sort(tvbuff_t *tvb, int offset, proto_tree *pt)
1051 {
1052     char        *which;
1053
1054     which = tvb_get_guint8(tvb, offset) ?
1055             "Sort into blocks of up to 16 messages" :
1056             "Do not sort messages";
1057     proto_tree_add_text(pt, tvb, offset, 1, "Set sorting: %s", which);
1058     offset += 1;
1059     return offset;
1060 }
1061
1062 static int
1063 cmd_optimize(tvbuff_t *tvb, int offset, proto_tree *pt)
1064 {
1065     char        *which;
1066
1067     which = tvb_get_guint8(tvb, offset) ?
1068             "Optimize for latency (Nagle algorithm disabled)" :
1069             "Optimize for throughput (Nagle algorithm enabled)";
1070     proto_tree_add_text(pt, tvb, offset, 1, "Set optimization: %s", which);
1071     offset += 1;
1072     return offset;
1073 }
1074
1075 static int
1076 resp_config(tvbuff_t *tvb, int offset, proto_tree *pt)
1077 {
1078     proto_item  *ti;
1079     proto_tree  *ft;
1080     int         devices;
1081     int         i;
1082     unsigned int x;
1083
1084     static const value_string protocol_types[] = {
1085         {GDUMMY * 256 + GDGDMARKONE,    "Dummy device driver"},
1086         {GCAN * 256 + G82527,           "CAN, 82527 subtype"},
1087         {GCAN * 256 + GSJA1000,         "CAN, SJA1000 subtype"},
1088         {GCAN * 256 + G82527SW,         "CAN, 82527 single wire subtype"},
1089         {GJ1850 * 256 + GHBCCPAIR,      "J1850, HBCC subtype"},
1090         {GJ1850 * 256 + GDLC,           "J1850, GM DLC subtype"},
1091         {GJ1850 * 256 + GCHRYSLER,      "J1850, Chrysler subtype"},
1092         {GJ1850 * 256 + GDEHC12,        "J1850, DE HC12 KWP/BDLC subtype"},
1093         {GKWP2000 * 256 + GDEHC12KWP,   "Keyword protocol 2000"},
1094         {GHONDA * 256 + GDGHC08,        "Honda UART, DG HC08 subtype"},
1095         {GFORDUBP * 256 + GDGUBP08,     "Ford UBP, DG HC08 subtype"},
1096         {0,                             NULL},
1097     };
1098
1099     proto_tree_add_text(pt, tvb, offset, 20, "Device name: %.20s",
1100         tvb_get_ptr(tvb, offset, 20));
1101     offset += 20;
1102
1103     proto_tree_add_text(pt, tvb, offset, 8, "Device version: %.8s",
1104         tvb_get_ptr(tvb, offset, 8));
1105     offset += 8;
1106
1107     proto_tree_add_text(pt, tvb, offset, 20, "Device serial number: %.20s",
1108         tvb_get_ptr(tvb, offset, 20));
1109     offset += 20;
1110
1111     devices = tvb_get_guint8(tvb, offset);
1112     proto_tree_add_text(pt, tvb, offset, 1, "Number of channels: %d", devices);
1113     proto_tree_add_text(pt, tvb, offset+1, 15, "reserved");
1114     offset += 16;
1115     for (i = 1; i <= devices; i++) {
1116         ti = proto_tree_add_text(pt, tvb, offset, 80, "Channel %d:", i);
1117         ft = proto_item_add_subtree(ti, ett_gryphon_cmd_config_device);
1118         proto_tree_add_text(ft, tvb, offset, 20, "Driver name: %.20s",
1119             tvb_get_ptr(tvb, offset, 20));
1120         offset += 20;
1121
1122         proto_tree_add_text(ft, tvb, offset, 8, "Driver version: %.8s",
1123             tvb_get_ptr(tvb, offset, 8));
1124         offset += 8;
1125
1126         proto_tree_add_text(ft, tvb, offset, 24, "Device security string: %.24s",
1127             tvb_get_ptr(tvb, offset, 24));
1128         offset += 24;
1129
1130         proto_tree_add_text(ft, tvb, offset, 20, "Hardware serial number: %.20s",
1131             tvb_get_ptr(tvb, offset, 20));
1132         offset += 20;
1133
1134         x = tvb_get_ntohs(tvb, offset);
1135         proto_tree_add_text(ft, tvb, offset, 2, "Protocol type & subtype: %s",
1136             val_to_str(x, protocol_types, "Unknown (0x%04x)"));
1137         offset += 2;
1138
1139         proto_tree_add_text(ft, tvb, offset, 1, "Channel ID: %u",
1140             tvb_get_guint8(tvb, offset));
1141         proto_tree_add_text(ft, tvb, offset+1, 5, "reserved");
1142         offset += 6;
1143     }
1144     return offset;
1145 }
1146
1147 static int
1148 cmd_sched(tvbuff_t *tvb, int offset, proto_tree *pt)
1149 {
1150     int             msglen;
1151     proto_item      *item, *item1;
1152     proto_tree      *tree, *tree1;
1153     int             save_offset;
1154     unsigned int    i, x, length;
1155     unsigned char   def_chan = tvb_get_guint8(tvb, offset-9);
1156
1157     msglen = tvb_reported_length_remaining(tvb, offset);
1158     x = tvb_get_ntohl(tvb, offset);
1159     if (x == 0xFFFFFFFF)
1160         proto_tree_add_text(pt, tvb, offset, 4, "Number of iterations: infinite");
1161     else
1162         proto_tree_add_text(pt, tvb, offset, 4, "Number of iterations: %u", x);
1163     offset += 4;
1164     msglen -= 4;
1165     x = tvb_get_ntohl(tvb, offset);
1166     item = proto_tree_add_text(pt, tvb, offset, 4, "Flags: 0x%08x", x);
1167     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1168     proto_tree_add_text(tree, tvb, offset, 4, "%s",
1169         decode_boolean_bitfield(x, 0x01, 32,
1170             "Critical scheduler", "Normal scheduler"));
1171     offset += 4;
1172     msglen -= 4;
1173     i = 1;
1174     while (msglen > 0) {
1175         length = 16 + tvb_get_guint8(tvb, offset+16) +
1176             tvb_get_ntohs(tvb, offset+18) + tvb_get_guint8(tvb, offset+20) + 16;
1177         length += 3 - (length + 3) % 4;
1178         item = proto_tree_add_text(pt, tvb, offset, length, "Message %d", i);
1179         tree = proto_item_add_subtree (item, ett_gryphon_cmd_sched_data);
1180         x = tvb_get_ntohl(tvb, offset);
1181         proto_tree_add_text(tree, tvb, offset, 4, "Sleep: %u milliseconds", x);
1182         offset += 4;
1183         msglen -= 4;
1184         x = tvb_get_ntohl(tvb, offset);
1185         proto_tree_add_text(tree, tvb, offset, 4, "Transmit count: %u", x);
1186         offset += 4;
1187         msglen -= 4;
1188         x = tvb_get_ntohl(tvb, offset);
1189         proto_tree_add_text(tree, tvb, offset, 4, "Transmit period: %u milliseconds", x);
1190         offset += 4;
1191         msglen -= 4;
1192         proto_tree_add_text(tree, tvb, offset, 2, "reserved flags");
1193         x = tvb_get_guint8(tvb, offset+2);
1194         if (x == 0)
1195             x = def_chan;
1196         proto_tree_add_text(tree, tvb, offset+2, 1, "Channel: %u", x);
1197         proto_tree_add_text(tree, tvb, offset+3, 1, "reserved");
1198         offset += 4;
1199         msglen -= 4;
1200         item1 = proto_tree_add_text(tree, tvb, offset, length, "Message");
1201         tree1 = proto_item_add_subtree (item1, ett_gryphon_cmd_sched_cmd);
1202         save_offset = offset;
1203         offset = decode_data(tvb, offset, tree1);
1204         msglen -= offset - save_offset;
1205         i++;
1206     }
1207     return offset;
1208 }
1209
1210 static int
1211 resp_blm_data(tvbuff_t *tvb, int offset, proto_tree *pt)
1212 {
1213     unsigned int    i;
1214     int             hours, minutes, seconds, fraction, x, fract;
1215     unsigned long   timestamp;
1216     static char    *fields[] = {
1217         "Bus load average: %d.%02d%%",
1218         "Current bus load: %d.%02d%%",
1219         "Peak bus load: %d.%02d%%",
1220         "Historic peak bus load: %d.%02d%%"
1221     };
1222
1223     timestamp = tvb_get_ntohl(tvb, offset);
1224     hours = timestamp /(100000 * 60 *60);
1225     minutes = (timestamp / (100000 * 60)) % 60;
1226     seconds = (timestamp / 100000) % 60;
1227     fraction = timestamp % 100000;
1228     proto_tree_add_text(pt, tvb, offset, 4, "Timestamp: %d:%02d:%02d.%05d", hours, minutes, seconds, fraction);
1229     offset += 4;
1230     for (i = 0; i < SIZEOF(fields); i++){
1231         x = tvb_get_ntohs(tvb, offset);
1232         fract = x % 100;
1233         x /= 100;
1234         proto_tree_add_text(pt, tvb, offset, 2, fields[i], x, fract);
1235         offset += 2;
1236     }
1237     return offset;
1238 }
1239
1240 static int
1241 resp_blm_stat(tvbuff_t *tvb, int offset, proto_tree *pt)
1242 {
1243     unsigned int    x, i;
1244     char            *fields[] = {
1245         "Receive frame count: %u",
1246         "Transmit frame count: %u",
1247         "Receive dropped frame count: %u",
1248         "Transmit dropped frame count: %u",
1249         "Receive error count: %u",
1250         "Transmit error count: %u",
1251     };
1252
1253     offset = resp_blm_data(tvb, offset, pt);
1254     for (i = 0; i < SIZEOF(fields); i++){
1255         x = tvb_get_ntohl(tvb, offset);
1256         proto_tree_add_text(pt, tvb, offset, 4, fields[i], x);
1257         offset += 4;
1258     }
1259     return offset;
1260 }
1261
1262 static const value_string action_vals[] = {
1263     { FR_RESP_AFTER_EVENT,  "Send response(s) for each conforming message" },
1264     { FR_RESP_AFTER_PERIOD, "Send response(s) after the specified period expires following a conforming message" },
1265     { FR_IGNORE_DURING_PER, "Send response(s) for a conforming message and ignore\nfurther messages until the specified period expires" },
1266     { 0,                    NULL }
1267 };
1268
1269 static const value_string deact_on_event_vals[] = {
1270     { FR_DEACT_ON_EVENT,
1271         "Deactivate this response for a conforming message" },
1272     { FR_DELETE|FR_DEACT_ON_EVENT,
1273         "Delete this response for a conforming message" },
1274     { 0,
1275         NULL }
1276 };
1277
1278 static const value_string deact_after_per_vals[] = {
1279     { FR_DEACT_AFTER_PER,
1280         "Deactivate this response after the specified period following a conforming message" },
1281     { FR_DELETE|FR_DEACT_AFTER_PER,
1282         "Delete this response after the specified period following a conforming message" },
1283     { 0,
1284         NULL }
1285 };
1286
1287 static int
1288 cmd_addresp(tvbuff_t *tvb, int offset, proto_tree *pt)
1289 {
1290     proto_item  *item;
1291     proto_tree  *tree;
1292     guint8      flags;
1293     int         blocks, responses, old_handle, i, msglen, length;
1294     int         action, actionType, actionValue;
1295     tvbuff_t    *next_tvb;
1296
1297     actionType = 0;
1298     flags = tvb_get_guint8(tvb, offset);
1299     item = proto_tree_add_text(pt, tvb, offset, 1, "Flags: 0x%02x", flags);
1300     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1301     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1302         decode_boolean_bitfield(flags, FILTER_ACTIVE_FLAG, 8,
1303                 "The response is active", "The response is inactive"));
1304     offset += 1;
1305     blocks = tvb_get_guint8(tvb, offset);
1306     proto_tree_add_text(pt, tvb, offset, 1, "Number of filter blocks = %d", blocks);
1307     offset += 1;
1308     responses = tvb_get_guint8(tvb, offset);
1309     proto_tree_add_text(pt, tvb, offset, 1, "Number of response blocks = %d", responses);
1310     offset += 1;
1311     old_handle = tvb_get_guint8(tvb, offset);
1312     proto_tree_add_text(pt, tvb, offset, 1, "Old handle = %d", old_handle);
1313     offset += 1;
1314     action = tvb_get_guint8(tvb, offset);
1315     item = proto_tree_add_text(pt, tvb, offset, 1, "Action: %s",
1316         val_to_str(action & 0x07, action_vals, "Unknown (%u)"));
1317     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1318     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1319         decode_enumerated_bitfield(action, 0x07, 8, action_vals, "%s"));
1320     actionValue = tvb_get_ntohs(tvb, offset+2);
1321     if (actionValue) {
1322         if (action & FR_PERIOD_MSGS) {
1323             actionType = 1;
1324         } else {
1325             actionType = 0;
1326         }
1327         proto_tree_add_text(tree, tvb, offset, 1, "%s",
1328             decode_boolean_bitfield(action, FR_PERIOD_MSGS, 8,
1329                 "The period is in frames", "The period is in 0.01 seconds"));
1330     }
1331     if (action & FR_DEACT_ON_EVENT) {
1332         proto_tree_add_text(tree, tvb, offset, 1, "%s",
1333             decode_enumerated_bitfield(action, FR_DELETE|FR_DEACT_ON_EVENT, 8,
1334                 deact_on_event_vals, "%s"));
1335     }
1336     if (action & FR_DEACT_AFTER_PER) {
1337         proto_tree_add_text(tree, tvb, offset, 1, "%s",
1338             decode_enumerated_bitfield(action, FR_DELETE|FR_DEACT_AFTER_PER, 8,
1339                 deact_after_per_vals, "%s"));
1340     }
1341     offset += 1;
1342     proto_tree_add_text(pt, tvb, offset, 1, "reserved");
1343     offset += 1;
1344     if (actionValue) {
1345         if (actionType == 1) {
1346             proto_tree_add_text(tree, tvb, offset, 2, "Period: %d messages", actionValue);
1347         } else {
1348             proto_tree_add_text(tree, tvb, offset, 2, "Period: %d.%02d seconds", actionValue/100, actionValue%100);
1349         }
1350     }
1351     offset += 2;
1352     for (i = 1; i <= blocks; i++) {
1353         length = tvb_get_ntohs(tvb, offset+2) * 2 + 8;
1354         length += 3 - (length + 3) % 4;
1355         item = proto_tree_add_text(pt, tvb, offset, length, "Filter block %d", i);
1356         tree = proto_item_add_subtree (item, ett_gryphon_cmd_filter_block);
1357         offset = filter_block(tvb, offset, tree);
1358     }
1359     for (i = 1; i <= responses; i++) {
1360         msglen = tvb_get_ntohs(tvb, offset+4) + 8;
1361         length = msglen + 3 - (msglen + 3) % 4;
1362         item = proto_tree_add_text(pt, tvb, offset, length, "Response block %d", i);
1363         tree = proto_item_add_subtree (item, ett_gryphon_cmd_response_block);
1364         next_tvb = tvb_new_subset(tvb, offset, msglen, msglen);
1365         dissect_gryphon_message(next_tvb, NULL, tree, TRUE);
1366         offset += length;
1367     }
1368     return offset;
1369 }
1370
1371 static int
1372 resp_addresp(tvbuff_t *tvb, int offset, proto_tree *pt)
1373 {
1374     proto_tree_add_text(pt, tvb, offset, 1, "Response handle: %u",
1375         tvb_get_guint8(tvb, offset));
1376     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1377     offset += 4;
1378     return offset;
1379 }
1380
1381 static int
1382 cmd_modresp(tvbuff_t *tvb, int offset, proto_tree *pt)
1383 {
1384     unsigned char   action;
1385     unsigned char   dest = tvb_get_guint8(tvb, offset-5);
1386     guint8          resp_handle;
1387
1388     resp_handle = tvb_get_guint8(tvb, offset);
1389     if (resp_handle)
1390         proto_tree_add_text(pt, tvb, offset, 1, "Response handle: %u",
1391             resp_handle);
1392     else if (dest)
1393         proto_tree_add_text(pt, tvb, offset, 1, "Response handles: all on channel %hd", dest);
1394     else
1395         proto_tree_add_text(pt, tvb, offset, 1, "Response handles: all");
1396     action = tvb_get_guint8(tvb, offset+1);
1397     proto_tree_add_text(pt, tvb, offset+1, 1, "Action: %s response",
1398         val_to_str(action, filtacts, "Unknown (%u)"));
1399     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1400     offset += 4;
1401     return offset;
1402 }
1403
1404 static int
1405 resp_resphan(tvbuff_t *tvb, int offset, proto_tree *pt)
1406 {
1407     int         handles = tvb_get_guint8(tvb, offset);
1408     int         i, padding;
1409
1410     proto_tree_add_text(pt, tvb, offset, 1, "Number of response handles: %d", handles);
1411     for (i = 1; i <= handles; i++){
1412         proto_tree_add_text(pt, tvb, offset+i, 1, "Handle %d: %u", i,
1413             tvb_get_guint8(tvb, offset+i));
1414     }
1415     padding = 3 - (handles + 1 + 3) % 4;
1416     if (padding)
1417         proto_tree_add_text(pt, tvb, offset+1+handles, padding, "padding");
1418     offset += 1+handles+padding;
1419     return offset;
1420 }
1421
1422 static int
1423 resp_sched(tvbuff_t *tvb, int offset, proto_tree *pt)
1424 {
1425     unsigned int    id = tvb_get_ntohl(tvb, offset);
1426
1427     proto_tree_add_text(pt, tvb, offset, 4, "Transmit schedule ID: %u", id);
1428     offset += 4;
1429     return offset;
1430 }
1431
1432 static int
1433 cmd_desc(tvbuff_t *tvb, int offset, proto_tree *pt)
1434 {
1435     proto_tree_add_text(pt, tvb, offset, 4, "Program size: %u bytes",
1436         tvb_get_ntohl(tvb, offset));
1437     offset += 4;
1438     proto_tree_add_text(pt, tvb, offset, 32, "Program name: %.32s",
1439         tvb_get_ptr(tvb, offset, 32));
1440     offset += 32;
1441     proto_tree_add_text(pt, tvb, offset, 80, "Program description: %.80s",
1442         tvb_get_ptr(tvb, offset, 80));
1443     offset += 80;
1444     return offset;
1445 }
1446
1447 static int
1448 resp_desc(tvbuff_t *tvb, int offset, proto_tree *pt)
1449 {
1450     proto_item  *item;
1451     proto_tree  *tree;
1452     guint8      flags;
1453
1454     flags = tvb_get_guint8(tvb, offset);
1455     item = proto_tree_add_text(pt, tvb, offset, 1, "Flags: 0x%02x", flags);
1456     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1457     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1458         decode_boolean_bitfield(flags, 0x01, 8,
1459                 "The program is already present",
1460                 "The program is not present"));
1461     proto_tree_add_text(pt, tvb, offset+1, 1, "Handle: %u",
1462         tvb_get_guint8(tvb, offset+1));
1463     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1464     offset += 4;
1465     return offset;
1466 }
1467
1468 static int
1469 cmd_upload(tvbuff_t *tvb, int offset, proto_tree *pt)
1470 {
1471     int             msglen;
1472     unsigned int    length;
1473
1474     msglen = tvb_reported_length_remaining(tvb, offset);
1475     proto_tree_add_text(pt, tvb, offset, 2, "Block number: %u",
1476         tvb_get_ntohs(tvb, offset));
1477     offset += 4;
1478     msglen -= 4;
1479     proto_tree_add_text(pt, tvb, offset+2, 1, "Handle: %u",
1480         tvb_get_guint8(tvb, offset+2));
1481     offset += 3;
1482     msglen -= 3;
1483     length = msglen;
1484     proto_tree_add_text(pt, tvb, offset, length, "Data (%u bytes)", length);
1485     offset += length;
1486     length = 3 - (length + 3) % 4;
1487     if (length) {
1488         proto_tree_add_text(pt, tvb, offset, length, "padding");
1489         offset += length;
1490     }
1491     return offset;
1492 }
1493
1494 static int
1495 cmd_delete(tvbuff_t *tvb, int offset, proto_tree *pt)
1496 {
1497     proto_tree_add_text(pt, tvb, offset, 32, "Program name: %.32s",
1498         tvb_get_ptr(tvb, offset, 32));
1499     offset += 32;
1500     return offset;
1501 }
1502
1503 static int
1504 cmd_list(tvbuff_t *tvb, int offset, proto_tree *pt)
1505 {
1506     proto_tree_add_text(pt, tvb, offset, 1, "Block number: %u",
1507         tvb_get_guint8(tvb, offset));
1508     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1509     offset += 4;
1510     return offset;
1511 }
1512
1513 static int
1514 resp_list(tvbuff_t *tvb, int offset, proto_tree *pt)
1515 {
1516     proto_item  *item;
1517     proto_tree  *tree;
1518     unsigned int    i, count;
1519
1520     count = tvb_get_guint8(tvb, offset);
1521     proto_tree_add_text(pt, tvb, offset, 1, "Number of programs in this response: %u", count);
1522     proto_tree_add_text(pt, tvb, offset+1, 1, "reserved");
1523     offset += 2;
1524     proto_tree_add_text(pt, tvb, offset, 2, "Number of remaining programs: %u",
1525         tvb_get_ntohs(tvb, offset));
1526     offset += 2;
1527     for (i = 1; i <= count; i++) {
1528         item = proto_tree_add_text(pt, tvb, offset, 112, "Program %u", i);
1529         tree = proto_item_add_subtree (item, ett_gryphon_pgm_list);
1530         proto_tree_add_text(tree, tvb, offset, 32, "Name: %.32s",
1531             tvb_get_ptr(tvb, offset, 32));
1532         offset += 32;
1533         proto_tree_add_text(tree, tvb, offset, 80, "Description: %.80s",
1534             tvb_get_ptr(tvb, offset, 80));
1535         offset += 80;
1536     }
1537     return offset;
1538 }
1539
1540 static int
1541 cmd_start(tvbuff_t *tvb, int offset, proto_tree *pt)
1542 {
1543     char            string[120];
1544     gint            length;
1545
1546     offset = cmd_delete(tvb, offset, pt);
1547     length = tvb_get_nstringz0(tvb, offset, 120, string) + 1;
1548     proto_tree_add_text(pt, tvb, offset, length, "Arguments: %s", string);
1549     offset += length;
1550     length = 3 - (length + 3) % 4;
1551     if (length) {
1552         proto_tree_add_text(pt, tvb, offset, length, "padding");
1553         offset += length;
1554     }
1555     return offset;
1556 }
1557
1558 static int
1559 resp_start(tvbuff_t *tvb, int offset, proto_tree *pt)
1560 {
1561     proto_tree_add_text(pt, tvb, offset, 1, "Channel (Client) number: %u",
1562         tvb_get_guint8(tvb, offset));
1563     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1564     offset += 4;
1565     return offset;
1566 }
1567
1568 static int
1569 resp_status(tvbuff_t *tvb, int offset, proto_tree *pt)
1570 {
1571     proto_item  *item;
1572     proto_tree  *tree;
1573     unsigned int    i, copies, length;
1574
1575     copies = tvb_get_guint8(tvb, offset);
1576     item = proto_tree_add_text(pt, tvb, offset, 1, "Number of running copies: %u", copies);
1577     tree = proto_item_add_subtree (item, ett_gryphon_pgm_status);
1578     offset += 1;
1579     if (copies) {
1580         for (i = 1; i <= copies; i++) {
1581             proto_tree_add_text(tree, tvb, offset, 1, "Program %u channel (client) number %u",
1582                 i, tvb_get_guint8(tvb, offset));
1583             offset += 1;
1584         }
1585     }
1586     length = 3 - (copies + 1 + 3) % 4;
1587     if (length) {
1588         proto_tree_add_text(pt, tvb, offset, length, "padding");
1589         offset += length;
1590     }
1591     return offset;
1592 }
1593
1594 static int
1595 cmd_options(tvbuff_t *tvb, int offset, proto_tree *pt)
1596 {
1597     int             msglen;
1598     proto_item      *item;
1599     proto_tree      *tree;
1600     unsigned int    i, size, padding, option, option_length, option_value;
1601     unsigned char   *string, *string1;
1602
1603     msglen = tvb_reported_length_remaining(tvb, offset);
1604     item = proto_tree_add_text(pt, tvb, offset, 1, "Handle: %u",
1605         tvb_get_guint8(tvb, offset));
1606     item = proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1607     offset += 4;
1608     msglen -= 4;
1609     for (i = 1; msglen > 0; i++) {
1610         option_length = tvb_get_guint8(tvb, offset+1);
1611         size = option_length + 2;
1612         padding = 3 - ((size + 3) %4);
1613         item = proto_tree_add_text(pt, tvb, offset, size + padding, "Option number %u", i);
1614         tree = proto_item_add_subtree (item, ett_gryphon_pgm_options);
1615         option = tvb_get_guint8(tvb, offset);
1616         switch (option_length) {
1617         case 1:
1618             option_value = tvb_get_guint8(tvb, offset+2);
1619             break;
1620         case 2:
1621             option_value = tvb_get_ntohs(tvb, offset+2);
1622             break;
1623         case 4:
1624             option_value = tvb_get_ntohl(tvb, offset+2);
1625             break;
1626         default:
1627             option_value = 0;
1628         }
1629         string = "unknown option";
1630         string1 = "unknown option data";
1631         switch (option) {
1632         case PGM_CONV:
1633             string = "Type of data in the file";
1634             switch (option_value) {
1635             case PGM_BIN:
1636                 string1 = "Binary - Don't modify";
1637                 break;
1638             case PGM_ASCII:
1639                 string1 = "ASCII - Remove CR's";
1640                 break;
1641             }
1642             break;
1643         case PGM_TYPE:
1644             string = "Type of file";
1645             switch (option_value) {
1646             case PGM_PGM:
1647                 string1 = "Executable";
1648                 break;
1649             case PGM_DATA:
1650                 string1 = "Data";
1651                 break;
1652             }
1653             break;
1654         }
1655         proto_tree_add_text(tree, tvb, offset, 1, "%s", string);
1656         proto_tree_add_text(tree, tvb, offset+2, option_length, "%s", string1);
1657         if (padding)
1658             proto_tree_add_text(tree, tvb, offset+option_length+2, padding, "padding");
1659         offset += size + padding;
1660         msglen -= size + padding;
1661     }
1662     return offset;
1663 }
1664
1665 static int
1666 cmd_files(tvbuff_t *tvb, int offset, proto_tree *pt)
1667 {
1668     int     msglen;
1669     guchar  *which;
1670
1671     msglen = tvb_reported_length_remaining(tvb, offset);
1672     if (tvb_get_guint8(tvb, offset) == 0)
1673         which = "First group of names";
1674     else
1675         which = "Subsequent group of names";
1676
1677     proto_tree_add_text(pt, tvb, offset, 1, "%s", which);
1678     proto_tree_add_text(pt, tvb, offset+1, msglen-1, "Directory: %.*s",
1679         msglen-1, tvb_get_ptr(tvb, offset+1, msglen-1));
1680     offset += msglen;
1681     return offset;
1682 }
1683
1684 static int
1685 resp_files(tvbuff_t *tvb, int offset, proto_tree *pt)
1686 {
1687     int         msglen;
1688     guchar      *flag;
1689
1690     msglen = tvb_reported_length_remaining(tvb, offset);
1691     flag = tvb_get_guint8(tvb, offset) ? "Yes": "No";
1692     proto_tree_add_text(pt, tvb, offset, 1, "More filenames to return: %s", flag);
1693     proto_tree_add_text(pt, tvb, offset+1, msglen-1, "File and directory names");
1694     offset += msglen;
1695     return offset;
1696 }
1697
1698 static int
1699 cmd_usdt(tvbuff_t *tvb, int offset, proto_tree *pt)
1700 {
1701     guchar  *desc;
1702     guint8  assemble_flag;
1703
1704     if (tvb_get_guint8(tvb, offset))
1705         desc = "Register with gusdt";
1706     else
1707         desc = "Unregister with gusdt";
1708     proto_tree_add_text(pt, tvb, offset, 1, "%s", desc);
1709
1710     if (tvb_get_guint8(tvb, offset+1))
1711         desc = "Echo long transmit messages back to the client";
1712     else
1713         desc = "Do not echo long transmit messages back to the client";
1714     proto_tree_add_text(pt, tvb, offset+1, 1, "%s", desc);
1715
1716     assemble_flag = tvb_get_guint8(tvb, offset+2);
1717     if (assemble_flag == 2)
1718         desc = "Assemble long received messages but do not send them to the client";
1719     else if (assemble_flag)
1720         desc = "Assemble long received messages and send them to the client";
1721     else
1722         desc = "Do not assemble long received messages on behalf of the client";
1723     proto_tree_add_text(pt, tvb, offset+2, 1, "%s", desc);
1724
1725     offset += 4;
1726     return offset;
1727 }
1728
1729 static int
1730 speed(tvbuff_t *tvb, int offset, proto_tree *pt)
1731 {
1732     proto_tree_add_text(pt, tvb, offset, 1, "Baud rate index: %u",
1733         tvb_get_guint8(tvb, offset));
1734     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1735     offset += 4;
1736     return offset;
1737 }
1738
1739 static int
1740 filter_block(tvbuff_t *tvb, int offset, proto_tree *pt)
1741 {
1742     unsigned int    type, operator;
1743     int     length, padding;
1744
1745     proto_tree_add_text(pt, tvb, offset, 2, "Filter field starts at byte %u",
1746         tvb_get_ntohs(tvb, offset));
1747     length = tvb_get_ntohs(tvb, offset+2);
1748     proto_tree_add_text(pt, tvb, offset+2, 2, "Filter field is %d bytes long", length);
1749     type = tvb_get_guint8(tvb, offset+4);
1750     proto_tree_add_text(pt, tvb, offset+4, 1, "Filtering on %s",
1751         val_to_str(type, filter_data_types, "Unknown (0x%02x)"));
1752
1753     operator = tvb_get_guint8(tvb, offset+5);
1754     proto_tree_add_text(pt, tvb, offset+5, 1, "Type of comparison: %s",
1755         val_to_str(operator, operators, "Unknown (%u)"));
1756     proto_tree_add_text(pt, tvb, offset+6, 2, "reserved");
1757     offset += 8;
1758
1759     if (operator == BIT_FIELD_CHECK) {
1760         proto_tree_add_text(pt, tvb, offset, length, "Pattern");
1761         proto_tree_add_text(pt, tvb, offset+length, length, "Mask");
1762     } else {
1763         switch (length) {
1764         case 1:
1765             proto_tree_add_text(pt, tvb, offset, 1, "Value: %u",
1766                 tvb_get_guint8(tvb, offset));
1767             break;
1768         case 2:
1769             proto_tree_add_text(pt, tvb, offset, 2, "Value: %u",
1770                 tvb_get_ntohs(tvb, offset));
1771             break;
1772         case 4:
1773             proto_tree_add_text(pt, tvb, offset, 4, "Value: %u",
1774                 tvb_get_ntohl(tvb, offset));
1775             break;
1776         default:
1777             proto_tree_add_text(pt, tvb, offset, length, "Value");
1778         }
1779     }
1780     offset += length * 2;
1781     padding = 3 - (length * 2 + 3) % 4;
1782     if (padding) {
1783         proto_tree_add_text(pt, tvb, offset, padding, "padding");
1784         offset += padding;
1785     }
1786     return offset;
1787 }
1788
1789 static int
1790 blm_mode(tvbuff_t *tvb, int offset, proto_tree *pt)
1791 {
1792     char    *mode, line[50];
1793     int     x, y, seconds;
1794
1795     x = tvb_get_ntohl(tvb, offset);
1796     y = tvb_get_ntohl(tvb, offset+4);
1797     switch (x) {
1798     case 0:
1799         mode = "Off";
1800         sprintf (line, "reserved");
1801         break;
1802     case 1:
1803         mode = "Average over time";
1804         seconds = y / 1000;
1805         y = y % 1000;
1806         sprintf (line, "Averaging period: %d.%03d seconds", seconds, y);
1807         break;
1808     case 2:
1809         mode = "Average over frame count";
1810         sprintf (line, "Averaging period: %d frames", y);
1811         break;
1812     default:
1813         mode = "- unknown -";
1814         sprintf (line, "reserved");
1815     }
1816     proto_tree_add_text(pt, tvb, offset, 4, "Mode: %s", mode);
1817     offset += 4;
1818     proto_tree_add_text(pt, tvb, offset, 4, line, NULL);
1819     offset += 4;
1820     return offset;
1821 }
1822
1823 void
1824 proto_register_gryphon(void)
1825 {
1826     static hf_register_info hf[] = {
1827         { &hf_gryph_src,
1828         { "Source",           "gryph.src", FT_UINT8, BASE_HEX, VALS(src_dest), 0x0,
1829                 "", HFILL }},
1830         { &hf_gryph_srcchan,
1831         { "Source channel",   "gryph.srcchan", FT_UINT8, BASE_DEC, NULL, 0x0,
1832                 "", HFILL }},
1833         { &hf_gryph_dest,
1834         { "Destination",      "gryph.dest", FT_UINT8, BASE_HEX, VALS(src_dest), 0x0,
1835                 "", HFILL }},
1836         { &hf_gryph_destchan,
1837         { "Destination channel", "gryph.dstchan", FT_UINT8, BASE_DEC, NULL, 0x0,
1838                 "", HFILL }},
1839         { &hf_gryph_type,
1840         { "Frame type",       "gryph.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1841                 "", HFILL }},
1842         { &hf_gryph_cmd,
1843         { "Command",          "gryph.cmd.cmd", FT_UINT8, BASE_DEC, NULL, 0x0,
1844                 "", HFILL }},
1845     };
1846
1847     static gint *ett[] = {
1848         &ett_gryphon,
1849         &ett_gryphon_header,
1850         &ett_gryphon_body,
1851         &ett_gryphon_command_data,
1852         &ett_gryphon_response_data,
1853         &ett_gryphon_data_header,
1854         &ett_gryphon_flags,
1855         &ett_gryphon_data_body,
1856         &ett_gryphon_cmd_filter_block,
1857         &ett_gryphon_cmd_events_data,
1858         &ett_gryphon_cmd_config_device,
1859         &ett_gryphon_cmd_sched_data,
1860         &ett_gryphon_cmd_sched_cmd,
1861         &ett_gryphon_cmd_response_block,
1862         &ett_gryphon_pgm_list,
1863         &ett_gryphon_pgm_status,
1864         &ett_gryphon_pgm_options,
1865     };
1866     module_t *gryphon_module;
1867
1868     proto_gryphon = proto_register_protocol("DG Gryphon Protocol",
1869                                             "Gryphon",
1870                                             "gryphon");
1871     proto_register_field_array(proto_gryphon, hf, array_length(hf));
1872     proto_register_subtree_array(ett, array_length(ett));
1873
1874     gryphon_module = prefs_register_protocol(proto_gryphon, NULL);
1875     prefs_register_bool_preference(gryphon_module, "desegment",
1876         "Desegment all Gryphon messages spanning multiple TCP segments",
1877         "Whether the Gryphon dissector should desegment all messages spanning multiple TCP segments",
1878         &gryphon_desegment);
1879 }
1880
1881 void
1882 proto_reg_handoff_gryphon(void)
1883 {
1884     dissector_handle_t gryphon_handle;
1885
1886     gryphon_handle = create_dissector_handle(dissect_gryphon, proto_gryphon);
1887     dissector_add("tcp.port", 7000, gryphon_handle);
1888 }
1889
1890 /* Start the functions we need for the plugin stuff */
1891 G_MODULE_EXPORT void
1892 plugin_reg_handoff(void){
1893   proto_reg_handoff_gryphon();
1894 }
1895
1896 G_MODULE_EXPORT void
1897 plugin_init(plugin_address_table_t *pat
1898 #ifndef PLUGINS_NEED_ADDRESS_TABLE
1899 _U_
1900 #endif
1901 ){
1902   /* initialise the table of pointers needed in Win32 DLLs */
1903   plugin_address_table_init(pat);
1904   /* register the new protocol, protocol fields, and subtrees */
1905   if (proto_gryphon == -1) { /* execute protocol initialization only once */
1906     proto_register_gryphon();
1907   }
1908 }
1909 /* End the functions we need for plugin stuff */