Coverage Report

Created: 2026-08-14 06:45

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
0
#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.38k
{
83
5.38k
    proto_tree *h1_tree, *block_tree;
84
5.38k
    proto_item *h1_ti, *block_ti;
85
5.38k
    int offset = 0, offset_block_start;
86
5.38k
    uint8_t h1_len;
87
5.38k
    uint8_t block_type, block_len;
88
5.38k
    tvbuff_t *next_tvb;
89
90
5.38k
    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
240
        return false;
94
240
    }
95
96
5.14k
    if (!(tvb_get_uint8(tvb, 0) == 'S' && tvb_get_uint8(tvb, 1) == '5')) {
97
5.13k
        return false;
98
5.13k
    }
99
100
3
    col_set_str (pinfo->cinfo, COL_PROTOCOL, "H1");
101
3
    col_set_str(pinfo->cinfo, COL_INFO, "S5: ");
102
103
3
    h1_ti = proto_tree_add_item(tree, proto_h1, tvb, offset, -1, ENC_NA);
104
3
    h1_tree = proto_item_add_subtree(h1_ti, ett_h1);
105
106
3
    proto_tree_add_item(h1_tree, hf_h1_header, tvb, offset, 2, ENC_BIG_ENDIAN);
107
3
    offset += 2;
108
109
3
    proto_tree_add_item_ret_uint8(h1_tree, hf_h1_len, tvb, offset, 1, ENC_BIG_ENDIAN, &h1_len);
110
3
    proto_item_set_len(h1_ti, h1_len);
111
3
    offset++;
112
113
5
    while (offset < h1_len) {
114
3
        offset_block_start = offset;
115
116
3
        block_type = tvb_get_uint8(tvb, offset);
117
3
        block_len = tvb_get_uint8(tvb, offset+1);
118
119
3
        if (!try_val_to_str(block_type, block_type_vals)) {
120
            /* XXX - should we skip unknown blocks? */
121
1
            return false;
122
1
        }
123
2
        if (block_len == 0) {
124
            /* XXX - expert info */
125
0
            break;
126
0
        }
127
128
2
        block_tree = proto_tree_add_subtree_format(h1_tree,
129
2
                tvb, offset, -1, ett_block, &block_ti, "%s",
130
2
                val_to_str_const(block_type, block_type_vals, "Unknown block"));
131
132
2
        proto_tree_add_item(block_tree, hf_h1_block_type,
133
2
                tvb, offset, 1, ENC_BIG_ENDIAN);
134
        /* we keep increasing offset as we go though the block
135
           however, to find the beginning of the next block,
136
           we use the current block's start offset and its length field */
137
2
        offset++;
138
2
        proto_tree_add_item(block_tree, hf_h1_block_len,
139
2
                tvb, offset, 1, ENC_BIG_ENDIAN);
140
2
        proto_item_set_len(block_ti, block_len);
141
2
        offset++;
142
143
2
        switch (block_type) {
144
0
            case OPCODE_BLOCK:
145
0
                proto_tree_add_item(block_tree, hf_h1_opcode,
146
0
                        tvb, offset, 1, ENC_BIG_ENDIAN);
147
0
                col_append_str (pinfo->cinfo, COL_INFO,
148
0
                        val_to_str(pinfo->pool, tvb_get_uint8(tvb,  offset),
149
0
                        opcode_vals, "Unknown Opcode (0x%2.2x)"));
150
0
                break;
151
152
0
            case REQUEST_BLOCK:
153
0
                proto_tree_add_item(block_tree, hf_h1_org, tvb,
154
0
                        offset, 1, ENC_BIG_ENDIAN);
155
0
                col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
156
0
                        val_to_str(pinfo->pool, tvb_get_uint8(tvb,  offset),
157
0
                            org_vals,"Unknown Type (0x%2.2x)"));
158
0
                offset++;
159
160
0
                proto_tree_add_item(block_tree, hf_h1_dbnr, tvb,
161
0
                        offset, 1, ENC_BIG_ENDIAN);
162
0
                col_append_fstr(pinfo->cinfo, COL_INFO, " %d",
163
0
                        tvb_get_uint8(tvb,  offset));
164
0
                offset++;
165
166
0
                proto_tree_add_item(block_tree, hf_h1_dwnr, tvb,
167
0
                        offset, 2, ENC_BIG_ENDIAN);
168
0
                col_append_fstr (pinfo->cinfo, COL_INFO, " DW %d",
169
0
                        tvb_get_ntohs(tvb, offset));
170
0
                offset += 2;
171
172
0
                proto_tree_add_item(block_tree, hf_h1_dlen, tvb,
173
0
                        offset, 2, ENC_BIG_ENDIAN);
174
0
                col_append_fstr (pinfo->cinfo, COL_INFO, " Count %d",
175
0
                        tvb_get_ntohs(tvb, offset));
176
0
                break;
177
178
0
            case RESPONSE_BLOCK:
179
0
                proto_tree_add_item(block_tree, hf_h1_response_value,
180
0
                        tvb, offset, 1, ENC_BIG_ENDIAN);
181
0
                col_append_fstr (pinfo->cinfo, COL_INFO, " %s",
182
0
                        val_to_str(pinfo->pool, tvb_get_uint8(tvb,  offset),
183
0
                            returncode_vals,"Unknown Returncode (0x%2.2x"));
184
0
                break;
185
2
        }
