Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-zep.c
Line
Count
Source
1
/* packet-zep.c
2
 * Dissector  routines for the ZigBee Encapsulation Protocol
3
 * By Owen Kirby <osk@exegin.com>
4
 * Copyright 2009 Exegin Technologies Limited
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 *------------------------------------------------------------
12
 *
13
 *      ZEP Packets must be received in the following format:
14
 *      |UDP Header|  ZEP Header |IEEE 802.15.4 Packet|
15
 *      | 8 bytes  | 16/32 bytes |    <= 127 bytes    |
16
 *------------------------------------------------------------
17
 *
18
 *      ZEP v1 Header will have the following format:
19
 *      |Preamble|Version|Channel ID|Device ID|CRC/LQI Mode|LQI Val|Reserved|Length|
20
 *      |2 bytes |1 byte |  1 byte  | 2 bytes |   1 byte   |1 byte |7 bytes |1 byte|
21
 *
22
 *      ZEP v2 Header will have the following format (if type=1/Data):
23
 *      |Preamble|Version| Type |Channel ID|Device ID|CRC/LQI Mode|LQI Val|NTP Timestamp|Sequence#|Reserved|Length|
24
 *      |2 bytes |1 byte |1 byte|  1 byte  | 2 bytes |   1 byte   |1 byte |   8 bytes   | 4 bytes |10 bytes|1 byte|
25
 *
26
 *      ZEP v2 Header will have the following format (if type=2/Ack):
27
 *      |Preamble|Version| Type |Sequence#|
28
 *      |2 bytes |1 byte |1 byte| 4 bytes |
29
 *------------------------------------------------------------
30
 */
31
32
#include "config.h"
33
34
35
#include <epan/packet.h>
36
#include <epan/tfs.h>
37
#include <epan/unit_strings.h>
38
#include <wsutil/array.h>
39
40
/*  Function declarations */
41
void proto_reg_handoff_zep(void);
42
void proto_register_zep(void);
43
44
15
#define ZEP_DEFAULT_PORT   17754
45
46
/*  ZEP Preamble Code */
47
1
#define ZEP_PREAMBLE        "EX"
48
49
/*  ZEP Header lengths. */
50
0
#define ZEP_V1_HEADER_LEN   16
51
0
#define ZEP_V2_HEADER_LEN   32
52
1
#define ZEP_V2_ACK_LEN      8
53
54
#define ZEP_V2_TYPE_DATA    1
55
0
#define ZEP_V2_TYPE_ACK     2
56
57
15
#define ZEP_LENGTH_MASK     0x7F
58
59
static const range_string type_rvals[] = {
60
    {0, 0, "Reserved"},
61
    {ZEP_V2_TYPE_DATA, ZEP_V2_TYPE_DATA, "Data"},
62
    {ZEP_V2_TYPE_ACK, ZEP_V2_TYPE_ACK, "Ack"},
63
    {3, 255, "Reserved"   },
64
    {0, 0, NULL}
65
};
66
67
68
static const true_false_string tfs_crc_lqi = { "CRC", "LQI" };
69
70
/*  Initialize protocol and registered fields. */
71
static int proto_zep;
72
static int hf_zep_version;
73
static int hf_zep_type;
74
static int hf_zep_channel_id;
75
static int hf_zep_device_id;
76
static int hf_zep_lqi_mode;
77
static int hf_zep_lqi;
78
static int hf_zep_timestamp;
79
static int hf_zep_seqno;
80
static int hf_zep_ieee_length;
81
static int hf_zep_protocol_id;
82
static int hf_zep_reserved_field;
83
84
/* Initialize protocol subtrees. */
85
static int ett_zep;
86
87
/*  Dissector handle */
88
static dissector_handle_t zep_handle;
89
90
/*  Subdissector handles */
91
static dissector_handle_t ieee802154_handle;
92
static dissector_handle_t ieee802154_cc24xx_handle;
93
94
/*FUNCTION:------------------------------------------------------
95
 *  NAME
96
 *      dissect_zep
97
 *  DESCRIPTION
98
 *      IEEE 802.15.4 packet dissection routine for Wireshark.
99
 *  PARAMETERS
100
 *      tvbuff_t *tvb       - pointer to buffer containing raw packet.
101
 *      packet_info *pinfo  - pointer to packet information fields
102
 *      proto_tree *tree    - pointer to data tree Wireshark uses to display packet.
103
 *  RETURNS
104
 *      void
105
 *---------------------------------------------------------------
106
 */
