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