186
187
2
        offset = offset_block_start + block_len; /* see the comment above */
188
2
    }
189
190
2
    if (tvb_reported_length_remaining(tvb, offset) > 0) {
191
1
        next_tvb = tvb_new_subset_remaining(tvb,  offset);
192
1
        call_data_dissector(next_tvb, pinfo, tree);
193
1
    }
194
195
2
    return true;
196
3
}
197
198
199
void
200
proto_register_h1 (void)
201
16
{
202
16
    static hf_register_info hf[] = {
203
16
        {&hf_h1_header,
204
16
            {"H1-Header", "h1.header", FT_UINT16, BASE_HEX, NULL, 0x0,
205
16
                NULL, HFILL }},
206
16
        {&hf_h1_len,
207
16
            {"Length indicator", "h1.len", FT_UINT8, BASE_DEC, NULL, 0x0,
208
16
                NULL, HFILL }},
209
16
        {&hf_h1_block_type,
210
16
            {"Block type", "h1.block_type", FT_UINT8, BASE_HEX, VALS(block_type_vals), 0x0,
211
16
                NULL, HFILL }},
212
16
        {&hf_h1_block_len,
213
16
            {"Block length", "h1.block_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
214
16
        {&hf_h1_opcode,
215
16
            {"Opcode", "h1.opcode", FT_UINT8, BASE_HEX, VALS (opcode_vals), 0x0,
216
16
                NULL, HFILL }},
217
16
        {&hf_h1_org,
218
16
            {"Memory type", "h1.org", FT_UINT8, BASE_HEX, VALS (org_vals), 0x0,
219
16
                NULL, HFILL }},
220
16
        {&hf_h1_dbnr,
221
16
            {"Memory block number", "h1.dbnr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
222
16
        {&hf_h1_dwnr,
223
16
            {"Address within memory block", "h1.dwnr", FT_UINT16, BASE_DEC, NULL, 0x0,
224
16
                NULL, HFILL }},
225
16
        {&hf_h1_dlen,
226
16
            {"Length in words", "h1.dlen", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
227
16
        {&hf_h1_response_value,
228
16
            {"Response value", "h1.resvalue", FT_UINT8, BASE_DEC,
229
16
                VALS (returncode_vals), 0x0, NULL, HFILL }}
230
16
    };
231
232
16
    static int *ett[] = {
233
16
        &ett_h1,
234
16
        &ett_block,
235
16
    };
236
237
16
    proto_h1 = proto_register_protocol ("Sinec H1 Protocol", "H1", "h1");
238
16
    proto_register_field_array (proto_h1, hf, array_length (hf));
239
16
    proto_register_subtree_array (ett, array_length (ett));
240
16
}
241
242
void
243
proto_reg_handoff_h1(void)
244
16
{
245
16
    heur_dissector_add("cotp", dissect_h1,
246
16
            "Sinec H1 over COTP", "hi_cotp", proto_h1, HEURISTIC_ENABLE);
247
16
    heur_dissector_add("cotp_is", dissect_h1,
248
16
            "Sinec H1 over COTP (inactive subset)", "hi_cotp_is", proto_h1, HEURISTIC_ENABLE);
249
16
    heur_dissector_add("tcp", dissect_h1,
250
16
            "Sinec H1 over TCP", "hi_tcp", proto_h1, HEURISTIC_ENABLE);
251
16
}
252
253
/*
254
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
255
 *
256
 * Local Variables:
257
 * c-basic-offset: 4
258
 * tab-width: 8
259
 * indent-tabs-mode: nil
260
 * End:
261
 *
262
 * ex: set shiftwidth=4 tabstop=8 expandtab:
263
 * :indentSize=4:tabSize=8:noTabs=true:
264
 */