Coverage Report

Created: 2026-01-02 06:13

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