107
static int dissect_zep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
108
1
{
109
1
    tvbuff_t      *next_tvb;
110
1
    proto_item    *proto_root;
111
1
    proto_tree    *zep_tree;
112
1
    uint8_t       ieee_packet_len;
113
1
    uint8_t       zep_header_len;
114
1
    uint8_t       version;
115
1
    uint8_t       type;
116
1
    uint32_t      channel_id, seqno;
117
1
    bool          lqi_mode = false;
118
119
1
    dissector_handle_t  next_dissector;
120
121
1
    if (tvb_reported_length(tvb) < ZEP_V2_ACK_LEN)
122
0
        return 0;
123
124
    /*  Determine whether this is a Q51/IEEE 802.15.4 sniffer packet or not */
125
1
    if(tvb_strneql(tvb, 0, ZEP_PREAMBLE, 2) != 0) {
126
        /*  This is not a Q51/ZigBee sniffer packet */
127
1
        return 0;
128
1
    }
129
130
    /*  Extract the protocol version from the ZEP header. */
131
0
    version = tvb_get_uint8(tvb, 2);
132
0
    if (version == 1) {
133
        /* Type indicates a ZEP_v1 packet. */
134
135
0
        zep_header_len = ZEP_V1_HEADER_LEN;
136
0
        if (tvb_reported_length(tvb) < ZEP_V1_HEADER_LEN)
137
0
            return 0;
138
139
0
        type = 0;
140
0
        ieee_packet_len = (tvb_get_uint8(tvb, ZEP_V1_HEADER_LEN - 1) & ZEP_LENGTH_MASK);
141
0
    }
142
0
    else {
143
        /* At the time of writing, v2 is the latest version of ZEP, assuming
144
         * anything higher than v2 has identical format. */
145
146
0
        type = tvb_get_uint8(tvb, 3);
147
0
        if (type == ZEP_V2_TYPE_ACK) {
148
            /* ZEP Ack has only the seqno. */
149
0
            zep_header_len = ZEP_V2_ACK_LEN;
150
0
            ieee_packet_len = 0;
151
0
        }
152
0
        else {
153
            /* Although, only type 1 corresponds to data, if another value is present, assume it is dissected the same. */
154
0
            zep_header_len = ZEP_V2_HEADER_LEN;
155
0
            if (tvb_reported_length(tvb) < ZEP_V2_HEADER_LEN)
156
0
                return 0;
157
158
0
            ieee_packet_len = (tvb_get_uint8(tvb, ZEP_V2_HEADER_LEN - 1) & ZEP_LENGTH_MASK);
159
0
        }
160
0
    }
161
162
0
    if(ieee_packet_len < tvb_reported_length(tvb)-zep_header_len){
163
        /* Packet's length is mis-reported, abort dissection */
164
0
        return 0;
165
0
    }
166
167
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, (version==1)?"ZEP":"ZEPv2");
168
169
0
    proto_root = proto_tree_add_item(tree, proto_zep, tvb, 0, zep_header_len, ENC_NA);
170
0
    zep_tree = proto_item_add_subtree(proto_root, ett_zep);
171
172
0
    proto_tree_add_item(zep_tree, hf_zep_protocol_id, tvb, 0, 2, ENC_ASCII);
173
0
    proto_tree_add_uint(zep_tree, hf_zep_version, tvb, 2, 1, version);
174
175
0
    switch (version)
