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-scop.c
Line
Count
Source
1
/* packet-scop.c
2
 * Owen Kirby <osk@exegin.com>
3
 *
4
 * Wireshark - Network traffic analyzer
5
 * By Gerald Combs <gerald@wireshark.org>
6
 * Copyright 1998 Gerald Combs
7
 *
8
 * SPDX-License-Identifier: GPL-2.0-or-later
9
 */
10
11
#include "config.h"
12
13
#include <epan/packet.h>
14
#include "packet-tcp.h"
15
16
/* Default SCOP Port numbers. */
17
32
#define SCOP_DEFAULT_PORT_RANGE     "17755-17756"
18
19
void proto_register_scop(void);
20
21
/* Structure to contain information from the SCoP packet. */
22
typedef struct {
23
    uint8_t     transport;
24
    uint8_t     version;
25
    uint16_t    length;
26
    bool        encrypted;
27
    uint8_t     service;
28
    uint8_t     type;
29
} scop_packet;
30
31
/* Header definitions for use with the TCP transport layer. */
32
3.05k
#define SCOP_HEADER_LENGTH      4
33
3.26k
#define SCOP_LENGTH_OFFSET      2
34
35
/* SCoP Transport Types */
36
#define SCOP_TRANSPORT_UDP        1
37
#define SCOP_TRANSPORT_TCP        2
38
9.98k
#define SCOP_TRANSPORT_UDP_CCM  129
39
9.98k
#define SCOP_TRANSPORT_TCP_CCM  130
40
#define SCOP_TRANSPORT_TCP_SSL  131
41
42
/* Service Identifier Field */
43
31
#define SCOP_SERVICE_SCOP       0x00
44
9.80k
#define SCOP_SERVICE_BRIDGE     0x01
45
1
#define SCOP_SERVICE_GATEWAY    0x02
46
47
/* SCoP Command Values */
48
#define SCOP_CMD_HELLO          0x00
49
31
#define SCOP_CMD_HELLO_RESP     0x01
50
#define SCOP_CMD_HELLO_ACK      0x02
51
#define SCOP_CMD_GOODBYE        0x04
52
#define SCOP_CMD_GOODBYE_RESP   0x05
53
#define SCOP_CMD_KEEPALIVE_PING 0x06
54
#define SCOP_CMD_KEEPALIVE_PONG 0x07
55
56
/* Bridge Command type values. */
57
#define SCOP_BRIDGE_CMD         0x00
58
#define SCOP_BRIDGE_MSG         0x01
59
60
/*  Function declarations */
61
void proto_reg_handoff_scop(void);
62
63
static void dissect_scop_zip       (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
64
static void dissect_scop_bridge    (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
65
66
static unsigned get_scop_length(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data);
67
68
/*  Initialize protocol and registered fields */
69
static int proto_scop;
70
static int hf_scop_transport;
71
static int hf_scop_version;
72
static int hf_scop_length;
73
static int hf_scop_service;
74
static int hf_scop_type;
75
static int hf_scop_status;
76
77
static int ett_scop;
78
79
static const value_string scop_transports [] = {
80
    { SCOP_TRANSPORT_UDP,       "UDP Mode 1" },
81
    { SCOP_TRANSPORT_TCP,       "TCP Mode 2" },
82
    { SCOP_TRANSPORT_UDP_CCM,   "UDP Mode 1 with CCM* Security" },
83
    { SCOP_TRANSPORT_TCP_CCM,   "TCP Mode 2 with CCM* Security" },
84
    { SCOP_TRANSPORT_TCP_SSL,   "TCP Mode 3 with SSL/TSL Tunnel" },
85
    { 0, NULL }
86
};
87
88
static const value_string scop_types [] = {
89
    { SCOP_CMD_HELLO,           "Hello" },
90
    { SCOP_CMD_HELLO_RESP,      "Hello Response" },
91
    { SCOP_CMD_HELLO_ACK,       "Hello Acknowledgment" },
92
    { SCOP_CMD_GOODBYE,         "Goodbye" },
93
    { SCOP_CMD_GOODBYE_RESP,    "Goodbye Response" },
94
    { SCOP_CMD_KEEPALIVE_PING,  "Keep Alive Ping" },
95
    { SCOP_CMD_KEEPALIVE_PONG,  "Keep Alive Pong" },
96
    { 0, NULL }
97
};
98
99
static const value_string scop_services [] = {
100
    { SCOP_SERVICE_SCOP,    "SCoP" },
101
    { SCOP_SERVICE_BRIDGE,  "Bridge" },
102
    { SCOP_SERVICE_GATEWAY, "Gateway" },
103
    { 0, NULL }
104
};
105
106
/*  Dissector handle */
107
static dissector_handle_t ieee802154_handle;
108
static dissector_handle_t  scop_udp_handle;
109
static dissector_handle_t  scop_tcp_handle;
110
111
112
/*FUNCTION:------------------------------------------------------
113
 *  NAME
114
 *      dissect_scop
115
 *  DESCRIPTION
116
 *      ZigBee SCoP packet dissection routine for Wireshark.
117
 *  PARAMETERS
118
 *      tvbuff_t    *tvb    - pointer to buffer containing raw packet.
119
 *      packet_info *pinfo  - pointer to packet information fields
120
 *      proto_tree  *tree   - pointer to data tree Wireshark uses to display packet.
121
 *  RETURNS
122
 *      void
123
 *---------------------------------------------------------------
124
 */
125
static int
126
dissect_scop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
127
9.98k
{
128
9.98k
    tvbuff_t    *next_tvb;
129
9.98k
    proto_item  *proto_root;
130
9.98k
    proto_tree  *scop_tree;
131
132
9.98k
    unsigned     offset = 0;
133
9.98k
    scop_packet  packet;
134
135
9.98k
    memset(&packet, 0, sizeof(packet));
136
137
    /* Set the protocol name. */
138
9.98k
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "SCoP");
139
140
    /* Clear the info column. */
141
9.98k
    col_clear(pinfo->cinfo, COL_INFO);
142
143
    /* Create the protocol display tree. */
144
9.98k
    proto_root = proto_tree_add_protocol_format(tree, proto_scop, tvb, 0, tvb_captured_length(tvb),
145
9.98k
                                                "ZigBee SCoP");
146
9.98k
    scop_tree = proto_item_add_subtree(proto_root, ett_scop);
147
148
    /* Extract the SCoP Transport type. */
149
9.98k
    packet.transport = tvb_get_uint8(tvb, offset);
150
9.98k
    proto_tree_add_uint(scop_tree, hf_scop_transport, tvb, offset, 1, packet.transport);
151
9.98k
    offset += 1;
152
153
    /* Extract the SCoP Version. */
154
9.98k
    packet.version = tvb_get_uint8(tvb, offset);
155
9.98k
    proto_tree_add_uint(scop_tree, hf_scop_version, tvb, offset, 1, packet.version);
156
9.98k
    offset += 1;
157
158
    /* Extract the SCoP Packet length. */
159
9.98k
    packet.length = tvb_get_ntohs(tvb, offset);
160
9.98k
    proto_tree_add_uint(scop_tree, hf_scop_length, tvb, offset, 2, packet.length);
161
9.98k
    offset += 2;
162
163
9.98k
    if (   (packet.transport == SCOP_TRANSPORT_UDP_CCM)
164
9.98k
        || (packet.transport == SCOP_TRANSPORT_TCP_CCM)) {
165
        /* Decryption Failed. */
166
4
        return offset;
167
4
    }
168
9.98k
    next_tvb = tvb;
169
170
    /* Extract the service type. */
171
9.98k
    packet.service = tvb_get_uint8(next_tvb, offset);
172
9.98k
    proto_tree_add_uint(scop_tree, hf_scop_service, next_tvb, offset, 1, packet.service);
173
9.98k
    offset += 1;
174
175
    /* Call the appropriate helper routine to dissect based on the service type. */
176
9.98k
    switch (packet.service) {
177
31
        case SCOP_SERVICE_SCOP:
178
31
            dissect_scop_zip(tvb_new_subset_remaining(next_tvb, offset), pinfo, scop_tree);
179
31
            break;
180
9.80k
        case SCOP_SERVICE_BRIDGE:
181
9.80k
            dissect_scop_bridge(tvb_new_subset_remaining(next_tvb, offset), pinfo, scop_tree);
182
9.80k
            break;
183
1
        case SCOP_SERVICE_GATEWAY:
184
            /* Nothing yet defined for the gateway. Fall-Through. */
185
139
        default:
186
            /* Unknown Service Type. */
187
139
            call_data_dissector(tvb_new_subset_remaining(next_tvb, offset), pinfo, tree);
188
139
            break;
189
9.98k
    }
190
191
9.62k
    return tvb_captured_length(tvb);
192
9.98k
} /* dissect_scop() */
193
194
/*FUNCTION:------------------------------------------------------
195
 *  NAME
196
 *      get_scop_length
197
 *  DESCRIPTION
198
 *      Returns the length of a SCoP packet. For use with the TCP
199
 *      transport type.
200
 *  PARAMETERS
201
 *      packet_info *pinfo  - pointer to packet information fields
202
 *      tvbuff_t    *tvb    - pointer to buffer containing the packet.
203
 *      int         offset  - beginning of packet.
204
 *  RETURNS
205
 *      unsigned            - Length of SCoP packet
206
 *---------------------------------------------------------------
207
 */
208
static unsigned
209
get_scop_length(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
210
3.26k
{
211
    /* Byte  0:   Protocol Type.
212
     * Byte  1:   Protocol Version.
213
     * Bytes 2-3: Packet Length (network order).
214
     */
215
3.26k
    return tvb_get_ntohs(tvb, offset + SCOP_LENGTH_OFFSET);
216
3.26k
} /* get_scop_length */
217
218
/*FUNCTION:------------------------------------------------------
219
 *  NAME
220
 *      dissect_scop_tcp
221
 *  DESCRIPTION
222
 *      ZigBee SCoP packet dissection routine for Wireshark.
223
 *      for use with TCP ports.
224
 *  PARAMETERS
225
 *      tvbuff_t    *tvb    - pointer to buffer containing raw packet.
226
 *      packet_info *pinfo  - pointer to packet information fields
227
 *      proto_tree  *tree   - pointer to data tree Wireshark uses to display packet.
228
 *  RETURNS
229
 *      void
230
 *---------------------------------------------------------------
231
 */
232
static int
233
dissect_scop_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
234
3.05k
{
235
3.05k
    tcp_dissect_pdus(tvb, pinfo, tree, true, SCOP_HEADER_LENGTH, get_scop_length, dissect_scop, data);
236
3.05k
    return tvb_captured_length(tvb);
237
3.05k
} /* dissect_scop_tcp */
238
239
240
/*FUNCTION:------------------------------------------------------
241
 *  NAME
242
 *      dissect_scop_zip
243
 *  DESCRIPTION
244
 *      Intermediate dissector for the SCoP service type.
245
 *  PARAMETERS
246
 *      tvbuff_t    *tvb    - pointer to buffer containing raw packet.
247
 *      packet_info *pinfo  - pointer to packet information fields
248
 *      proto_tree  *tree   - pointer to data tree Wireshark uses to display packet.
249
 *  RETURNS
250
 *      void
251
 *---------------------------------------------------------------
252
 */
253
static void
254
dissect_scop_zip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
255
31
{
256
31
    unsigned    offset = 0;
257
31
    uint8_t     type = tvb_get_uint8(tvb, offset);
258
31
    uint16_t    status;
259
260
    /* Display the Packet type*/
261
31
    proto_tree_add_uint(tree, hf_scop_type, tvb, offset, 1, type);
262
31
    proto_item_append_text(tree, ", %s", val_to_str_const(type, scop_types, "Reserved Type"));
263
31
    col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(type, scop_types, "Reserved Type"));
264
31
    offset += 2;
265
266
31
    if (type == SCOP_CMD_HELLO_RESP) {
267
2
        status = tvb_get_ntohs(tvb, 1);
268
2
        proto_tree_add_uint_format_value(tree, hf_scop_status, tvb, offset, 2, status, "%s", (status==0x0000)?"Success":"Failure");
269
2
        offset += 2;
270
2
    }
271
272
    /* If there are any bytes left over, pass them to the data dissector. */
273
31
    if (offset < tvb_reported_length(tvb)) {
274
28
        tvbuff_t    *payload_tvb = tvb_new_subset_remaining(tvb, offset);
275
28
        proto_tree  *root        = proto_tree_get_root(tree);
276
28
        call_data_dissector(payload_tvb, pinfo, root);
277
28
    }
278
31
} /* dissect_scop_zip() */
279
280
/*FUNCTION:------------------------------------------------------
281
 *  NAME
282
 *      dissect_scop_bridge
283
 *  DESCRIPTION
284
 *      Intermediate dissector for the Bridge service type.
285
 *  PARAMETERS
286
 *      tvbuff_t    *tvb    - pointer to buffer containing raw packet.
287
 *      packet_info *pinfo  - pointer to packet information fields
288
 *      proto_tree  *tree   - pointer to data tree Wireshark uses to display packet.
289
 *  RETURNS
290
 *      void
291
 *---------------------------------------------------------------
292
 */
293
static void
294
dissect_scop_bridge(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
295
9.80k
{
296
9.80k
    call_dissector(ieee802154_handle, tvb, pinfo, proto_tree_get_root(tree));
297
9.80k
} /* dissect_scop_bridge() */
298
299
/*FUNCTION:------------------------------------------------------
300
 *  NAME
301
 *      proto_register_scop
302
 *  DESCRIPTION
303
 *      SCoP protocol registration.
304
 *  PARAMETERS
305
 *      none
306
 *  RETURNS
307
 *      void
308
 *---------------------------------------------------------------
309
 */
310
void proto_register_scop(void)
311
16
{
312
16
    static hf_register_info hf[] = {
313
16
        { &hf_scop_transport,
314
16
        { "Transport Type",         "scop.transport", FT_UINT8, BASE_DEC, VALS(scop_transports), 0x0,
315
16
            "The type of transport used.", HFILL }},
316
317
16
        { &hf_scop_version,
318
16
        { "Version",                "scop.version", FT_UINT8, BASE_DEC, NULL, 0x0,
319
16
            "The version of the sniffer.", HFILL }},
320
321
16
        { &hf_scop_length,
322
16
        { "Length",                 "scop.length", FT_UINT16, BASE_DEC, NULL, 0x0,
323
16
            NULL, HFILL }},
324
325
16
        { &hf_scop_service,
326
16
        { "Service Identifier",     "scop.service", FT_UINT8, BASE_DEC, VALS(scop_services), 0x0,
327
16
            NULL, HFILL }},
328
329
16
        { &hf_scop_type,
330
16
        { "Packet Type",            "scop.type", FT_UINT8, BASE_DEC, VALS(scop_types), 0x0,
331
16
            "Service-specific packet type.", HFILL }},
332
333
16
        { &hf_scop_status,
334
16
        { "Status",                 "scop.status", FT_UINT16, BASE_HEX, NULL, 0x0,
335
16
            "Status of the SCoP Command.", HFILL }}
336
16
    };
337
338
16
    static int *ett[] = {
339
16
        &ett_scop
340
16
    };
341
342
    /*  Register protocol name and description. */
343
16
    proto_scop = proto_register_protocol("ZigBee SCoP", "SCoP", "scop");
344
345
    /*  Register header fields and subtrees. */
346
16
    proto_register_field_array(proto_scop, hf, array_length(hf));
347
16
    proto_register_subtree_array(ett, array_length(ett));
348
349
    /*  Register dissector with Wireshark. */
350
16
    scop_udp_handle = register_dissector("scop.udp", dissect_scop, proto_scop);
351
16
    scop_tcp_handle = register_dissector("scop.tcp", dissect_scop_tcp, proto_scop);
352
16
} /* proto_register_scop() */
353
354
/*FUNCTION:------------------------------------------------------
355
 *  NAME
356
 *      proto_reg_handoff_scop
357
 *  DESCRIPTION
358
 *      Registers the zigbee dissector with Wireshark.
359
 *      Will be called every time 'apply' is pressed in the preferences menu.
360
 *  PARAMETERS
361
 *      none
362
 *  RETURNS
363
 *      void
364
 *---------------------------------------------------------------
365
 */
366
void proto_reg_handoff_scop(void)
367
16
{
368
16
    ieee802154_handle   = find_dissector_add_dependency("wpan_nofcs", proto_scop);
369
370
16
    dissector_add_uint_range_with_preference("udp.port", SCOP_DEFAULT_PORT_RANGE, scop_udp_handle);
371
16
    dissector_add_uint_range_with_preference("tcp.port", SCOP_DEFAULT_PORT_RANGE, scop_tcp_handle);
372
16
}
373
374
/*
375
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
376
 *
377
 * Local variables:
378
 * c-basic-offset: 4
379
 * tab-width: 8
380
 * indent-tabs-mode: nil
381
 * End:
382
 *
383
 * vi: set shiftwidth=4 tabstop=8 expandtab:
384
 * :indentSize=4:tabSize=8:noTabs=true:
385
 */