97250f41ae750280ca4bd515616bd0d3a29088cd
[obnox/wireshark/wip.git] / plugins / interlink / packet-interlink.c
1 /* packet-interlink.c
2  * Routines for Interlink protocol packet disassembly
3  * By Uwe Girlich <uwe.girlich@philosys.de>
4  * Copyright 2010 Uwe Girlich
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <epan/packet.h>
32
33
34 /*
35  * No public information available.
36  */
37
38 static int proto_interlink = -1;
39
40 static int hf_interlink_id = -1;
41 static int hf_interlink_version = -1;
42 static int hf_interlink_cmd = -1;
43 static int hf_interlink_seq = -1;
44 static int hf_interlink_flags = -1;
45 static int hf_interlink_flags_req_ack = -1;
46 static int hf_interlink_flags_inc_ack_port = -1;
47 static int hf_interlink_block_type = -1;
48 static int hf_interlink_block_version = -1;
49 static int hf_interlink_block_length = -1;
50
51 static gint ett_interlink = -1;
52 static gint ett_interlink_header = -1;
53 static gint ett_interlink_flags = -1;
54 static gint ett_interlink_block = -1;
55
56 static dissector_handle_t data_handle;
57 static dissector_table_t subdissector_table;
58
59 static const true_false_string flags_set_notset = {
60         "Set", "Not set"
61 };
62
63 static const value_string names_cmd[] = {
64         { 1, "Data" },
65         { 2, "Ack" },
66         { 0, NULL }
67 };
68
69
70 static void
71 dissect_interlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
72 {
73         int             offset = 0;
74         proto_tree      *il_tree = NULL;
75         proto_tree      *ilh_tree = NULL;
76         proto_tree      *ilb_tree = NULL;
77         guint8          ilb_type;
78         guint8          ilb_version;
79         guint16         type_version = 0;
80         dissector_handle_t      handle;
81         tvbuff_t        *next_tvb;
82
83         col_set_str(pinfo->cinfo, COL_PROTOCOL, "INTERLINK");
84         col_clear(pinfo->cinfo, COL_INFO);
85
86         if (tree) {
87                 proto_item      *il_item;
88                 il_item = proto_tree_add_item(tree, proto_interlink,
89                                                                 tvb, 0, 16, FALSE);
90                 if (il_item)
91                         il_tree = proto_item_add_subtree(il_item, ett_interlink);
92         }
93
94         if (il_tree) {
95                 proto_item      *ilh_item = NULL;
96                 ilh_item = proto_tree_add_text(il_tree, tvb, 0, 12, "Interlink Header");
97                 if (ilh_item)
98                         ilh_tree = proto_item_add_subtree(ilh_item, ett_interlink_header);
99         }
100
101         if (ilh_tree) {
102                 proto_tree_add_item(ilh_tree, hf_interlink_id, tvb, offset, 4, FALSE);
103                 offset += 4;
104                 proto_tree_add_item(ilh_tree, hf_interlink_version, tvb, offset, 2, TRUE);
105                 offset += 2;
106                 proto_tree_add_item(ilh_tree, hf_interlink_cmd, tvb, offset, 2, TRUE);
107                 offset += 2;
108                 proto_tree_add_item(ilh_tree, hf_interlink_seq, tvb, offset, 2, TRUE);
109                 offset += 2;
110         }
111
112         if (ilh_tree) {
113                 proto_item      *flags_item;
114                 proto_tree      *flags_tree = NULL;
115
116                 flags_item = proto_tree_add_item(ilh_tree, hf_interlink_flags,
117                         tvb, offset, 2, TRUE);
118                 if (flags_item) {
119                         flags_tree = proto_item_add_subtree(flags_item, ett_interlink_flags);
120                 }
121                 if (flags_tree) {
122                         guint16         il_flags;
123                         il_flags = tvb_get_letohs(tvb, offset);
124                         proto_tree_add_boolean(flags_tree, hf_interlink_flags_req_ack, tvb, offset, 2, il_flags);
125                         proto_tree_add_boolean(flags_tree, hf_interlink_flags_inc_ack_port, tvb, offset, 2, il_flags);
126                 }
127         }
128         offset += 2;
129
130         if (tree) {
131                 proto_item      *ilb_item;
132                 ilb_item = proto_tree_add_text(il_tree, tvb, offset, 4, "Block Header");
133                 if (ilb_item)
134                         ilb_tree = proto_item_add_subtree(ilb_item, ett_interlink_block);
135         }
136
137         ilb_type = tvb_get_guint8(tvb, offset);
138         ilb_version = tvb_get_guint8(tvb, offset + 1);
139         type_version = ilb_type << 8 | ilb_version;
140         col_append_fstr(pinfo->cinfo, COL_INFO, "Type: 0x%02x, Version: %d",
141                 ilb_type, ilb_version);
142
143         if (ilb_tree) {
144                 proto_tree_add_item(ilb_tree, hf_interlink_block_type, tvb, offset, 1, FALSE);
145                 offset += 1;
146                 proto_tree_add_item(ilb_tree, hf_interlink_block_version, tvb, offset, 1, FALSE);
147                 offset += 1;
148                 proto_tree_add_item(ilb_tree, hf_interlink_block_length, tvb, offset, 2, TRUE);
149                 offset += 2;
150         }
151
152         /* Generate a new tvb for the rest. */
153         next_tvb = tvb_new_subset_remaining(tvb, offset);
154
155         /* Probably a sub-dissector exists for this type/version combination. */
156         handle = dissector_get_port_handle(subdissector_table, type_version);
157
158         /* Without a proper sub-dissector, we use "data". */
159         if (handle == NULL) handle = data_handle;
160
161         /* Call the sub-dissector. */
162         call_dissector(handle, next_tvb, pinfo, tree);
163 }
164
165
166 static gboolean
167 dissect_interlink_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
168 {
169         if (!tvb_bytes_exist(tvb, 0, 4)) {
170                 return FALSE;
171         }
172         if (
173                 tvb_get_guint8(tvb,0) != 'I' ||
174                 tvb_get_guint8(tvb,1) != 'L' ||
175                 tvb_get_guint8(tvb,2) != 'N' ||
176                 tvb_get_guint8(tvb,3) != 'K'
177         )
178                 return FALSE;
179
180         dissect_interlink(tvb, pinfo, tree);
181         return TRUE;
182 }
183
184
185 void
186 proto_register_interlink(void)
187 {
188         static hf_register_info hf[] = {
189                 { &hf_interlink_id, {
190                         "Magic ID", "interlink.id", FT_STRING,
191                         BASE_NONE, NULL, 0, NULL, HFILL }},
192                 { &hf_interlink_version, {
193                         "Version", "interlink.version", FT_UINT16,
194                         BASE_DEC, NULL, 0, NULL, HFILL }},
195                 { &hf_interlink_cmd, {
196                         "Command", "interlink.cmd", FT_UINT16,
197                         BASE_DEC, VALS(names_cmd), 0, NULL, HFILL }},
198                 { &hf_interlink_seq, {
199                         "Sequence", "interlink.seq", FT_UINT16,
200                         BASE_DEC, NULL, 0, NULL, HFILL }},
201                 { &hf_interlink_flags, {
202                         "Flags", "interlink.flags", FT_UINT16,
203                         BASE_HEX, NULL, 0, NULL, HFILL }},
204                 { &hf_interlink_flags_req_ack, {
205                         "REQ_ACK", "interlink.flags.req_ack", FT_BOOLEAN,
206                         16, TFS(&flags_set_notset), 0x01, NULL, HFILL }},
207                 { &hf_interlink_flags_inc_ack_port, {
208                         "INC_ACK_PORT", "interlink.flags.inc_ack_port", FT_BOOLEAN,
209                         16, TFS(&flags_set_notset), 0x02, NULL, HFILL }},
210                 { &hf_interlink_block_type, {
211                         "Type", "interlink.type", FT_UINT8,
212                         BASE_HEX, NULL, 0, NULL, HFILL }},
213                 { &hf_interlink_block_version, {
214                         "Version", "interlink.block_version", FT_UINT8,
215                         BASE_DEC, NULL, 0, NULL, HFILL }},
216                 { &hf_interlink_block_length, {
217                         "Length", "interlink.length", FT_UINT16,
218                         BASE_DEC, NULL, 0, NULL, HFILL }},
219         };
220
221         static gint *ett[] = {
222                 &ett_interlink,
223                 &ett_interlink_header,
224                 &ett_interlink_flags,
225                 &ett_interlink_block,
226         };
227
228         proto_interlink = proto_register_protocol("Interlink Protocol",
229                                                         "Interlink",
230                                                         "interlink");
231         proto_register_field_array(proto_interlink, hf, array_length(hf));
232         proto_register_subtree_array(ett, array_length(ett));
233         register_dissector("interlink", dissect_interlink, proto_interlink);
234
235         /* Probably someone will write sub-dissectors. You can never know. */
236         subdissector_table = register_dissector_table("interlink.type_version",
237                 "Interlink type_version", FT_UINT16, BASE_HEX);
238 }
239
240
241 void
242 proto_reg_handoff_interlink(void)
243 {
244         dissector_handle_t interlink_handle;
245         interlink_handle = find_dissector("interlink");
246
247         /* Allow "Decode As" with any UDP packet. */
248         dissector_add_handle("udp.port", interlink_handle);
249
250         /* Add our heuristic packet finder. */
251         heur_dissector_add("udp", dissect_interlink_heur, proto_interlink);
252
253         data_handle = find_dissector("data");
254 }
255