Use the bitfield decoding routines for bitfields.
[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.30 2002/05/01 06:15:44 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
963     item = proto_tree_add_text(pt, tvb, offset, 1, "Flags");
964     tree = proto_item_add_subtree (item, ett_gryphon_flags);
965     flags = tvb_get_guint8(tvb, offset);
966     proto_tree_add_text(tree, tvb, offset, 1, "%s",
967         decode_boolean_bitfield(flags, FILTER_PASS_FLAG, 8,
968             "Conforming messages are passed",
969             "Conforming messages are blocked"));
970     proto_tree_add_text(tree, tvb, offset, 1, "%s",
971         decode_boolean_bitfield(flags, FILTER_ACTIVE_FLAG, 8,
972             "The filter is active", "The filter is inactive"));
973     offset += 1;
974     blocks = tvb_get_guint8(tvb, offset);
975     proto_tree_add_text(pt, tvb, offset, 1, "Number of filter blocks = %d", blocks);
976     proto_tree_add_text(pt, tvb, offset+1, 6, "reserved");
977     offset += 7;
978     for (i = 1; i <= blocks; i++) {
979         length = tvb_get_ntohs(tvb, offset+2) * 2 + 8;
980         length += 3 - (length + 3) % 4;
981         item = proto_tree_add_text(pt, tvb, offset, length, "Filter block %d", i);
982         tree = proto_item_add_subtree (item, ett_gryphon_cmd_filter_block);
983         offset = filter_block(tvb, offset, src, tree);
984     }
985     return offset;
986 }
987
988 static int
989 resp_addfilt(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
990 {
991     proto_tree_add_text(pt, tvb, offset, 1, "Filter handle: %u",
992         tvb_get_guint8(tvb, offset));
993     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
994     offset += 4;
995     return offset;
996 }
997
998 static int
999 cmd_modfilt(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1000 {
1001     guint8          filter_handle;
1002     unsigned char   action, i;
1003
1004     filter_handle = tvb_get_guint8(tvb, offset);
1005     if (filter_handle)
1006         proto_tree_add_text(pt, tvb, offset, 1, "Filter handle: %u",
1007             filter_handle);
1008     else
1009         proto_tree_add_text(pt, tvb, offset, 1, "Filter handles: all");
1010     action = tvb_get_guint8(tvb, offset + 1);
1011     for (i = 0; i < SIZEOF(filtacts); i++) {
1012         if (filtacts[i].value == action)
1013             break;
1014     }
1015     if (i >= SIZEOF(filtacts))
1016         i = SIZEOF(filtacts) - 1;
1017     proto_tree_add_text(pt, tvb, offset+1, 1, "Action: %s filter", filtacts[i].strptr);
1018     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1019     offset += 4;
1020     return offset;
1021 }
1022
1023 static int
1024 resp_filthan(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1025 {
1026     int         handles = tvb_get_guint8(tvb, offset);
1027     int         i, padding;
1028     
1029     proto_tree_add_text(pt, tvb, offset, 1, "Number of filter handles: %d", handles);
1030     for (i = 1; i <= handles; i++){
1031         proto_tree_add_text(pt, tvb, offset+i, 1, "Handle %d: %u", i,
1032             tvb_get_guint8(tvb, offset+i));
1033     }
1034     padding = 3 - (handles + 1 + 3) % 4;
1035     if (padding)
1036         proto_tree_add_text(pt, tvb, offset+1+handles, padding, "padding");
1037     offset += 1+handles+padding;
1038     return offset;
1039 }
1040
1041 static int
1042 dfiltmode(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1043 {
1044     unsigned int    i;
1045     unsigned char   mode;
1046     
1047     mode = tvb_get_guint8(tvb, offset);
1048     for (i = 0; i < SIZEOF(modes); i++) {
1049         if (dmodes[i].value == mode)
1050             break;
1051     }
1052     if (i >= SIZEOF(dmodes))
1053         i = SIZEOF(dmodes) - 1;
1054     proto_tree_add_text(pt, tvb, offset, 1, "Filter mode: %s", dmodes[i].strptr);
1055     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1056     offset += 4;
1057     return offset;
1058 }
1059
1060 static int
1061 filtmode(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1062 {
1063     unsigned int    i;
1064     unsigned char   mode;
1065     
1066     mode = tvb_get_guint8(tvb, offset);
1067     for (i = 0; i < SIZEOF(modes); i++) {
1068         if (modes[i].value == mode)
1069             break;
1070     }
1071     if (i >= SIZEOF(modes))
1072         i = SIZEOF(modes) - 1;
1073     proto_tree_add_text(pt, tvb, offset, 1, "Filter mode: %s", modes[i].strptr);
1074     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1075     offset += 4;
1076     return offset;
1077 }
1078
1079 static int
1080 resp_events(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1081 {
1082     int             msglen;
1083     unsigned int    i;
1084     proto_tree      *tree;
1085     proto_item      *item;
1086     
1087     msglen = tvb_reported_length_remaining(tvb, offset);
1088     i = 1;
1089     while (msglen != 0) {
1090         item = proto_tree_add_text(pt, tvb, offset, 20, "Event %d:", i);
1091         tree = proto_item_add_subtree (item, ett_gryphon_cmd_events_data);
1092         proto_tree_add_text(tree, tvb, offset, 1, "Event ID: %u",
1093             tvb_get_guint8(tvb, offset));
1094         proto_tree_add_text(tree, tvb, offset+1, 19, "Event name: %.19s",
1095                 tvb_get_ptr(tvb, offset+1, 19));
1096         offset += 20;
1097         msglen -= 20;
1098         i++;
1099     }
1100     return offset;
1101 }
1102
1103 static int
1104 cmd_register(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1105 {
1106     proto_tree_add_text(pt, tvb, offset, 16, "Username: %.16s",
1107         tvb_get_ptr(tvb, offset, 16));
1108     offset += 16;
1109     proto_tree_add_text(pt, tvb, offset, 32, "Password: %.32s",
1110         tvb_get_ptr(tvb, offset, 32));
1111     offset += 32;
1112     return offset;
1113 }
1114
1115 static int
1116 resp_register(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1117 {
1118     proto_tree_add_text(pt, tvb, offset, 1, "Client ID: %u",
1119         tvb_get_guint8(tvb, offset));
1120     proto_tree_add_text(pt, tvb, offset+1, 1, "Privileges: %u",
1121         tvb_get_guint8(tvb, offset+1));
1122     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1123     offset += 4;
1124     return offset;
1125 }
1126
1127
1128 static int
1129 resp_getspeeds(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1130 {
1131     int size;
1132     int number;
1133     int index;
1134     
1135     proto_tree_add_text(pt, tvb, offset, 4, "Set Speed IOCTL");
1136     proto_tree_add_text(pt, tvb, offset+4, 4, "Get Speed IOCTL");
1137     size = tvb_get_guint8(tvb, offset+8);
1138     proto_tree_add_text(pt, tvb, offset+8, 1, "Speed data size is %d bytes", size);
1139     number = tvb_get_guint8(tvb, offset+9);
1140     proto_tree_add_text(pt, tvb, offset+9, 1, "There are %d preset speeds", number);
1141     offset += 10;
1142     for (index = 0; index < number; index++) {
1143         proto_tree_add_text(pt, tvb, offset, size, "Data for preset %d",
1144             index+1);
1145         offset += size;
1146     }
1147     return offset;
1148 }
1149
1150 static int
1151 cmd_sort(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1152 {
1153     char        *which;
1154     
1155     which = tvb_get_guint8(tvb, offset) ?
1156             "Sort into blocks of up to 16 messages" :
1157             "Do not sort messages";
1158     proto_tree_add_text(pt, tvb, offset, 1, "Set sorting: %s", which);
1159     offset += 1;
1160     return offset;
1161 }
1162
1163 static int
1164 cmd_optimize(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1165 {
1166     char        *which;
1167     
1168     which = tvb_get_guint8(tvb, offset) ? 
1169             "Optimize for latency (Nagle algorithm disabled)" :
1170             "Optimize for throughput (Nagle algorithm enabled)";
1171     proto_tree_add_text(pt, tvb, offset, 1, "Set optimization: %s", which);
1172     offset += 1;
1173     return offset;
1174 }
1175
1176 static int
1177 resp_config(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1178 {
1179     proto_item  *ti;
1180     proto_tree  *ft;
1181     int         devices;
1182     int         i;
1183     unsigned int j, x;
1184     
1185     static const value_string protocol_types[] = {
1186         {GDUMMY * 256 + GDGDMARKONE,    "Dummy device driver"},
1187         {GCAN * 256 + G82527,           "CAN, 82527 subtype"},
1188         {GCAN * 256 + GSJA1000,         "CAN, SJA1000 subtype"},
1189         {GCAN * 256 + G82527SW,         "CAN, 82527 single wire subtype"},
1190         {GJ1850 * 256 + GHBCCPAIR,      "J1850, HBCC subtype"},
1191         {GJ1850 * 256 + GDLC,           "J1850, GM DLC subtype"},
1192         {GJ1850 * 256 + GCHRYSLER,      "J1850, Chrysler subtype"},
1193         {GJ1850 * 256 + GDEHC12,        "J1850, DE HC12 KWP/BDLC subtype"},
1194         {GKWP2000 * 256 + GDEHC12KWP,   "Keyword protocol 2000"},
1195         {GHONDA * 256 + GDGHC08,        "Honda UART, DG HC08 subtype"},
1196         {GFORDUBP * 256 + GDGUBP08,     "Ford UBP, DG HC08 subtype"},
1197         {-1,                            "- unknown -"},
1198     };
1199
1200     proto_tree_add_text(pt, tvb, offset, 20, "Device name: %.20s",
1201         tvb_get_ptr(tvb, offset, 20));
1202     offset += 20;
1203
1204     proto_tree_add_text(pt, tvb, offset, 8, "Device version: %.8s",
1205         tvb_get_ptr(tvb, offset, 8));
1206     offset += 8;
1207
1208     proto_tree_add_text(pt, tvb, offset, 20, "Device serial number: %.20s",
1209         tvb_get_ptr(tvb, offset, 20));
1210     offset += 20;
1211
1212     devices = tvb_get_guint8(tvb, offset);
1213     proto_tree_add_text(pt, tvb, offset, 1, "Number of channels: %d", devices);
1214     proto_tree_add_text(pt, tvb, offset+1, 15, "reserved");
1215     offset += 16;
1216     for (i = 1; i <= devices; i++) {
1217         ti = proto_tree_add_text(pt, tvb, offset, 80, "Channel %d:", i);
1218         ft = proto_item_add_subtree(ti, ett_gryphon_cmd_config_device);
1219         proto_tree_add_text(ft, tvb, offset, 20, "Driver name: %.20s",
1220             tvb_get_ptr(tvb, offset, 20));
1221         offset += 20;
1222
1223         proto_tree_add_text(ft, tvb, offset, 8, "Driver version: %.8s",
1224             tvb_get_ptr(tvb, offset, 8));
1225         offset += 8;
1226
1227         proto_tree_add_text(ft, tvb, offset, 24, "Device security string: %.24s",
1228             tvb_get_ptr(tvb, offset, 24));
1229         offset += 24;
1230
1231         proto_tree_add_text(ft, tvb, offset, 20, "Hardware serial number: %.20s",
1232             tvb_get_ptr(tvb, offset, 20));
1233         offset += 20;
1234
1235         x = tvb_get_ntohs(tvb, offset);
1236         for (j = 0; j < SIZEOF(protocol_types); j++) {
1237             if (protocol_types[j].value == x)
1238                 break;
1239         }
1240         if (j >= SIZEOF(protocol_types))
1241             j = SIZEOF(protocol_types) -1;
1242         proto_tree_add_text(ft, tvb, offset, 2, "Protocol type & subtype: %s", protocol_types[j].strptr);
1243         offset += 2;
1244
1245         proto_tree_add_text(ft, tvb, offset, 1, "Channel ID: %u",
1246             tvb_get_guint8(tvb, offset));
1247         proto_tree_add_text(ft, tvb, offset+1, 5, "reserved");
1248         offset += 6;
1249     }
1250     return offset;
1251 }
1252
1253 static int
1254 cmd_sched(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1255 {
1256     int             msglen;
1257     proto_item      *item, *item1;
1258     proto_tree      *tree, *tree1;
1259     int             save_offset;
1260     unsigned int    i, x, length;
1261     unsigned char   def_chan = tvb_get_guint8(tvb, offset-9);
1262     
1263     msglen = tvb_reported_length_remaining(tvb, offset);
1264     x = tvb_get_ntohl(tvb, offset);
1265     if (x == 0xFFFFFFFF)
1266         proto_tree_add_text(pt, tvb, offset, 4, "Number of iterations: infinite");
1267     else
1268         proto_tree_add_text(pt, tvb, offset, 4, "Number of iterations: %u", x);
1269     offset += 4;
1270     msglen -= 4;
1271     x = tvb_get_ntohl(tvb, offset);
1272     item = proto_tree_add_text(pt, tvb, offset, 4, "Flags: 0x%08x", x);
1273     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1274     proto_tree_add_text(tree, tvb, offset, 4, "%s",
1275         decode_boolean_bitfield(x, 0x01, 32,
1276             "Critical scheduler", "Normal scheduler"));
1277     offset += 4;
1278     msglen -= 4;
1279     i = 1;
1280     while (msglen > 0) {
1281         length = 16 + tvb_get_guint8(tvb, offset+16) +
1282             tvb_get_ntohs(tvb, offset+18) + tvb_get_guint8(tvb, offset+20) + 16;
1283         length += 3 - (length + 3) % 4;
1284         item = proto_tree_add_text(pt, tvb, offset, length, "Message %d", i);
1285         tree = proto_item_add_subtree (item, ett_gryphon_cmd_sched_data);
1286         x = tvb_get_ntohl(tvb, offset);
1287         proto_tree_add_text(tree, tvb, offset, 4, "Sleep: %u milliseconds", x);
1288         offset += 4;
1289         msglen -= 4;
1290         x = tvb_get_ntohl(tvb, offset);
1291         proto_tree_add_text(tree, tvb, offset, 4, "Transmit count: %u", x);
1292         offset += 4;
1293         msglen -= 4;
1294         x = tvb_get_ntohl(tvb, offset);
1295         proto_tree_add_text(tree, tvb, offset, 4, "Transmit period: %u milliseconds", x);
1296         offset += 4;
1297         msglen -= 4;
1298         proto_tree_add_text(tree, tvb, offset, 2, "reserved flags");
1299         x = tvb_get_guint8(tvb, offset+2);
1300         if (x == 0)
1301             x = def_chan;
1302         proto_tree_add_text(tree, tvb, offset+2, 1, "Channel: %u", x);
1303         proto_tree_add_text(tree, tvb, offset+3, 1, "reserved");
1304         offset += 4;
1305         msglen -= 4;
1306         item1 = proto_tree_add_text(tree, tvb, offset, length, "Message");
1307         tree1 = proto_item_add_subtree (item1, ett_gryphon_cmd_sched_cmd);
1308         save_offset = offset;
1309         offset = decode_data(tvb, offset, src, tree1);
1310         msglen -= offset - save_offset;
1311         i++;
1312     }
1313     return offset;
1314 }
1315
1316 static int
1317 resp_blm_data(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1318 {
1319     unsigned int    i;
1320     int             hours, minutes, seconds, fraction, x, fract;
1321     unsigned long   timestamp;
1322     static char    *fields[] = {
1323         "Bus load average: %d.%02d%%",
1324         "Current bus load: %d.%02d%%",
1325         "Peak bus load: %d.%02d%%",
1326         "Historic peak bus load: %d.%02d%%"
1327     };
1328
1329     timestamp = tvb_get_ntohl(tvb, offset);
1330     hours = timestamp /(100000 * 60 *60);
1331     minutes = (timestamp / (100000 * 60)) % 60;
1332     seconds = (timestamp / 100000) % 60;
1333     fraction = timestamp % 100000;
1334     proto_tree_add_text(pt, tvb, offset, 4, "Timestamp: %d:%02d:%02d.%05d", hours, minutes, seconds, fraction);
1335     offset += 4;
1336     for (i = 0; i < SIZEOF(fields); i++){
1337         x = tvb_get_ntohs(tvb, offset);
1338         fract = x % 100;
1339         x /= 100;
1340         proto_tree_add_text(pt, tvb, offset, 2, fields[i], x, fract);
1341         offset += 2;
1342     }
1343     return offset;
1344 }
1345
1346 static int
1347 resp_blm_stat(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1348 {
1349     unsigned int    x, i;
1350     char            *fields[] = {
1351         "Receive frame count: %u",
1352         "Transmit frame count: %u",
1353         "Receive dropped frame count: %u",
1354         "Transmit dropped frame count: %u",
1355         "Receive error count: %u",
1356         "Transmit error count: %u",
1357     };
1358
1359     offset = resp_blm_data(tvb, offset, src, pt);
1360     for (i = 0; i < SIZEOF(fields); i++){
1361         x = tvb_get_ntohl(tvb, offset);
1362         proto_tree_add_text(pt, tvb, offset, 4, fields[i], x);
1363         offset += 4;
1364     }
1365     return offset;
1366 }
1367
1368 static const value_string action_vals[] = {
1369     { FR_RESP_AFTER_EVENT,  "Send response(s) for each conforming message" },
1370     { FR_RESP_AFTER_PERIOD, "Send response(s) after the specified period expires following a conforming message" },
1371     { FR_IGNORE_DURING_PER, "Send response(s) for a conforming message and ignore\nfurther messages until the specified period expires" },
1372     { 0,                    NULL }
1373 };
1374
1375 static const value_string deact_on_event_vals[] = {
1376     { FR_DEACT_ON_EVENT,
1377         "Deactivate this response for a conforming message" },
1378     { FR_DELETE|FR_DEACT_ON_EVENT,
1379         "Delete this response for a conforming message" },
1380     { 0,
1381         NULL }
1382 };
1383
1384 static const value_string deact_after_per_vals[] = {
1385     { FR_DEACT_AFTER_PER,
1386         "Deactivate this response after the specified period following a conforming message" },
1387     { FR_DELETE|FR_DEACT_AFTER_PER,
1388         "Delete this response after the specified period following a conforming message" },
1389     { 0,
1390         NULL }
1391 };
1392
1393 static int
1394 cmd_addresp(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1395 {
1396     proto_item  *item;
1397     proto_tree  *tree;
1398     guint8      flags;
1399     int         blocks, responses, old_handle, i, msglen, length;
1400     int         action, actionType, actionValue;
1401     tvbuff_t    *next_tvb;
1402
1403     actionType = 0;
1404     flags = tvb_get_guint8(tvb, offset);
1405     item = proto_tree_add_text(pt, tvb, offset, 1, "Flags: 0x%02x", flags);
1406     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1407     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1408         decode_boolean_bitfield(flags, FILTER_ACTIVE_FLAG, 8,
1409                 "The response is active", "The response is inactive"));
1410     offset += 1;
1411     blocks = tvb_get_guint8(tvb, offset);
1412     proto_tree_add_text(pt, tvb, offset, 1, "Number of filter blocks = %d", blocks);
1413     offset += 1;
1414     responses = tvb_get_guint8(tvb, offset);
1415     proto_tree_add_text(pt, tvb, offset, 1, "Number of response blocks = %d", responses);
1416     offset += 1;
1417     old_handle = tvb_get_guint8(tvb, offset);
1418     proto_tree_add_text(pt, tvb, offset, 1, "Old handle = %d", old_handle);
1419     offset += 1;
1420     action = tvb_get_guint8(tvb, offset);
1421     item = proto_tree_add_text(pt, tvb, offset, 1, "Action: %s",
1422         val_to_str(action & 0x07, action_vals, "Unknown (%u)"));
1423     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1424     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1425         decode_enumerated_bitfield(action, 0x07, 8, action_vals, "%s"));
1426     actionValue = tvb_get_ntohs(tvb, offset+2);
1427     if (actionValue) {
1428         if (action & FR_PERIOD_MSGS) {
1429             actionType = 1;
1430         } else {
1431             actionType = 0;
1432         }
1433         proto_tree_add_text(tree, tvb, offset, 1, "%s",
1434             decode_boolean_bitfield(action, FR_PERIOD_MSGS, 8,
1435                 "The period is in frames", "The period is in 0.01 seconds"));
1436     }
1437     if (action & FR_DEACT_ON_EVENT) {
1438         proto_tree_add_text(tree, tvb, offset, 1, "%s",
1439             decode_enumerated_bitfield(action, FR_DELETE|FR_DEACT_ON_EVENT, 8,
1440                 deact_on_event_vals, "%s"));
1441     }
1442     if (action & FR_DEACT_AFTER_PER) {
1443         proto_tree_add_text(tree, tvb, offset, 1, "%s",
1444             decode_enumerated_bitfield(action, FR_DELETE|FR_DEACT_AFTER_PER, 8,
1445                 deact_after_per_vals, "%s"));
1446     }
1447     offset += 1;
1448     proto_tree_add_text(pt, tvb, offset, 1, "reserved");
1449     offset += 1;
1450     if (actionValue) {
1451         if (actionType == 1) {
1452             proto_tree_add_text(tree, tvb, offset, 2, "Period: %d messages", actionValue);
1453         } else {
1454             proto_tree_add_text(tree, tvb, offset, 2, "Period: %d.%02d seconds", actionValue/100, actionValue%100);
1455         }
1456     }
1457     offset += 2;
1458     for (i = 1; i <= blocks; i++) {
1459         length = tvb_get_ntohs(tvb, offset+2) * 2 + 8;
1460         length += 3 - (length + 3) % 4;
1461         item = proto_tree_add_text(pt, tvb, offset, length, "Filter block %d", i);
1462         tree = proto_item_add_subtree (item, ett_gryphon_cmd_filter_block);
1463         offset = filter_block(tvb, offset, src, tree);
1464     }
1465     for (i = 1; i <= responses; i++) {
1466         msglen = tvb_get_ntohs(tvb, offset+4) + 8;
1467         length = msglen + 3 - (msglen + 3) % 4;
1468         item = proto_tree_add_text(pt, tvb, offset, length, "Response block %d", i);
1469         tree = proto_item_add_subtree (item, ett_gryphon_cmd_response_block);
1470         next_tvb = tvb_new_subset(tvb, offset, msglen, msglen);
1471         dissect_gryphon_message(next_tvb, NULL, tree, TRUE);
1472         offset += length;
1473     }
1474     return offset;
1475 }
1476
1477 static int
1478 resp_addresp(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1479 {
1480     proto_tree_add_text(pt, tvb, offset, 1, "Response handle: %u",
1481         tvb_get_guint8(tvb, offset));
1482     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1483     offset += 4;
1484     return offset;
1485 }
1486
1487 static int
1488 cmd_modresp(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1489 {
1490     unsigned char   action;
1491     unsigned char   dest = tvb_get_guint8(tvb, offset-5);
1492     guint8          resp_handle;
1493     unsigned int    i;
1494
1495     resp_handle = tvb_get_guint8(tvb, offset);
1496     if (resp_handle)
1497         proto_tree_add_text(pt, tvb, offset, 1, "Response handle: %u",
1498             resp_handle);
1499     else if (dest)
1500         proto_tree_add_text(pt, tvb, offset, 1, "Response handles: all on channel %hd", dest);
1501     else
1502         proto_tree_add_text(pt, tvb, offset, 1, "Response handles: all");
1503     action = tvb_get_guint8(tvb, offset+1);
1504     for (i = 0; i < SIZEOF(filtacts); i++) {
1505         if (filtacts[i].value == action)
1506             break;
1507     }
1508     if (i >= SIZEOF(filtacts))
1509         i = SIZEOF(filtacts) - 1;
1510     proto_tree_add_text(pt, tvb, offset+1, 1, "Action: %s response", filtacts[i].strptr);
1511     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1512     offset += 4;
1513     return offset;
1514 }
1515
1516 static int
1517 resp_resphan(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1518 {
1519     int         handles = tvb_get_guint8(tvb, offset);
1520     int         i, padding;
1521     
1522     proto_tree_add_text(pt, tvb, offset, 1, "Number of response handles: %d", handles);
1523     for (i = 1; i <= handles; i++){
1524         proto_tree_add_text(pt, tvb, offset+i, 1, "Handle %d: %u", i,
1525             tvb_get_guint8(tvb, offset+i));
1526     }
1527     padding = 3 - (handles + 1 + 3) % 4;
1528     if (padding)
1529         proto_tree_add_text(pt, tvb, offset+1+handles, padding, "padding");
1530     offset += 1+handles+padding;
1531     return offset;
1532 }
1533
1534 static int
1535 resp_sched(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1536 {
1537     unsigned int    id = tvb_get_ntohl(tvb, offset);
1538
1539     proto_tree_add_text(pt, tvb, offset, 4, "Transmit schedule ID: %u", id);
1540     offset += 4;
1541     return offset;
1542 }
1543
1544 static int
1545 cmd_desc(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1546 {
1547     proto_tree_add_text(pt, tvb, offset, 4, "Program size: %u bytes",
1548         tvb_get_ntohl(tvb, offset));
1549     offset += 4;
1550     proto_tree_add_text(pt, tvb, offset, 32, "Program name: %.32s",
1551         tvb_get_ptr(tvb, offset, 32));
1552     offset += 32;
1553     proto_tree_add_text(pt, tvb, offset, 80, "Program description: %.80s",
1554         tvb_get_ptr(tvb, offset, 80));
1555     offset += 80;
1556     return offset;
1557 }
1558
1559 static int
1560 resp_desc(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1561 {
1562     proto_item  *item;
1563     proto_tree  *tree;
1564     guint8      flags;
1565     
1566     flags = tvb_get_guint8(tvb, offset);
1567     item = proto_tree_add_text(pt, tvb, offset, 1, "Flags: 0x%02x", flags);
1568     tree = proto_item_add_subtree (item, ett_gryphon_flags);
1569     proto_tree_add_text(tree, tvb, offset, 1, "%s",
1570         decode_boolean_bitfield(flags, 0x01, 8,
1571                 "The program is already present",
1572                 "The program is not present"));
1573     proto_tree_add_text(pt, tvb, offset+1, 1, "Handle: %u",
1574         tvb_get_guint8(tvb, offset+1));
1575     proto_tree_add_text(pt, tvb, offset+2, 2, "reserved");
1576     offset += 4;
1577     return offset;
1578 }
1579
1580 static int
1581 cmd_upload(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1582 {
1583     int             msglen;
1584     unsigned int    length;
1585     
1586     msglen = tvb_reported_length_remaining(tvb, offset);
1587     proto_tree_add_text(pt, tvb, offset, 2, "Block number: %u",
1588         tvb_get_ntohs(tvb, offset));
1589     offset += 4;
1590     msglen -= 4;
1591     proto_tree_add_text(pt, tvb, offset+2, 1, "Handle: %u",
1592         tvb_get_guint8(tvb, offset+2));
1593     offset += 3;
1594     msglen -= 3;
1595     length = msglen;
1596     proto_tree_add_text(pt, tvb, offset, length, "Data (%u bytes)", length);
1597     offset += length;
1598     length = 3 - (length + 3) % 4;
1599     if (length) {
1600         proto_tree_add_text(pt, tvb, offset, length, "padding");
1601         offset += length;
1602     }
1603     return offset;
1604 }
1605
1606 static int
1607 cmd_delete(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1608 {
1609     proto_tree_add_text(pt, tvb, offset, 32, "Program name: %.32s",
1610         tvb_get_ptr(tvb, offset, 32));
1611     offset += 32;
1612     return offset;
1613 }
1614
1615 static int
1616 cmd_list(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1617 {
1618     proto_tree_add_text(pt, tvb, offset, 1, "Block number: %u",
1619         tvb_get_guint8(tvb, offset));
1620     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1621     offset += 4;
1622     return offset;
1623 }
1624
1625 static int
1626 resp_list(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1627 {
1628     proto_item  *item;
1629     proto_tree  *tree;
1630     unsigned int    i, count;
1631     
1632     count = tvb_get_guint8(tvb, offset);
1633     proto_tree_add_text(pt, tvb, offset, 1, "Number of programs in this response: %u", count);
1634     proto_tree_add_text(pt, tvb, offset+1, 1, "reserved");
1635     offset += 2;
1636     proto_tree_add_text(pt, tvb, offset, 2, "Number of remaining programs: %u",
1637         tvb_get_ntohs(tvb, offset));
1638     offset += 2;
1639     for (i = 1; i <= count; i++) {
1640         item = proto_tree_add_text(pt, tvb, offset, 112, "Program %u", i);
1641         tree = proto_item_add_subtree (item, ett_gryphon_pgm_list);
1642         proto_tree_add_text(tree, tvb, offset, 32, "Name: %.32s",
1643             tvb_get_ptr(tvb, offset, 32));
1644         offset += 32;
1645         proto_tree_add_text(tree, tvb, offset, 80, "Description: %.80s",
1646             tvb_get_ptr(tvb, offset, 80));
1647         offset += 80;
1648     }
1649     return offset;
1650 }
1651
1652 static int
1653 cmd_start(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1654 {
1655     char            string[120];
1656     gint            length;
1657     
1658     offset = cmd_delete(tvb, offset, src, pt);
1659     length = tvb_get_nstringz0(tvb, offset, 120, string) + 1;
1660     proto_tree_add_text(pt, tvb, offset, length, "Arguments: %s", string);
1661     offset += length;
1662     length = 3 - (length + 3) % 4;
1663     if (length) {
1664         proto_tree_add_text(pt, tvb, offset, length, "padding");
1665         offset += length;
1666     }
1667     return offset;
1668 }
1669
1670 static int
1671 resp_start(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1672 {
1673     proto_tree_add_text(pt, tvb, offset, 1, "Channel (Client) number: %u",
1674         tvb_get_guint8(tvb, offset));
1675     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1676     offset += 4;
1677     return offset;
1678 }
1679
1680 static int
1681 resp_status(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1682 {
1683     proto_item  *item;
1684     proto_tree  *tree;
1685     unsigned int    i, copies, length;
1686     
1687     copies = tvb_get_guint8(tvb, offset);
1688     item = proto_tree_add_text(pt, tvb, offset, 1, "Number of running copies: %u", copies);
1689     tree = proto_item_add_subtree (item, ett_gryphon_pgm_status);
1690     offset += 1;
1691     if (copies) {
1692         for (i = 1; i <= copies; i++) {
1693             proto_tree_add_text(tree, tvb, offset, 1, "Program %u channel (client) number %u",
1694                 i, tvb_get_guint8(tvb, offset));
1695             offset += 1;
1696         }
1697     }
1698     length = 3 - (copies + 1 + 3) % 4;
1699     if (length) {
1700         proto_tree_add_text(pt, tvb, offset, length, "padding");
1701         offset += length;
1702     }
1703     return offset;
1704 }
1705
1706 static int
1707 cmd_options(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1708 {
1709     int             msglen;
1710     proto_item      *item;
1711     proto_tree      *tree;
1712     unsigned int    i, size, padding, option, option_length, option_value;
1713     unsigned char   *string, *string1;
1714     
1715     msglen = tvb_reported_length_remaining(tvb, offset);
1716     item = proto_tree_add_text(pt, tvb, offset, 1, "Handle: %u",
1717         tvb_get_guint8(tvb, offset));
1718     item = proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1719     offset += 4;
1720     msglen -= 4;
1721     for (i = 1; msglen > 0; i++) {
1722         option_length = tvb_get_guint8(tvb, offset+1);
1723         size = option_length + 2;
1724         padding = 3 - ((size + 3) %4);
1725         item = proto_tree_add_text(pt, tvb, offset, size + padding, "Option number %u", i);
1726         tree = proto_item_add_subtree (item, ett_gryphon_pgm_options);
1727         option = tvb_get_guint8(tvb, offset);
1728         switch (option_length) {
1729         case 1:
1730             option_value = tvb_get_guint8(tvb, offset+2);
1731             break;
1732         case 2:
1733             option_value = tvb_get_ntohs(tvb, offset+2);
1734             break;
1735         case 4:
1736             option_value = tvb_get_ntohl(tvb, offset+2);
1737             break;
1738         default:
1739             option_value = 0;
1740         }
1741         string = "unknown option";
1742         string1 = "unknown option data";
1743         switch (option) {
1744         case PGM_CONV:
1745             string = "Type of data in the file";
1746             switch (option_value) {
1747             case PGM_BIN:
1748                 string1 = "Binary - Don't modify";
1749                 break;
1750             case PGM_ASCII:
1751                 string1 = "ASCII - Remove CR's";
1752                 break;
1753             }
1754             break;
1755         case PGM_TYPE:
1756             string = "Type of file";
1757             switch (option_value) {
1758             case PGM_PGM:
1759                 string1 = "Executable";
1760                 break;
1761             case PGM_DATA:
1762                 string1 = "Data";
1763                 break;
1764             }
1765             break;
1766         }
1767         proto_tree_add_text(tree, tvb, offset, 1, "%s", string);
1768         proto_tree_add_text(tree, tvb, offset+2, option_length, "%s", string1);
1769         if (padding)
1770             proto_tree_add_text(tree, tvb, offset+option_length+2, padding, "padding");
1771         offset += size + padding;
1772         msglen -= size + padding;
1773     }
1774     return offset;
1775 }
1776
1777 static int
1778 cmd_files(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1779 {
1780     int     msglen;
1781     u_char  *which;
1782     
1783     msglen = tvb_reported_length_remaining(tvb, offset);
1784     if (tvb_get_guint8(tvb, offset) == 0)
1785         which = "First group of names";
1786     else
1787         which = "Subsequent group of names";
1788     
1789     proto_tree_add_text(pt, tvb, offset, 1, "%s", which);
1790     proto_tree_add_text(pt, tvb, offset+1, msglen-1, "Directory: %.*s",
1791         msglen-1, tvb_get_ptr(tvb, offset+1, msglen-1));
1792     offset += msglen;
1793     return offset;
1794 }
1795
1796 static int
1797 resp_files(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1798 {
1799     int         msglen;
1800     u_char      *flag;
1801     
1802     msglen = tvb_reported_length_remaining(tvb, offset);
1803     flag = tvb_get_guint8(tvb, offset) ? "Yes": "No";
1804     proto_tree_add_text(pt, tvb, offset, 1, "More filenames to return: %s", flag);
1805     proto_tree_add_text(pt, tvb, offset+1, msglen-1, "File and directory names");
1806     offset += msglen;
1807     return offset;
1808 }
1809
1810 static int
1811 cmd_usdt(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1812 {
1813     u_char  *desc;
1814     guint8  assemble_flag;
1815     
1816     if (tvb_get_guint8(tvb, offset))
1817         desc = "Register with gusdt";
1818     else
1819         desc = "Unregister with gusdt";
1820     proto_tree_add_text(pt, tvb, offset, 1, "%s", desc);
1821     
1822     if (tvb_get_guint8(tvb, offset+1))
1823         desc = "Echo long transmit messages back to the client";
1824     else
1825         desc = "Do not echo long transmit messages back to the client";
1826     proto_tree_add_text(pt, tvb, offset+1, 1, "%s", desc);
1827     
1828     assemble_flag = tvb_get_guint8(tvb, offset+2);
1829     if (assemble_flag == 2)
1830         desc = "Assemble long received messages but do not send them to the client";
1831     else if (assemble_flag)
1832         desc = "Assemble long received messages and send them to the client";
1833     else
1834         desc = "Do not assemble long received messages on behalf of the client";
1835     proto_tree_add_text(pt, tvb, offset+2, 1, "%s", desc);
1836     
1837     offset += 4;
1838     return offset;
1839 }
1840
1841 static int
1842 speed(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1843 {
1844     proto_tree_add_text(pt, tvb, offset, 1, "Baud rate index: %u",
1845         tvb_get_guint8(tvb, offset));
1846     proto_tree_add_text(pt, tvb, offset+1, 3, "reserved");
1847     offset += 4;
1848     return offset;
1849 }
1850
1851 static int
1852 filter_block(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1853 {
1854     unsigned int    type, operator, i;
1855     int     length, padding;
1856     
1857     proto_tree_add_text(pt, tvb, offset, 2, "Filter field starts at byte %u",
1858         tvb_get_ntohs(tvb, offset));
1859     length = tvb_get_ntohs(tvb, offset+2);
1860     proto_tree_add_text(pt, tvb, offset+2, 2, "Filter field is %d bytes long", length);
1861     type = tvb_get_guint8(tvb, offset+4);
1862     for (i = 0; i < SIZEOF(filter_data_types); i++) {
1863         if (filter_data_types[i].value == type)
1864             break;
1865     }
1866     if (i >= SIZEOF(filter_data_types))
1867         i = SIZEOF(filter_data_types) - 1;
1868     proto_tree_add_text(pt, tvb, offset+4, 1, "Filtering on %s", filter_data_types[i].strptr);
1869
1870     operator = tvb_get_guint8(tvb, offset+5);
1871     for (i = 0; i < SIZEOF(operators); i++) {
1872         if (operators[i].value == operator)
1873             break;
1874     }
1875     if (i >= SIZEOF(operators))
1876         i = SIZEOF(operators) - 1;
1877     proto_tree_add_text(pt, tvb, offset+5, 1, "Type of comparison: %s", operators[i].strptr);
1878     proto_tree_add_text(pt, tvb, offset+6, 2, "reserved");
1879     offset += 8;
1880     
1881     if (operator == BIT_FIELD_CHECK) {
1882         proto_tree_add_text(pt, tvb, offset, length, "Pattern");
1883         proto_tree_add_text(pt, tvb, offset+length, length, "Mask");
1884     } else {
1885         switch (length) {
1886         case 1:
1887             proto_tree_add_text(pt, tvb, offset, 1, "Value: %u",
1888                 tvb_get_guint8(tvb, offset));
1889             break;
1890         case 2:
1891             proto_tree_add_text(pt, tvb, offset, 2, "Value: %u",
1892                 tvb_get_ntohs(tvb, offset));
1893             break;
1894         case 4:
1895             proto_tree_add_text(pt, tvb, offset, 4, "Value: %u",
1896                 tvb_get_ntohl(tvb, offset));
1897             break;
1898         default:
1899             proto_tree_add_text(pt, tvb, offset, length, "Value");
1900         }
1901     }
1902     offset += length * 2;
1903     padding = 3 - (length * 2 + 3) % 4;
1904     if (padding) {
1905         proto_tree_add_text(pt, tvb, offset, padding, "padding");
1906         offset += padding;
1907     }
1908     return offset;
1909 }
1910
1911 static int
1912 blm_mode(tvbuff_t *tvb, int offset, int src, proto_tree *pt)
1913 {
1914     char    *mode, line[50];
1915     int     x, y, seconds;
1916     
1917     x = tvb_get_ntohl(tvb, offset);
1918     y = tvb_get_ntohl(tvb, offset+4);
1919     switch (x) {
1920     case 0:
1921         mode = "Off";
1922         sprintf (line, "reserved");
1923         break;
1924     case 1:
1925         mode = "Average over time";
1926         seconds = y / 1000;
1927         y = y % 1000;
1928         sprintf (line, "Averaging period: %d.%03d seconds", seconds, y);
1929         break;
1930     case 2:
1931         mode = "Average over frame count";
1932         sprintf (line, "Averaging period: %d frames", y);
1933         break;
1934     default:
1935         mode = "- unknown -";
1936         sprintf (line, "reserved");
1937     }
1938     proto_tree_add_text(pt, tvb, offset, 4, "Mode: %s", mode);
1939     offset += 4;
1940     proto_tree_add_text(pt, tvb, offset, 4, line, NULL);
1941     offset += 4;
1942     return offset;
1943 }
1944
1945 void
1946 proto_register_gryphon(void)
1947 {
1948     static hf_register_info hf[] = {
1949         { &hf_gryph_src,
1950         { "Source",           "gryph.src", FT_UINT8, BASE_DEC, NULL, 0x0,
1951                 "", HFILL }},
1952         { &hf_gryph_srcchan,
1953         { "Source channel",   "gryph.srcchan", FT_UINT8, BASE_DEC, NULL, 0x0,
1954                 "", HFILL }},
1955         { &hf_gryph_dest,
1956         { "Destination",      "gryph.dest", FT_UINT8, BASE_DEC, NULL, 0x0,
1957                 "", HFILL }},
1958         { &hf_gryph_destchan,
1959         { "Destination channel", "gryph.dstchan", FT_UINT8, BASE_DEC, NULL, 0x0,
1960                 "", HFILL }},
1961         { &hf_gryph_type,
1962         { "Frame type",       "gryph.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1963                 "", HFILL }},
1964         { &hf_gryph_cmd,
1965         { "Command",          "gryph.cmd.cmd", FT_UINT8, BASE_DEC, NULL, 0x0,
1966                 "", HFILL }},
1967     };
1968
1969     static gint *ett[] = {
1970         &ett_gryphon,
1971         &ett_gryphon_header,
1972         &ett_gryphon_body,
1973         &ett_gryphon_command_data,
1974         &ett_gryphon_response_data,
1975         &ett_gryphon_data_header,
1976         &ett_gryphon_flags,
1977         &ett_gryphon_data_body,
1978         &ett_gryphon_cmd_filter_block,
1979         &ett_gryphon_cmd_events_data,
1980         &ett_gryphon_cmd_config_device,
1981         &ett_gryphon_cmd_sched_data,
1982         &ett_gryphon_cmd_sched_cmd,
1983         &ett_gryphon_cmd_response_block,
1984         &ett_gryphon_pgm_list,
1985         &ett_gryphon_pgm_status,
1986         &ett_gryphon_pgm_options,
1987     };
1988     module_t *gryphon_module;
1989
1990     proto_gryphon = proto_register_protocol("DG Gryphon Protocol",
1991                                             "Gryphon",
1992                                             "gryphon");
1993     proto_register_field_array(proto_gryphon, hf, array_length(hf));
1994     proto_register_subtree_array(ett, array_length(ett));
1995
1996     gryphon_module = prefs_register_protocol(proto_gryphon, NULL);
1997     prefs_register_bool_preference(gryphon_module, "desegment",
1998         "Desegment all Gryphon messages spanning multiple TCP segments",
1999         "Whether the Gryphon dissector should desegment all messages spanning multiple TCP segments",
2000         &gryphon_desegment);
2001 }
2002
2003 void
2004 proto_reg_handoff_gryphon(void)
2005 {
2006     dissector_handle_t gryphon_handle;
2007
2008     gryphon_handle = create_dissector_handle(dissect_gryphon, proto_gryphon);
2009     dissector_add("tcp.port", 7000, gryphon_handle);
2010 }
2011
2012 /* Start the functions we need for the plugin stuff */
2013 G_MODULE_EXPORT void
2014 plugin_reg_handoff(void){
2015   proto_reg_handoff_gryphon();
2016 }
2017
2018 G_MODULE_EXPORT void
2019 plugin_init(plugin_address_table_t *pat
2020 #ifndef PLUGINS_NEED_ADDRESS_TABLE
2021 _U_
2022 #endif
2023 ){
2024   /* initialise the table of pointers needed in Win32 DLLs */
2025   plugin_address_table_init(pat);
2026   /* register the new protocol, protocol fields, and subtrees */
2027   if (proto_gryphon == -1) { /* execute protocol initialization only once */
2028     proto_register_gryphon();
2029   }
2030 }
2031 /* End the functions we need for plugin stuff */