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