1 /* packet-h1.c
2 * Routines for Sinec H1 packet disassembly
3 * Gerrit Gehnen <G.Gehnen@atrie.de>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "config.h"
13
14 #include <epan/packet.h>
15 #include <epan/exceptions.h>
16
17 void proto_register_h1(void);
18 void proto_reg_handoff_h1(void);
19
20 static int proto_h1 = -1;
21 static int hf_h1_header = -1;
22 static int hf_h1_len = -1;
23 static int hf_h1_block_type = -1;
24 static int hf_h1_block_len = -1;
25 static int hf_h1_opcode = -1;
26 static int hf_h1_dbnr = -1;
27 static int hf_h1_dwnr = -1;
28 static int hf_h1_dlen = -1;
29 static int hf_h1_org = -1;
30 static int hf_h1_response_value = -1;
31
32
33 #define EMPTY_BLOCK 0xFF
34 #define OPCODE_BLOCK 0x01
35 #define REQUEST_BLOCK 0x03
36 #define RESPONSE_BLOCK 0x0F
37
38 static const value_string block_type_vals[] = {
39 { EMPTY_BLOCK, "Empty Block" },
40 { OPCODE_BLOCK, "Opcode Block" },
41 { REQUEST_BLOCK, "Request Block" },
42 { RESPONSE_BLOCK, "Response Block" },
43 {0, NULL}
44 };
45
46
47 static const value_string opcode_vals[] = {
48 {3, "Write Request"},
49 {4, "Write Response"},
50 {5, "Read Request"},
51 {6, "Read Response"},
52 {0, NULL}
53 };
54
55 static const value_string org_vals[] = {
56 {0x01, "DB"},
57 {0x02, "MB"},
58 {0x03, "EB"},
59 {0x04, "AB"},
60 {0x05, "PB"},
61 {0x06, "ZB"},
62 {0x07, "TB"},
63 {0x08, "BS"},
64 {0x09, "AS"},
65 {0x0a, "DX"},
66 {0x10, "DE"},
67 {0x11, "QB"},
68 {0, NULL}
69 };
70
71 static const value_string returncode_vals[] = {
72 {0x00, "No error"},
73 {0x02, "Requested block does not exist"},
74 {0x03, "Requested block too small"},
75 {0xFF, "Error, reason unknown"},
76 {0, NULL}
77 };
78
79 static gint ett_h1 = -1;
80 static gint ett_block = -1;
81
dissect_h1(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)82 static gboolean dissect_h1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
83 {
84 proto_tree *h1_tree, *block_tree;
85 proto_item *h1_ti, *block_ti;
86 gint offset = 0, offset_block_start;
87 guint8 h1_len;
88 guint8 block_type, block_len;
89 tvbuff_t *next_tvb;
90
91 if (tvb_captured_length(tvb) < 2) {
92 /* Not enough data captured to hold the "S5" header; don't try
93 to interpret it as H1. */
94 return FALSE;
95 }
96
97 if (!(tvb_get_guint8(tvb, 0) == 'S' && tvb_get_guint8(tvb, 1) == '5')) {
98 return FALSE;
99 }
100
101 col_set_str (pinfo->cinfo, COL_PROTOCOL, "H1");
102 col_set_str(pinfo->cinfo, COL_INFO, "S5: ");
103
104 h1_ti = proto_tree_add_item(tree, proto_h1, tvb, offset, -1, ENC_NA);
105 h1_tree = proto_item_add_subtree(h1_ti, ett_h1);
106
107 proto_tree_add_item(h1_tree, hf_h1_header, tvb, offset, 2, ENC_BIG_ENDIAN);
108 offset += 2;
109
110 h1_len = tvb_get_guint8(tvb, offset);
111 proto_tree_add_item(h1_tree, hf_h1_len, tvb, offset, 1, ENC_BIG_ENDIAN);
112 proto_item_set_len(h1_ti, h1_len);
113 offset++;
114
115 while (offset < h1_len) {
116 offset_block_start = offset;
117
118 block_type = tvb_get_guint8(tvb, offset);
119 block_len = tvb_get_guint8(tvb, offset+1);
120
121 if (!try_val_to_str(block_type, block_type_vals)) {
122 /* XXX - should we skip unknown blocks? */
123 return FALSE;
124 }
125 if (block_len == 0) {
126 /* XXX - expert info */
127 break;
128 }
129
130 block_tree = proto_tree_add_subtree_format(h1_tree,
131 tvb, offset, -1, ett_block, &block_ti, "%s",
132 val_to_str_const(block_type, block_type_vals, "Unknown block"));
133
134 proto_tree_add_item(block_tree, hf_h1_block_type,
135 tvb, offset, 1, ENC_BIG_ENDIAN);
136 /* we keep increasing offset as we go though the block
137 however, to find the beginning of the next block,
138 we use the current block's start offset and its length field */
139 offset++;
140 proto_tree_add_item(block_tree, hf_h1_block_len,
141 tvb, offset, 1, ENC_BIG_ENDIAN);
142 proto_item_set_len(block_ti, block_len);
143 offset++;
144
145 switch (block_type) {
146 case OPCODE_BLOCK:
147 proto_tree_add_item(block_tree, hf_h1_opcode,
148 tvb, offset, 1, ENC_BIG_ENDIAN);
149 col_append_str (pinfo->cinfo, COL_INFO,
150 val_to_str (tvb_get_guint8(tvb, offset),
151 opcode_vals, "Unknown Opcode (0x%2.2x)"));
152 break;
153
154 case REQUEST_BLOCK:
155 proto_tree_add_item(block_tree, hf_h1_org, tvb,
156 offset, 1, ENC_BIG_ENDIAN);
157 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
158 val_to_str (tvb_get_guint8(tvb, offset),
159 org_vals,"Unknown Type (0x%2.2x)"));
160 offset++;
161
162 proto_tree_add_item(block_tree, hf_h1_dbnr, tvb,
163 offset, 1, ENC_BIG_ENDIAN);
164 col_append_fstr(pinfo->cinfo, COL_INFO, " %d",
165 tvb_get_guint8(tvb, offset));
166 offset++;
167
168 proto_tree_add_item(block_tree, hf_h1_dwnr, tvb,
169 offset, 2, ENC_BIG_ENDIAN);
170 col_append_fstr (pinfo->cinfo, COL_INFO, " DW %d",
171 tvb_get_ntohs(tvb, offset));
172 offset += 2;
173
174 proto_tree_add_item(block_tree, hf_h1_dlen, tvb,
175 offset, 2, ENC_BIG_ENDIAN);
176 col_append_fstr (pinfo->cinfo, COL_INFO, " Count %d",
177 tvb_get_ntohs(tvb, offset));
178 break;
179
180 case RESPONSE_BLOCK:
181 proto_tree_add_item(block_tree, hf_h1_response_value,
182 tvb, offset, 1, ENC_BIG_ENDIAN);
183 col_append_fstr (pinfo->cinfo, COL_INFO, " %s",
184 val_to_str (tvb_get_guint8(tvb, offset),
185 returncode_vals,"Unknown Returncode (0x%2.2x"));
186 break;
187 }
188
189 offset = offset_block_start + block_len; /* see the comment above */
190 }
191
192 if (tvb_reported_length_remaining(tvb, offset) > 0) {
193 next_tvb = tvb_new_subset_remaining(tvb, offset);
194 call_data_dissector(next_tvb, pinfo, tree);
195 }
196
197 return TRUE;
198 }
199
200
201 void
proto_register_h1(void)202 proto_register_h1 (void)
203 {
204 static hf_register_info hf[] = {
205 {&hf_h1_header,
206 {"H1-Header", "h1.header", FT_UINT16, BASE_HEX, NULL, 0x0,
207 NULL, HFILL }},
208 {&hf_h1_len,
209 {"Length indicator", "h1.len", FT_UINT16, BASE_DEC, NULL, 0x0,
210 NULL, HFILL }},
211 {&hf_h1_block_type,
212 {"Block type", "h1.block_type", FT_UINT8, BASE_HEX, VALS(block_type_vals), 0x0,
213 NULL, HFILL }},
214 {&hf_h1_block_len,
215 {"Block length", "h1.block_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
216 {&hf_h1_opcode,
217 {"Opcode", "h1.opcode", FT_UINT8, BASE_HEX, VALS (opcode_vals), 0x0,
218 NULL, HFILL }},
219 {&hf_h1_org,
220 {"Memory type", "h1.org", FT_UINT8, BASE_HEX, VALS (org_vals), 0x0,
221 NULL, HFILL }},
222 {&hf_h1_dbnr,
223 {"Memory block number", "h1.dbnr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
224 {&hf_h1_dwnr,
225 {"Address within memory block", "h1.dwnr", FT_UINT16, BASE_DEC, NULL, 0x0,
226 NULL, HFILL }},
227 {&hf_h1_dlen,
228 {"Length in words", "h1.dlen", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
229 {&hf_h1_response_value,
230 {"Response value", "h1.resvalue", FT_UINT8, BASE_DEC,
231 VALS (returncode_vals), 0x0, NULL, HFILL }}
232 };
233
234 static gint *ett[] = {
235 &ett_h1,
236 &ett_block,
237 };
238
239 proto_h1 = proto_register_protocol ("Sinec H1 Protocol", "H1", "h1");
240 proto_register_field_array (proto_h1, hf, array_length (hf));
241 proto_register_subtree_array (ett, array_length (ett));
242 }
243
244 void
proto_reg_handoff_h1(void)245 proto_reg_handoff_h1(void)
246 {
247 heur_dissector_add("cotp", dissect_h1,
248 "Sinec H1 over COTP", "hi_cotp", proto_h1, HEURISTIC_ENABLE);
249 heur_dissector_add("cotp_is", dissect_h1,
250 "Sinec H1 over COTP (inactive subset)", "hi_cotp_is", proto_h1, HEURISTIC_ENABLE);
251 heur_dissector_add("tcp", dissect_h1,
252 "Sinec H1 over TCP", "hi_tcp", proto_h1, HEURISTIC_ENABLE);
253 }
254
255 /*
256 * Editor modelines - https://www.wireshark.org/tools/modelines.html
257 *
258 * Local Variables:
259 * c-basic-offset: 4
260 * tab-width: 8
261 * indent-tabs-mode: nil
262 * End:
263 *
264 * ex: set shiftwidth=4 tabstop=8 expandtab:
265 * :indentSize=4:tabSize=8:noTabs=true:
266 */
267