2 * Dissector routines for the ZigBee Encapsulation Protocol
3 * By Owen Kirby <osk@exegin.com>
4 * Copyright 2009 Exegin Technologies Limited
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 *------------------------------------------------------------
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 *------------------------------------------------------------
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|
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|
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 *------------------------------------------------------------
35 #include <epan/packet.h>
37 #include <epan/unit_strings.h>
38 #include <wsutil/array.h>
40 /* Function declarations */
41 void proto_reg_handoff_zep(void);
42 void proto_register_zep(void);
44 #define ZEP_DEFAULT_PORT 17754
46 /* ZEP Preamble Code */
47 #define ZEP_PREAMBLE "EX"
49 /* ZEP Header lengths. */
50 #define ZEP_V1_HEADER_LEN 16
51 #define ZEP_V2_HEADER_LEN 32
52 #define ZEP_V2_ACK_LEN 8
54 #define ZEP_V2_TYPE_DATA 1
55 #define ZEP_V2_TYPE_ACK 2
57 #define ZEP_LENGTH_MASK 0x7F
59 static const range_string type_rvals
[] = {
61 {ZEP_V2_TYPE_DATA
, ZEP_V2_TYPE_DATA
, "Data"},
62 {ZEP_V2_TYPE_ACK
, ZEP_V2_TYPE_ACK
, "Ack"},
63 {3, 255, "Reserved" },
68 static const true_false_string tfs_crc_lqi
= { "CRC", "LQI" };
70 /* Initialize protocol and registered fields. */
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
;
84 /* Initialize protocol subtrees. */
87 /* Dissector handle */
88 static dissector_handle_t zep_handle
;
90 /* Subdissector handles */
91 static dissector_handle_t ieee802154_handle
;
92 static dissector_handle_t ieee802154_cc24xx_handle
;
94 /*FUNCTION:------------------------------------------------------
98 * IEEE 802.15.4 packet dissection routine for Wireshark.
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.
105 *---------------------------------------------------------------
107 static int dissect_zep(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
110 proto_item
*proto_root
;
111 proto_tree
*zep_tree
;
112 uint8_t ieee_packet_len
;
113 uint8_t zep_header_len
;
116 uint32_t channel_id
, seqno
;
117 bool lqi_mode
= false;
119 dissector_handle_t next_dissector
;
121 if (tvb_reported_length(tvb
) < ZEP_V2_ACK_LEN
)
124 /* Determine whether this is a Q51/IEEE 802.15.4 sniffer packet or not */
125 if(strcmp(tvb_get_string_enc(pinfo
->pool
, tvb
, 0, 2, ENC_ASCII
), ZEP_PREAMBLE
)){
126 /* This is not a Q51/ZigBee sniffer packet */
130 /* Extract the protocol version from the ZEP header. */
131 version
= tvb_get_uint8(tvb
, 2);
133 /* Type indicates a ZEP_v1 packet. */
135 zep_header_len
= ZEP_V1_HEADER_LEN
;
136 if (tvb_reported_length(tvb
) < ZEP_V1_HEADER_LEN
)
140 ieee_packet_len
= (tvb_get_uint8(tvb
, ZEP_V1_HEADER_LEN
- 1) & ZEP_LENGTH_MASK
);
143 /* At the time of writing, v2 is the latest version of ZEP, assuming
144 * anything higher than v2 has identical format. */
146 type
= tvb_get_uint8(tvb
, 3);
147 if (type
== ZEP_V2_TYPE_ACK
) {
148 /* ZEP Ack has only the seqno. */
149 zep_header_len
= ZEP_V2_ACK_LEN
;
153 /* Although, only type 1 corresponds to data, if another value is present, assume it is dissected the same. */
154 zep_header_len
= ZEP_V2_HEADER_LEN
;
155 if (tvb_reported_length(tvb
) < ZEP_V2_HEADER_LEN
)
158 ieee_packet_len
= (tvb_get_uint8(tvb
, ZEP_V2_HEADER_LEN
- 1) & ZEP_LENGTH_MASK
);
162 if(ieee_packet_len
< tvb_reported_length(tvb
)-zep_header_len
){
163 /* Packet's length is mis-reported, abort dissection */
167 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, (version
==1)?"ZEP":"ZEPv2");
169 proto_root
= proto_tree_add_item(tree
, proto_zep
, tvb
, 0, zep_header_len
, ENC_NA
);
170 zep_tree
= proto_item_add_subtree(proto_root
, ett_zep
);
172 proto_tree_add_item(zep_tree
, hf_zep_protocol_id
, tvb
, 0, 2, ENC_NA
|ENC_ASCII
);
173 proto_tree_add_uint(zep_tree
, hf_zep_version
, tvb
, 2, 1, version
);
178 proto_tree_add_item_ret_uint(zep_tree
, hf_zep_channel_id
, tvb
, 3, 1, ENC_NA
, &channel_id
);
179 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Encapsulated ZigBee Packet [Channel]=%u [Length]=%u", channel_id
, ieee_packet_len
);
180 proto_item_append_text(proto_root
, ", Channel: %u, Length: %u", channel_id
, ieee_packet_len
);
182 proto_tree_add_item(zep_tree
, hf_zep_device_id
, tvb
, 4, 2, ENC_BIG_ENDIAN
);
183 proto_tree_add_item_ret_boolean(zep_tree
, hf_zep_lqi_mode
, tvb
, 6, 1, ENC_NA
, &lqi_mode
);
185 proto_tree_add_item(zep_tree
, hf_zep_lqi
, tvb
, 7, 1, ENC_NA
);
186 proto_tree_add_item(zep_tree
, hf_zep_reserved_field
, tvb
, 8, 8, ENC_NA
);
188 proto_tree_add_item(zep_tree
, hf_zep_reserved_field
, tvb
, 7, 9, ENC_NA
);
191 proto_tree_add_item(zep_tree
, hf_zep_ieee_length
, tvb
, ZEP_V1_HEADER_LEN
- 1, 1, ENC_NA
);
196 proto_tree_add_uint(zep_tree
, hf_zep_type
, tvb
, 3, 1, type
);
197 if (type
== ZEP_V2_TYPE_ACK
) {
198 proto_tree_add_item_ret_uint(zep_tree
, hf_zep_seqno
, tvb
, 4, 4, ENC_BIG_ENDIAN
, &seqno
);
199 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Ack, Sequence Number: %i", seqno
);
200 proto_item_append_text(proto_root
, ", Ack");
202 proto_tree_add_item_ret_uint(zep_tree
, hf_zep_channel_id
, tvb
, 4, 1, ENC_NA
, &channel_id
);
203 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Encapsulated ZigBee Packet [Channel]=%u [Length]=%u", channel_id
, ieee_packet_len
);
204 proto_item_append_text(proto_root
, ", Channel: %u, Length: %u", channel_id
, ieee_packet_len
);
205 proto_tree_add_item(zep_tree
, hf_zep_device_id
, tvb
, 5, 2, ENC_BIG_ENDIAN
);
206 proto_tree_add_item_ret_boolean(zep_tree
, hf_zep_lqi_mode
, tvb
, 7, 1, ENC_NA
, &lqi_mode
);
208 proto_tree_add_item(zep_tree
, hf_zep_lqi
, tvb
, 8, 1, ENC_NA
);
210 proto_tree_add_item(zep_tree
, hf_zep_timestamp
, tvb
, 9, 8, ENC_BIG_ENDIAN
|ENC_TIME_NTP
);
211 proto_tree_add_item(zep_tree
, hf_zep_seqno
, tvb
, 17, 4, ENC_BIG_ENDIAN
);
212 proto_tree_add_item(zep_tree
, hf_zep_ieee_length
, tvb
, ZEP_V2_HEADER_LEN
- 1, 1, ENC_NA
);
217 /* Determine which dissector to call next. */
219 /* CRC present, use standard IEEE dissector.
220 * XXX - 2-octet or 4-octet CRC?
222 next_dissector
= ieee802154_handle
;
225 /* ChipCon/TI CC24xx-compliant metadata present, CRC absent */
226 next_dissector
= ieee802154_cc24xx_handle
;
229 /* Call the appropriate IEEE 802.15.4 dissector */
230 if (!((version
>=2) && (type
==ZEP_V2_TYPE_ACK
))) {
231 next_tvb
= tvb_new_subset_length(tvb
, zep_header_len
, ieee_packet_len
);
232 if (next_dissector
!= NULL
) {
233 call_dissector(next_dissector
, next_tvb
, pinfo
, tree
);
235 /* IEEE 802.15.4 dissectors couldn't be found. */
236 call_data_dissector(next_tvb
, pinfo
, tree
);
239 return tvb_captured_length(tvb
);
240 } /* dissect_ieee802_15_4 */
242 /*FUNCTION:------------------------------------------------------
246 * IEEE 802.15.4 protocol registration routine.
251 *---------------------------------------------------------------
253 void proto_register_zep(void)
255 static hf_register_info hf
[] = {
257 { "Protocol Version", "zep.version", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
258 "The version of the sniffer.", HFILL
}},
261 { "Type", "zep.type", FT_UINT8
, BASE_DEC
|BASE_RANGE_STRING
, RVALS(type_rvals
), 0x0,
264 { &hf_zep_channel_id
,
265 { "Channel ID", "zep.channel_id", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
266 "The logical channel on which this packet was detected.", HFILL
}},
269 { "Device ID", "zep.device_id", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
270 "The ID of the device that detected this packet.", HFILL
}},
273 { "LQI/CRC Mode", "zep.lqi_mode", FT_BOOLEAN
, BASE_NONE
, TFS(&tfs_crc_lqi
), 0x0,
274 "Determines what format the last two bytes of the MAC frame use.", HFILL
}},
277 { "Link Quality Indication", "zep.lqi", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
281 { "Timestamp", "zep.time", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x0,
285 { "Sequence Number", "zep.seqno", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
288 { &hf_zep_ieee_length
,
289 { "Length", "zep.length", FT_UINT8
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_byte_bytes
), ZEP_LENGTH_MASK
,
290 "The length (in bytes) of the encapsulated IEEE 802.15.4 MAC frame.", HFILL
}},
292 { &hf_zep_protocol_id
,
293 { "Protocol ID String", "zep.protocol_id", FT_STRING
, BASE_NONE
, NULL
, 0x0,
296 { &hf_zep_reserved_field
,
297 { "Reserved Fields", "zep.reserved_field", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
301 static int *ett
[] = {
305 /* Register protocol name and description. */
306 proto_zep
= proto_register_protocol("ZigBee Encapsulation Protocol", "ZEP", "zep");
308 /* Register header fields and subtrees. */
309 proto_register_field_array(proto_zep
, hf
, array_length(hf
));
310 proto_register_subtree_array(ett
, array_length(ett
));
312 /* Register dissector with Wireshark. */
313 zep_handle
= register_dissector("zep", dissect_zep
, proto_zep
);
314 } /* proto_register_zep */
316 /*FUNCTION:------------------------------------------------------
318 * proto_reg_handoff_zep
320 * Registers the zigbee dissector with Wireshark.
321 * Will be called every time 'apply' is pressed in the preferences menu.
326 *---------------------------------------------------------------
328 void proto_reg_handoff_zep(void)
330 dissector_handle_t h
;
332 /* Get dissector handles. */
333 if ( !(h
= find_dissector("wpan")) ) { /* Try use built-in 802.15.4 dissector */
334 h
= find_dissector("ieee802154"); /* otherwise use older 802.15.4 plugin dissector */
336 ieee802154_handle
= h
;
337 if ( !(h
= find_dissector("wpan_cc24xx")) ) { /* Try use built-in 802.15.4 (Chipcon) dissector */
338 h
= find_dissector("ieee802154_ccfcs"); /* otherwise use older 802.15.4 (Chipcon) plugin dissector */
340 ieee802154_cc24xx_handle
= h
;
342 dissector_add_uint("udp.port", ZEP_DEFAULT_PORT
, zep_handle
);
343 } /* proto_reg_handoff_zep */
346 * Editor modelines - https://www.wireshark.org/tools/modelines.html
351 * indent-tabs-mode: nil
354 * vi: set shiftwidth=4 tabstop=8 expandtab:
355 * :indentSize=4:tabSize=8:noTabs=true: