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