176
0
    {
177
0
    case 1:
178
0
        proto_tree_add_item_ret_uint(zep_tree, hf_zep_channel_id, tvb, 3, 1, ENC_NA, &channel_id);
179
0
        col_add_fstr(pinfo->cinfo, COL_INFO, "Encapsulated ZigBee Packet [Channel]=%u [Length]=%u", channel_id, ieee_packet_len);
180
0
        proto_item_append_text(proto_root, ", Channel: %u, Length: %u", channel_id, ieee_packet_len);
181
182
0
        proto_tree_add_item(zep_tree, hf_zep_device_id, tvb, 4, 2, ENC_BIG_ENDIAN);
183
0
        proto_tree_add_item_ret_boolean(zep_tree, hf_zep_lqi_mode, tvb, 6, 1, ENC_NA, &lqi_mode);
184
0
        if (lqi_mode != 0) {
185
0
            proto_tree_add_item(zep_tree, hf_zep_lqi, tvb, 7, 1, ENC_NA);
186
0
            proto_tree_add_item(zep_tree, hf_zep_reserved_field, tvb, 8, 8, ENC_NA);
187
0
        } else {
188
0
            proto_tree_add_item(zep_tree, hf_zep_reserved_field, tvb, 7, 9, ENC_NA);
189
190
0
        }
191
0
        proto_tree_add_item(zep_tree, hf_zep_ieee_length, tvb, ZEP_V1_HEADER_LEN - 1, 1, ENC_NA);
192
0
        break;
193
194
0
    case 2:
195
0
    default:
196
0
        proto_tree_add_uint(zep_tree, hf_zep_type, tvb, 3, 1, type);
197
0
        if (type == ZEP_V2_TYPE_ACK) {
198
0
            proto_tree_add_item_ret_uint(zep_tree, hf_zep_seqno, tvb, 4, 4, ENC_BIG_ENDIAN, &seqno);
199
0
            col_add_fstr(pinfo->cinfo, COL_INFO, "Ack, Sequence Number: %i", seqno);
200
0
            proto_item_append_text(proto_root, ", Ack");
201
0
        } else {
202
0
            proto_tree_add_item_ret_uint(zep_tree, hf_zep_channel_id, tvb, 4, 1, ENC_NA, &channel_id);
203
0
            col_add_fstr(pinfo->cinfo, COL_INFO, "Encapsulated ZigBee Packet [Channel]=%u [Length]=%u", channel_id, ieee_packet_len);
204
0
            proto_item_append_text(proto_root, ", Channel: %u, Length: %u", channel_id, ieee_packet_len);
205
0
            proto_tree_add_item(zep_tree, hf_zep_device_id, tvb, 5, 2, ENC_BIG_ENDIAN);
206
0
            proto_tree_add_item_ret_boolean(zep_tree, hf_zep_lqi_mode, tvb, 7, 1, ENC_NA, &lqi_mode);
207
0
            if (lqi_mode == 0) {
208
0
                proto_tree_add_item(zep_tree, hf_zep_lqi, tvb, 8, 1, ENC_NA);
209
0
            }
210
0
            proto_tree_add_item(zep_tree, hf_zep_timestamp, tvb, 9, 8, ENC_BIG_ENDIAN|ENC_TIME_NTP);
211
0
            proto_tree_add_item(zep_tree, hf_zep_seqno, tvb, 17, 4, ENC_BIG_ENDIAN);
212
0
            proto_tree_add_item(zep_tree, hf_zep_ieee_length, tvb, ZEP_V2_HEADER_LEN - 1, 1, ENC_NA);
213
0
        }
214
0
        break;
215
0
    }
216
217
    /* Determine which dissector to call next. */
218
0
    if (lqi_mode) {
219
        /* CRC present, use standard IEEE dissector.
220
         * XXX - 2-octet or 4-octet CRC?
221
         */
222
0
        next_dissector = ieee802154_handle;
223
0
    }
224
0
    else {
225
        /* ChipCon/TI CC24xx-compliant metadata present, CRC absent */
226
0
        next_dissector = ieee802154_cc24xx_handle;
227
0
    }
228
229
    /*  Call the appropriate IEEE 802.15.4 dissector */
230
0
    if (!((version>=2) && (type==ZEP_V2_TYPE_ACK))) {
231
0
        next_tvb = tvb_new_subset_length(tvb, zep_header_len, ieee_packet_len);
232
0
        if (next_dissector != NULL) {
233
0
            call_dissector(next_dissector, next_tvb, pinfo, tree);
234
0
        } else {
235
            /* IEEE 802.15.4 dissectors couldn't be found. */
236
0
            call_data_dissector(next_tvb, pinfo, tree);
237
0
        }
238
0
    }
239
0
    return tvb_captured_length(tvb);
240
0
} /* dissect_ieee802_15_4 */
241
242
/*FUNCTION:------------------------------------------------------
243
 *  NAME
244
 *      proto_register_zep
245
 *  DESCRIPTION
246
 *      IEEE 802.15.4 protocol registration routine.
247
 *  PARAMETERS
248
 *      none
249
 *  RETURNS
250
 *      void
251
 *---------------------------------------------------------------
252
 */
