/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 | | */ |