253
void proto_register_zep(void)
254
15
{
255
15
    static hf_register_info hf[] = {
256
15
        { &hf_zep_version,
257
15
        { "Protocol Version",           "zep.version", FT_UINT8, BASE_DEC, NULL, 0x0,
258
15
            "The version of the sniffer.", HFILL }},
259
260
15
        { &hf_zep_type,
261
15
        { "Type",                       "zep.type", FT_UINT8, BASE_DEC|BASE_RANGE_STRING, RVALS(type_rvals), 0x0,
262
15
            NULL, HFILL }},
263
264
15
        { &hf_zep_channel_id,
265
15
        { "Channel ID",                 "zep.channel_id", FT_UINT8, BASE_DEC, NULL, 0x0,
266
15
            "The logical channel on which this packet was detected.", HFILL }},
267
268
15
        { &hf_zep_device_id,
269
15
        { "Device ID",                  "zep.device_id", FT_UINT16, BASE_DEC, NULL, 0x0,
270
15
            "The ID of the device that detected this packet.", HFILL }},
271
272
15
        { &hf_zep_lqi_mode,
273
15
        { "LQI/CRC Mode",               "zep.lqi_mode", FT_BOOLEAN, BASE_NONE, TFS(&tfs_crc_lqi), 0x0,
274
15
            "Determines what format the last two bytes of the MAC frame use.", HFILL }},
275
276
15
        { &hf_zep_lqi,
277
15
        { "Link Quality Indication",    "zep.lqi", FT_UINT8, BASE_DEC, NULL, 0x0,
278
15
            NULL, HFILL }},
279
280
15
        { &hf_zep_timestamp,
281
15
        { "Timestamp",                  "zep.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0,
282
15
            NULL, HFILL }},
283
284
15
        { &hf_zep_seqno,
285
15
        { "Sequence Number",            "zep.seqno", FT_UINT32, BASE_DEC, NULL, 0x0,
286
15
            NULL, HFILL }},
287
288
15
        { &hf_zep_ieee_length,
289
15
        { "Length",              "zep.length", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), ZEP_LENGTH_MASK,
290
15
            "The length (in bytes) of the encapsulated IEEE 802.15.4 MAC frame.", HFILL }},
291
292
15
        { &hf_zep_protocol_id,
293
15
        { "Protocol ID String",            "zep.protocol_id", FT_STRING, BASE_NONE, NULL, 0x0,
294
15
            NULL, HFILL }},
295
296
15
        { &hf_zep_reserved_field,
297
15
        { "Reserved Fields",            "zep.reserved_field", FT_BYTES, BASE_NONE, NULL, 0x0,
298
15
            NULL, HFILL }},
299
15
    };
300
301
15
    static int *ett[] = {
302
15
        &ett_zep
303
15
    };
304
305
    /*  Register protocol name and description. */
306
15
    proto_zep = proto_register_protocol("ZigBee Encapsulation Protocol", "ZEP", "zep");
307
308
    /*  Register header fields and subtrees. */
309
15
    proto_register_field_array(proto_zep, hf, array_length(hf));
310
15
    proto_register_subtree_array(ett, array_length(ett));
311
312
    /*  Register dissector with Wireshark. */
313
15
    zep_handle = register_dissector("zep", dissect_zep, proto_zep);
314
15
} /* proto_register_zep */
315
316
/*FUNCTION:------------------------------------------------------
317
 *  NAME
318
 *      proto_reg_handoff_zep
319
 *  DESCRIPTION
320
 *      Registers the zigbee dissector with Wireshark.
321
 *      Will be called every time 'apply' is pressed in the preferences menu.
322
 *  PARAMETERS
323
 *      none
324
 *  RETURNS
325
 *      void
326
 *---------------------------------------------------------------
327
 */
328
void proto_reg_handoff_zep(void)
329
15
{
330
15
    dissector_handle_t h;
331
332
    /* Get dissector handles. */
333
15
    if ( !(h = find_dissector("wpan")) ) { /* Try use built-in 802.15.4 dissector */
334
0
        h = find_dissector("ieee802154");  /* otherwise use older 802.15.4 plugin dissector */
335
0
    }
336
15
    ieee802154_handle = h;
337
15
    if ( !(h = find_dissector("wpan_cc24xx")) ) { /* Try use built-in 802.15.4 (Chipcon) dissector */
338
0
        h = find_dissector("ieee802154_ccfcs");   /* otherwise use older 802.15.4 (Chipcon) plugin dissector */
339
0
    }
340
15
    ieee802154_cc24xx_handle = h;
341
342
15
    dissector_add_uint("udp.port", ZEP_DEFAULT_PORT, zep_handle);
343
15
} /* proto_reg_handoff_zep */
344
345
/*
346
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
347
 *
348
 * Local variables:
349
 * c-basic-offset: 4
350
 * tab-width: 8
351
 * indent-tabs-mode: nil
352
 * End:
353
 *
354
 * vi: set shiftwidth=4 tabstop=8 expandtab:
355
 * :indentSize=4:tabSize=8:noTabs=true:
356
 */