HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-ieee802154.c
blob0c74371cc3ce58124c5788f0adfc60aa456e0717
1 /* packet-ieee802154.c
3 * $Id$
5 * Auxiliary Security Header support and
6 * option to force TI CC24xx FCS format
7 * By Jean-Francois Wauthy <jfw@info.fundp.ac.be>
8 * Copyright 2009 The University of Namur, Belgium
10 * IEEE 802.15.4 Dissectors for Wireshark
11 * By Owen Kirby <osk@exegin.com>
12 * Copyright 2007 Exegin Technologies Limited
14 * Wireshark - Network traffic analyzer
15 * By Gerald Combs <gerald@wireshark.org>
16 * Copyright 1998 Gerald Combs
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 *------------------------------------------------------------
33 * In IEEE 802.15.4 packets, all fields are little endian. And
34 * Each byte is transmitted least significant bit first (reflected
35 * bit ordering).
36 *------------------------------------------------------------
38 * IEEE 802.15.4 Packets have the following format:
39 * | FCF |Seq No| Addressing | Data | FCS |
40 * |2 bytes|1 byte|0 to 20 bytes|Length-(Overhead) bytes|2 Bytes|
41 *------------------------------------------------------------
43 * CRC16 is calculated using the x^16 + x^12 + x^5 + 1 polynomial
44 * as specified by ITU-T, and is calculated over the IEEE 802.15.4
45 * packet (excluding the FCS) as transmitted over the air. Note,
46 * that because the least significan bits are transmitted first, this
47 * will require reversing the bit-order in each byte. Also, unlike
48 * most CRC algorithms, IEEE 802.15.4 uses an initial and final value
49 * of 0x0000, instead of 0xffff (which is used by the CCITT).
50 *------------------------------------------------------------
52 * This dissector supports both link-layer IEEE 802.15.4 captures
53 * and IEEE 802.15.4 packets encapsulated within other layers.
54 * Additionally, support has been provided for various formats
55 * of the frame check sequence:
56 * - IEEE 802.15.4 compliant FCS.
57 * - ChipCon/Texas Instruments CC24xx style FCS.
58 *------------------------------------------------------------
61 /* Include files */
62 #include "config.h"
64 #include <string.h>
66 #include <sys/stat.h>
68 #include <glib.h>
70 #include <epan/wmem/wmem.h>
71 #include <epan/packet.h>
72 #include <epan/exceptions.h>
73 #include <wsutil/pint.h>
74 #include <epan/crc16-tvb.h>
75 #include <epan/expert.h>
76 #include <epan/addr_resolv.h>
77 #include <epan/prefs.h>
78 #include <epan/uat.h>
79 #include <epan/strutil.h>
80 #include <epan/show_exception.h>
82 /* Use libgcrypt for cipher libraries. */
83 #ifdef HAVE_LIBGCRYPT
84 #include <wsutil/wsgcrypt.h>
85 #endif /* HAVE_LIBGCRYPT */
87 #include "packet-ieee802154.h"
88 #include "packet-sll.h"
90 /* Dissection Options for dissect_ieee802154_common */
91 #define DISSECT_IEEE802154_OPTION_CC24xx 0x00000001 /* FCS field contains a TI CC24xx style FCS. */
92 #define DISSECT_IEEE802154_OPTION_LINUX 0x00000002 /* Addressing fields are padded DLT_IEEE802_15_4_LINUX, not implemented. */
94 /* ethertype for 802.15.4 tag - encapsulating an Ethernet packet */
95 static unsigned int ieee802154_ethertype = 0x809A;
97 /* boolean value set if the FCS field is using the TI CC24xx format */
98 static gboolean ieee802154_cc24xx = FALSE;
100 /* boolean value set if the FCS must be ok before payload is dissected */
101 static gboolean ieee802154_fcs_ok = TRUE;
103 /* User string with the decryption key. */
104 static const gchar *ieee802154_key_str = NULL;
105 static gboolean ieee802154_key_valid;
106 static guint8 ieee802154_key[IEEE802154_CIPHER_SIZE];
107 static const char *ieee802154_user = "User";
109 /*-------------------------------------
110 * Address Hash Tables
111 *-------------------------------------
113 static ieee802154_map_tab_t ieee802154_map = { NULL, NULL };
115 /*-------------------------------------
116 * Static Address Mapping UAT
117 *-------------------------------------
119 /* UAT entry structure. */
120 typedef struct {
121 guchar *eui64;
122 guint eui64_len;
123 guint addr16;
124 guint pan;
125 } static_addr_t;
127 /* UAT variables */
128 static uat_t *static_addr_uat = NULL;
129 static static_addr_t *static_addrs = NULL;
130 static guint num_static_addrs = 0;
132 /* Sanity-checks a UAT record. */
133 static void
134 addr_uat_update_cb(void *r, const char **err)
136 static_addr_t *map = (static_addr_t *)r;
137 /* Ensure a valid short address */
138 if (map->addr16 >= IEEE802154_NO_ADDR16) {
139 *err = g_strdup("Invalid short address");
140 return;
142 /* Ensure a valid PAN identifier. */
143 if (map->pan >= IEEE802154_BCAST_PAN) {
144 *err = g_strdup("Invalid PAN identifier");
145 return;
147 /* Ensure a valid EUI-64 length */
148 if (map->eui64_len != sizeof(guint64)) {
149 *err = g_strdup("Invalid EUI-64 length");
150 return;
152 } /* ieee802154_addr_uat_update_cb */
154 /* Field callbacks. */
155 UAT_HEX_CB_DEF(addr_uat, addr16, static_addr_t)
156 UAT_HEX_CB_DEF(addr_uat, pan, static_addr_t)
157 UAT_BUFFER_CB_DEF(addr_uat, eui64, static_addr_t, eui64, eui64_len)
159 /*-------------------------------------
160 * Dissector Function Prototypes
161 *-------------------------------------
163 /* Register Functions. Loads the dissector into Wireshark. */
164 void proto_reg_handoff_ieee802154 (void);
166 /* Dissection Routines. */
167 static void dissect_ieee802154_nonask_phy (tvbuff_t *, packet_info *, proto_tree *);
168 static void dissect_ieee802154 (tvbuff_t *, packet_info *, proto_tree *);
169 static void dissect_ieee802154_nofcs (tvbuff_t *, packet_info *, proto_tree *);
170 static void dissect_ieee802154_cc24xx (tvbuff_t *, packet_info *, proto_tree *);
171 /*static void dissect_ieee802154_linux (tvbuff_t *, packet_info *, proto_tree *); TODO: Implement Me. */
172 static void dissect_ieee802154_common (tvbuff_t *, packet_info *, proto_tree *, guint);
174 /* Sub-dissector helpers. */
175 static void dissect_ieee802154_fcf (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
176 static void dissect_ieee802154_superframe (tvbuff_t *, packet_info *, proto_tree *, guint *);
177 static void dissect_ieee802154_gtsinfo (tvbuff_t *, packet_info *, proto_tree *, guint *);
178 static void dissect_ieee802154_pendaddr (tvbuff_t *, packet_info *, proto_tree *, guint *);
179 static void dissect_ieee802154_assoc_req (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
180 static void dissect_ieee802154_assoc_rsp (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
181 static void dissect_ieee802154_disassoc (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
182 static void dissect_ieee802154_realign (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
183 static void dissect_ieee802154_gtsreq (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
185 /* Decryption helpers. */
186 typedef enum {
187 DECRYPT_PACKET_SUCCEEDED,
188 DECRYPT_NOT_ENCRYPTED,
189 DECRYPT_VERSION_UNSUPPORTED,
190 DECRYPT_PACKET_TOO_SMALL,
191 DECRYPT_PACKET_NO_EXT_SRC_ADDR,
192 DECRYPT_PACKET_NO_KEY,
193 DECRYPT_PACKET_DECRYPT_FAILED,
194 DECRYPT_PACKET_MIC_CHECK_FAILED
195 } ws_decrypt_status;
197 static tvbuff_t * dissect_ieee802154_decrypt(tvbuff_t *, guint, packet_info *, ieee802154_packet *,
198 ws_decrypt_status *);
199 static void ccm_init_block (gchar *, gboolean, gint, guint64, ieee802154_packet *, gint);
200 static gboolean ccm_ctr_encrypt (const gchar *, const gchar *, gchar *, gchar *, gint);
201 static gboolean ccm_cbc_mac (const gchar *, const gchar *, const gchar *, gint, const gchar *, gint, gchar *);
203 /* Initialize Protocol and Registered fields */
204 static int proto_ieee802154_nonask_phy = -1;
205 static int hf_ieee802154_nonask_phy_preamble = -1;
206 static int hf_ieee802154_nonask_phy_sfd = -1;
207 static int hf_ieee802154_nonask_phy_length = -1;
209 static int proto_ieee802154 = -1;
210 static int hf_ieee802154_frame_length = -1;
211 static int hf_ieee802154_frame_type = -1;
212 static int hf_ieee802154_security = -1;
213 static int hf_ieee802154_pending = -1;
214 static int hf_ieee802154_ack_request = -1;
215 static int hf_ieee802154_intra_pan = -1;
216 static int hf_ieee802154_seqno = -1;
217 static int hf_ieee802154_src_addr_mode = -1;
218 static int hf_ieee802154_dst_addr_mode = -1;
219 static int hf_ieee802154_version = -1;
220 static int hf_ieee802154_dst_panID = -1;
221 static int hf_ieee802154_dst16 = -1;
222 static int hf_ieee802154_dst64 = -1;
223 static int hf_ieee802154_src_panID = -1;
224 static int hf_ieee802154_src16 = -1;
225 static int hf_ieee802154_src64 = -1;
226 static int hf_ieee802154_src64_origin = -1;
227 static int hf_ieee802154_fcs = -1;
228 static int hf_ieee802154_rssi = -1;
229 static int hf_ieee802154_fcs_ok = -1;
230 static int hf_ieee802154_correlation = -1;
232 /* Registered fields for Command Packets */
233 static int hf_ieee802154_cmd_id = -1;
234 static int hf_ieee802154_cinfo_alt_coord = -1;
235 static int hf_ieee802154_cinfo_device_type = -1;
236 static int hf_ieee802154_cinfo_power_src = -1;
237 static int hf_ieee802154_cinfo_idle_rx = -1;
238 static int hf_ieee802154_cinfo_sec_capable = -1;
239 static int hf_ieee802154_cinfo_alloc_addr = -1;
240 static int hf_ieee802154_assoc_addr = -1;
241 static int hf_ieee802154_assoc_status = -1;
242 static int hf_ieee802154_disassoc_reason = -1;
243 static int hf_ieee802154_realign_pan = -1;
244 static int hf_ieee802154_realign_caddr = -1;
245 static int hf_ieee802154_realign_channel = -1;
246 static int hf_ieee802154_realign_addr = -1;
247 static int hf_ieee802154_realign_channel_page = -1;
248 static int hf_ieee802154_gtsreq_len = -1;
249 static int hf_ieee802154_gtsreq_dir = -1;
250 static int hf_ieee802154_gtsreq_type = -1;
252 /* Registered fields for Beacon Packets */
253 static int hf_ieee802154_beacon_order = -1;
254 static int hf_ieee802154_superframe_order = -1;
255 static int hf_ieee802154_cap = -1;
256 static int hf_ieee802154_superframe_battery_ext = -1;
257 static int hf_ieee802154_superframe_coord = -1;
258 static int hf_ieee802154_assoc_permit = -1;
259 static int hf_ieee802154_gts_count = -1;
260 static int hf_ieee802154_gts_permit = -1;
261 static int hf_ieee802154_gts_direction = -1;
262 static int hf_ieee802154_pending16 = -1;
263 static int hf_ieee802154_pending64 = -1;
265 /* Registered fields for Auxiliary Security Header */
266 static int hf_ieee802154_security_level = -1;
267 static int hf_ieee802154_key_id_mode = -1;
268 static int hf_ieee802154_aux_sec_reserved = -1;
269 static int hf_ieee802154_aux_sec_frame_counter = -1;
270 static int hf_ieee802154_aux_sec_key_source = -1;
271 static int hf_ieee802154_aux_sec_key_index = -1;
273 /* 802.15.4-2003 security */
274 static int hf_ieee802154_sec_frame_counter = -1;
275 static int hf_ieee802154_sec_key_sequence_counter = -1;
277 /* Initialize Subtree Pointers */
278 static gint ett_ieee802154_nonask_phy = -1;
279 static gint ett_ieee802154_nonask_phy_phr = -1;
280 static gint ett_ieee802154 = -1;
281 static gint ett_ieee802154_fcf = -1;
282 static gint ett_ieee802154_auxiliary_security = -1;
283 static gint ett_ieee802154_aux_sec_control = -1;
284 static gint ett_ieee802154_aux_sec_key_id = -1;
285 static gint ett_ieee802154_fcs = -1;
286 static gint ett_ieee802154_cmd = -1;
287 static gint ett_ieee802154_superframe = -1;
288 static gint ett_ieee802154_gts = -1;
289 static gint ett_ieee802154_gts_direction = -1;
290 static gint ett_ieee802154_gts_descriptors = -1;
291 static gint ett_ieee802154_pendaddr = -1;
293 static expert_field ei_ieee802154_invalid_addressing = EI_INIT;
294 static expert_field ei_ieee802154_fcs = EI_INIT;
295 static expert_field ei_ieee802154_decrypt_error = EI_INIT;
296 static expert_field ei_ieee802154_dst = EI_INIT;
297 static expert_field ei_ieee802154_src = EI_INIT;
299 /* Dissector handles */
300 static dissector_handle_t data_handle;
301 static heur_dissector_list_t ieee802154_heur_subdissector_list;
303 /* Name Strings */
304 static const value_string ieee802154_frame_types[] = {
305 { IEEE802154_FCF_BEACON, "Beacon" },
306 { IEEE802154_FCF_DATA, "Data" },
307 { IEEE802154_FCF_ACK, "Ack" },
308 { IEEE802154_FCF_CMD, "Command" },
309 { 0, NULL }
312 static const value_string ieee802154_addr_modes[] = {
313 { IEEE802154_FCF_ADDR_NONE, "None" },
314 { IEEE802154_FCF_ADDR_SHORT,"Short/16-bit" },
315 { IEEE802154_FCF_ADDR_EXT, "Long/64-bit" },
316 { 0, NULL }
319 static const value_string ieee802154_cmd_names[] = {
320 { IEEE802154_CMD_ASRQ, "Association Request" },
321 { IEEE802154_CMD_ASRSP, "Association Response" },
322 { IEEE802154_CMD_DISAS, "Disassociation Notification" },
323 { IEEE802154_CMD_DATA_RQ, "Data Request" },
324 { IEEE802154_CMD_PANID_ERR, "PAN ID Conflict" },
325 { IEEE802154_CMD_ORPH_NOTIF,"Orphan Notification" },
326 { IEEE802154_CMD_BCN_RQ, "Beacon Request" },
327 { IEEE802154_CMD_COORD_REAL,"Coordinator Realignment" },
328 { IEEE802154_CMD_GTS_REQ, "GTS Request" },
329 { 0, NULL }
332 static const value_string ieee802154_sec_level_names[] = {
333 { SECURITY_LEVEL_NONE, "No Security" },
334 { SECURITY_LEVEL_MIC_32, "32-bit Message Integrity Code" },
335 { SECURITY_LEVEL_MIC_64, "64-bit Message Integrity Code" },
336 { SECURITY_LEVEL_MIC_128, "128-bit Message Integrity Code" },
337 { SECURITY_LEVEL_ENC, "Encryption" },
338 { SECURITY_LEVEL_ENC_MIC_32, "Encryption with 32-bit Message Integrity Code" },
339 { SECURITY_LEVEL_ENC_MIC_64, "Encryption with 64-bit Message Integrity Code" },
340 { SECURITY_LEVEL_ENC_MIC_128, "Encryption with 128-bit Message Integrity Code" },
341 { 0, NULL }
344 static const value_string ieee802154_key_id_mode_names[] = {
345 { KEY_ID_MODE_IMPLICIT, "Implicit Key" },
346 { KEY_ID_MODE_KEY_INDEX, "Indexed Key using the Default Key Source" },
347 { KEY_ID_MODE_KEY_EXPLICIT_4, "Explicit Key with 4-octet Key Source" },
348 { KEY_ID_MODE_KEY_EXPLICIT_8, "Explicit Key with 8-octet Key Source" },
349 { 0, NULL }
352 static const true_false_string ieee802154_gts_direction_tfs = {
353 "Receive Only",
354 "Transmit Only"
357 /* The 802.15.4-2003 security suites for the security preferences (only AES-CCM suites are supported). */
358 /* NOTE: The equivalent 2006 security level identifer enumerations are used to simplify 2003 & 2006 integration! */
359 static const enum_val_t ieee802154_2003_sec_suite_enums[] = {
360 { "AES-CCM-128", "AES-128 Encryption, 128-bit Integrity Protection", SECURITY_LEVEL_ENC_MIC_128 },
361 { "AES-CCM-64", "AES-128 Encryption, 64-bit Integrity Protection", SECURITY_LEVEL_ENC_MIC_64 },
362 { "AES-CCM-32", "AES-128 Encryption, 32-bit Integrity Protection", SECURITY_LEVEL_ENC_MIC_32 },
363 { NULL, NULL, 0 }
366 /* Preferences for 2003 security */
367 static gint ieee802154_sec_suite = SECURITY_LEVEL_ENC_MIC_64;
368 static gboolean ieee802154_extend_auth = TRUE;
370 /* Macro to check addressing, and throw a warning flag if incorrect. */
371 #define IEEE802154_CMD_ADDR_CHECK(_pinfo_, _item_, _cmdid_, _x_) \
372 if (!(_x_)) \
373 expert_add_info_format(_pinfo_, _item_, &ei_ieee802154_invalid_addressing, \
374 "Invalid Addressing for %s", \
375 val_to_str_const(_cmdid_, ieee802154_cmd_names, "Unknown Command"))
377 /* CRC definitions. IEEE 802.15.4 CRCs vary from CCITT by using an initial value of
378 * 0x0000, and no XOR out. IEEE802154_CRC_XOR is defined as 0xFFFF in order to un-XOR
379 * the output from the CCITT CRC routines in Wireshark.
381 #define IEEE802154_CRC_SEED 0x0000
382 #define IEEE802154_CRC_XOROUT 0xFFFF
383 #define ieee802154_crc_tvb(tvb, offset) (crc16_ccitt_tvb_seed(tvb, offset, IEEE802154_CRC_SEED) ^ IEEE802154_CRC_XOROUT)
386 /*FUNCTION:------------------------------------------------------
387 * NAME
388 * dissect_ieee802154_fcf
389 * DESCRIPTION
390 * Dissector helper, parses and displays the frame control
391 * field.
393 * PARAMETERS
394 * ieee802154_packet *packet - Packet info structure.
395 * tvbuff_t *tvb - pointer to buffer containing raw packet.
396 * packet_info *pinfo - pointer to packet information fields
397 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
398 * ieee802154_packet *packet - IEEE 802.15.4 packet information.
399 * guint offset - offset into the tvb to find the FCF.
400 * RETURNS
401 * void
402 *---------------------------------------------------------------
404 static void
405 dissect_ieee802154_fcf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet, guint *offset)
407 guint16 fcf;
408 proto_tree *field_tree;
409 proto_item *ti;
411 /* Get the FCF field. */
412 fcf = tvb_get_letohs(tvb, *offset);
414 /* Parse FCF Flags. */
415 packet->frame_type = fcf & IEEE802154_FCF_TYPE_MASK;
416 packet->security_enable = fcf & IEEE802154_FCF_SEC_EN;
417 packet->frame_pending = fcf & IEEE802154_FCF_FRAME_PND;
418 packet->ack_request = fcf & IEEE802154_FCF_ACK_REQ;
419 packet->intra_pan = fcf & IEEE802154_FCF_INTRA_PAN;
420 packet->version = (fcf & IEEE802154_FCF_VERSION) >> 12;
421 packet->dst_addr_mode = (fcf & IEEE802154_FCF_DADDR_MASK) >> 10;
422 packet->src_addr_mode = (fcf & IEEE802154_FCF_SADDR_MASK) >> 14;
424 /* Display the frame type. */
425 proto_item_append_text(tree, " %s", val_to_str_const(packet->frame_type, ieee802154_frame_types, "Reserved"));
426 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet->frame_type, ieee802154_frame_types, "Reserved"));
428 /* Add the FCF to the protocol tree. */
429 if (tree) {
430 /* Create the FCF subtree. */
431 ti = proto_tree_add_text(tree, tvb, *offset, 2, "Frame Control Field: %s (0x%04x)",
432 val_to_str_const(packet->frame_type, ieee802154_frame_types, "Unknown"), fcf);
433 field_tree = proto_item_add_subtree(ti, ett_ieee802154_fcf);
435 /* FCF Fields. */
436 proto_tree_add_uint(field_tree, hf_ieee802154_frame_type, tvb, *offset, 1, fcf & IEEE802154_FCF_TYPE_MASK);
437 proto_tree_add_boolean(field_tree, hf_ieee802154_security, tvb, *offset, 1, fcf & IEEE802154_FCF_SEC_EN);
438 proto_tree_add_boolean(field_tree, hf_ieee802154_pending, tvb, *offset, 1, fcf & IEEE802154_FCF_FRAME_PND);
439 proto_tree_add_boolean(field_tree, hf_ieee802154_ack_request, tvb, *offset, 1, fcf & IEEE802154_FCF_ACK_REQ);
440 proto_tree_add_boolean(field_tree, hf_ieee802154_intra_pan, tvb, *offset, 1, fcf & IEEE802154_FCF_INTRA_PAN);
441 proto_tree_add_uint(field_tree, hf_ieee802154_dst_addr_mode, tvb, (*offset)+1, 1, fcf & IEEE802154_FCF_DADDR_MASK);
442 proto_tree_add_uint(field_tree, hf_ieee802154_version, tvb, (*offset)+1, 1, fcf & IEEE802154_FCF_VERSION);
443 proto_tree_add_uint(field_tree, hf_ieee802154_src_addr_mode, tvb, (*offset)+1, 1, fcf & IEEE802154_FCF_SADDR_MASK);
446 *offset += 2;
447 } /* dissect_ieee802154_fcf */
449 /*FUNCTION:------------------------------------------------------
450 * NAME
451 * dissect_ieee802154_nonask_phy
452 * DESCRIPTION
453 * Dissector for IEEE 802.15.4 non-ASK PHY packet with an FCS containing
454 * a 16-bit CRC value.
456 * PARAMETERS
457 * tvbuff_t *tvb - pointer to buffer containing raw packet.
458 * packet_info *pinfo - pointer to packet information fields
459 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
460 * RETURNS
461 * void
462 *---------------------------------------------------------------
464 static void
465 dissect_ieee802154_nonask_phy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
467 proto_tree *ieee802154_tree = NULL;
468 proto_item *proto_root = NULL;
470 guint offset = 0;
471 guint32 preamble;
472 guint8 sfd,phr;
473 tvbuff_t* mac;
475 /* Create the protocol tree. */
476 if (tree) {
477 proto_root = proto_tree_add_protocol_format(tree, proto_ieee802154_nonask_phy, tvb, 0, tvb_length(tvb), "IEEE 802.15.4 non-ASK PHY");
478 ieee802154_tree = proto_item_add_subtree(proto_root, ett_ieee802154_nonask_phy);
481 /* Add the protocol name. */
482 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEEE 802.15.4 non-ASK PHY");
483 /* Add the packet length. */
484 col_add_fstr(pinfo->cinfo, COL_PACKET_LENGTH, "%i", tvb_length(tvb));
486 preamble=tvb_get_letohl(tvb,offset);
487 sfd=tvb_get_guint8(tvb,offset+4);
488 phr=tvb_get_guint8(tvb,offset+4+1);
490 if(tree) {
491 proto_tree *phr_tree;
492 proto_item *pi;
493 guint loffset=offset;
495 proto_tree_add_uint(ieee802154_tree, hf_ieee802154_nonask_phy_preamble, tvb, loffset, 4, preamble);
496 loffset+=4;
497 proto_tree_add_uint(ieee802154_tree, hf_ieee802154_nonask_phy_sfd, tvb, loffset, 1, sfd);
498 loffset+=1;
500 pi = proto_tree_add_text(ieee802154_tree, tvb, loffset, 1, "PHR: 0x%02x", phr);
501 phr_tree = proto_item_add_subtree(pi, ett_ieee802154_nonask_phy_phr);
503 proto_tree_add_uint(phr_tree, hf_ieee802154_nonask_phy_length, tvb, loffset, 1, phr);
506 offset+=4+2*1;
507 mac=tvb_new_subset(tvb,offset,-1, phr & IEEE802154_PHY_LENGTH_MASK);
509 /* Call the common dissector. */
510 dissect_ieee802154(mac, pinfo, ieee802154_tree);
511 } /* dissect_ieee802154_nonask_phy */
513 /*FUNCTION:------------------------------------------------------
514 * NAME
515 * dissect_ieee802154
516 * DESCRIPTION
517 * Dissector for IEEE 802.15.4 packet with an FCS containing
518 * a 16-bit CRC value.
520 * PARAMETERS
521 * tvbuff_t *tvb - pointer to buffer containing raw packet.
522 * packet_info *pinfo - pointer to packet information fields
523 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
524 * RETURNS
525 * void
526 *---------------------------------------------------------------
528 static void
529 dissect_ieee802154(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
531 /* Call the common dissector. */
532 dissect_ieee802154_common(tvb, pinfo, tree, (ieee802154_cc24xx ? DISSECT_IEEE802154_OPTION_CC24xx : 0));
533 } /* dissect_ieee802154 */
535 /*FUNCTION:------------------------------------------------------
536 * NAME
537 * dissect_ieee802154_nofcs
538 * DESCRIPTION
539 * Dissector for IEEE 802.15.4 packet with no FCS present.
541 * PARAMETERS
542 * tvbuff_t *tvb - pointer to buffer containing raw packet.
543 * packet_info *pinfo - pointer to packet information fields
544 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
545 * RETURNS
546 * void
547 *---------------------------------------------------------------
549 static void
550 dissect_ieee802154_nofcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
552 tvbuff_t *new_tvb;
553 /* If there is no FCS present in the reported packet, then the length of
554 * the true IEEE 802.15.4 packet is actually 2 bytes longer. Re-create
555 * the buffer with an extended reported length so that the packet will
556 * be handled as though the FCS were truncated.
558 * Note, we can't just call tvb_set_reported_length(), because it includes
559 * checks to ensure that the new reported length is not longer than the old
560 * reported length (why?), and will throw an exception.
562 new_tvb = tvb_new_subset(tvb, 0, -1, tvb_reported_length(tvb)+IEEE802154_FCS_LEN);
563 /* Call the common dissector. */
564 dissect_ieee802154_common(new_tvb, pinfo, tree, 0);
565 } /* dissect_ieee802154_nofcs */
567 /*FUNCTION:------------------------------------------------------
568 * NAME
569 * dissect_ieee802154_cc24xx
570 * DESCRIPTION
571 * Dissector for IEEE 802.15.4 packet with a ChipCon/Texas
572 * Instruments compatible FCS. This is typically called by
573 * layers encapsulating an IEEE 802.15.4 packet.
575 * PARAMETERS
576 * tvbuff_t *tvb - pointer to buffer containing raw packet.
577 * packet_info *pinfo - pointer to packet information fields
578 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
579 * RETURNS
580 * void
581 *---------------------------------------------------------------
583 static void
584 dissect_ieee802154_cc24xx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
586 /* Call the common dissector. */
587 dissect_ieee802154_common(tvb, pinfo, tree, DISSECT_IEEE802154_OPTION_CC24xx);
588 } /* dissect_ieee802154_cc24xx */
590 /*FUNCTION:------------------------------------------------------
591 * NAME
592 * dissect_ieee802154_common
593 * DESCRIPTION
594 * IEEE 802.15.4 packet dissection routine for Wireshark.
595 * This function extracts all the information first before displaying.
596 * If payload exists, that portion will be passed into another dissector
597 * for further processing.
599 * This is called after the individual dissect_ieee802154* functions
600 * have been called to determine what sort of FCS is present.
601 * The dissect_ieee802154* functions will set the parameters
602 * in the ieee802154_packet structure, and pass it to this one
603 * through the data parameter.
605 * PARAMETERS
606 * tvbuff_t *tvb - pointer to buffer containing raw packet.
607 * packet_info *pinfo - pointer to packet information fields
608 * proto_tree *tree - pointer to data tree wireshark uses to display packet.
609 * guint options - bitwise or of dissector options (see DISSECT_IEEE802154_OPTION_xxx).
610 * RETURNS
611 * void
612 *---------------------------------------------------------------
614 static void
615 dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint options)
617 tvbuff_t *volatile payload_tvb;
618 proto_tree *volatile ieee802154_tree = NULL;
619 proto_item *volatile proto_root = NULL;
620 proto_item *hidden_item;
621 proto_item *ti;
623 guint offset = 0;
624 volatile gboolean fcs_ok = TRUE;
625 const char *saved_proto;
626 ws_decrypt_status status;
628 ieee802154_packet *packet = wmem_new(wmem_packet_scope(), ieee802154_packet);
629 ieee802154_short_addr addr16;
630 ieee802154_hints_t *ieee_hints;
632 packet->short_table = ieee802154_map.short_table;
634 /* Allocate frame data with hints for upper layers */
635 if(!pinfo->fd->flags.visited){
636 ieee_hints = wmem_new0(wmem_file_scope(), ieee802154_hints_t);
637 p_add_proto_data(pinfo->fd, proto_ieee802154, 0, ieee_hints);
638 } else {
639 ieee_hints = (ieee802154_hints_t *)p_get_proto_data(pinfo->fd, proto_ieee802154, 0);
642 /* Create the protocol tree. */
643 if (tree) {
644 proto_root = proto_tree_add_protocol_format(tree, proto_ieee802154, tvb, 0, tvb_length(tvb), "IEEE 802.15.4");
645 ieee802154_tree = proto_item_add_subtree(proto_root, ett_ieee802154);
647 /* Add the protocol name. */
648 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEEE 802.15.4");
649 /* Add the packet length. */
650 col_add_fstr(pinfo->cinfo, COL_PACKET_LENGTH, "%i", tvb_length(tvb));
652 /* Add the packet length to the filter field */
653 hidden_item = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_frame_length, NULL, 0, 0, tvb_reported_length(tvb));
654 PROTO_ITEM_SET_HIDDEN(hidden_item);
656 /*=====================================================
657 * FRAME CONTROL FIELD
658 *=====================================================
660 dissect_ieee802154_fcf(tvb, pinfo, ieee802154_tree, packet, &offset);
662 /*=====================================================
663 * SEQUENCE NUMBER
664 *=====================================================
666 packet->seqno = tvb_get_guint8(tvb, offset);
667 if (tree) {
668 proto_tree_add_uint(ieee802154_tree, hf_ieee802154_seqno, tvb, offset, 1, packet->seqno);
669 /* For Ack packets display this in the root. */
670 if (packet->frame_type == IEEE802154_FCF_ACK) {
671 proto_item_append_text(proto_root, ", Sequence Number: %u", packet->seqno);
674 offset += 1;
676 /*=====================================================
677 * ADDRESSING FIELDS
678 *=====================================================
680 /* Clear out the addressing strings. */
681 SET_ADDRESS(&pinfo->dst, AT_NONE, 0, NULL);
682 SET_ADDRESS(&pinfo->src, AT_NONE, 0, NULL);
683 SET_ADDRESS(&pinfo->dl_dst, AT_NONE, 0, NULL);
684 SET_ADDRESS(&pinfo->dl_src, AT_NONE, 0, NULL);
685 SET_ADDRESS(&pinfo->net_dst, AT_NONE, 0, NULL);
686 SET_ADDRESS(&pinfo->net_src, AT_NONE, 0, NULL);
688 /* Get and display the destination PAN, if present. */
689 if ( (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) ||
690 (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) ) {
691 packet->dst_pan = tvb_get_letohs(tvb, offset);
692 if (tree) {
693 proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_panID, tvb, offset, 2, packet->dst_pan);
695 offset += 2;
698 /* Get destination address. */
699 if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) {
700 char dst_addr[32];
702 /* Get the address. */
703 packet->dst16 = tvb_get_letohs(tvb, offset);
705 /* Display the destination address. */
706 if ( packet->dst16 == IEEE802154_BCAST_ADDR ) {
707 g_snprintf(dst_addr, 32, "Broadcast");
709 else {
710 g_snprintf(dst_addr, 32, "0x%04x", packet->dst16);
712 /* Provide address hints to higher layers that need it. */
713 if (ieee_hints) {
714 ieee_hints->dst16 = packet->dst16;
717 TVB_SET_ADDRESS(&pinfo->dl_dst, AT_IEEE_802_15_4_SHORT, tvb, offset, 2);
718 TVB_SET_ADDRESS(&pinfo->dst, AT_IEEE_802_15_4_SHORT, tvb, offset, 2);
720 if (tree) {
721 proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst16, tvb, offset, 2, packet->dst16);
722 proto_item_append_text(proto_root, ", Dst: %s", dst_addr);
725 col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_addr);
726 offset += 2;
728 else if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) {
729 static guint64 addr; /* has to be static due to SET_ADDRESS */
731 /* Get the address */
732 packet->dst64 = tvb_get_letoh64(tvb, offset);
734 /* Copy and convert the address to network byte order. */
735 addr = pntoh64(&(packet->dst64));
737 /* Display the destination address. */
738 /* XXX - OUI resolution doesn't happen when displaying resolved
739 * EUI64 addresses; that should probably be fixed in
740 * epan/addr_resolv.c.
742 SET_ADDRESS(&pinfo->dl_dst, AT_EUI64, 8, &addr);
743 SET_ADDRESS(&pinfo->dst, AT_EUI64, 8, &addr);
744 if (tree) {
745 proto_tree_add_item(ieee802154_tree, hf_ieee802154_dst64, tvb, offset, 8, ENC_LITTLE_ENDIAN);
746 proto_item_append_text(proto_root, ", Dst: %s", get_eui64_name(packet->dst64));
748 col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", get_eui64_name(packet->dst64));
749 offset += 8;
751 else if (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE) {
752 /* Invalid Destination Address Mode. Abort Dissection. */
753 expert_add_info(pinfo, proto_root, &ei_ieee802154_dst);
754 return;
757 /* Get the source PAN if it exists. The source address will be present if:
758 * - The Source addressing exists and
759 * - The Destination addressing doesn't exist, or the Intra-PAN bit is unset.
761 if ( ((packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) || (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT)) &&
762 ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) || (!packet->intra_pan)) ) {
763 /* Source PAN is present, extract it and add it to the tree. */
764 packet->src_pan = tvb_get_letohs(tvb, offset);
765 if (tree) {
766 proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_panID, tvb, offset, 2, packet->src_pan);
768 offset += 2;
770 else {
771 /* Set the panID field in case the intra-pan condition was met. */
772 packet->src_pan = packet->dst_pan;
775 if (ieee_hints) {
776 ieee_hints->src_pan = packet->src_pan;
779 /* Get short source address if present. */
780 if (packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) {
781 char src_addr[32];
783 /* Get the address. */
784 packet->src16 = tvb_get_letohs(tvb, offset);
786 /* Update the Address fields. */
787 if (packet->src16==IEEE802154_BCAST_ADDR) {
788 g_snprintf(src_addr, 32, "Broadcast");
790 else {
791 g_snprintf(src_addr, 32, "0x%04x", packet->src16);
793 if (!pinfo->fd->flags.visited) {
794 /* If we know our extended source address from previous packets,
795 * provide a pointer to it in a hint for upper layers */
796 addr16.addr = packet->src16;
797 addr16.pan = packet->src_pan;
799 if (ieee_hints) {
800 ieee_hints->src16 = packet->src16;
801 ieee_hints->map_rec = (ieee802154_map_rec *)
802 g_hash_table_lookup(ieee802154_map.short_table, &addr16);
807 TVB_SET_ADDRESS(&pinfo->dl_src, AT_IEEE_802_15_4_SHORT, tvb, offset, 2);
808 TVB_SET_ADDRESS(&pinfo->src, AT_IEEE_802_15_4_SHORT, tvb, offset, 2);
810 /* Add the addressing info to the tree. */
811 if (tree) {
812 proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src16, tvb, offset, 2, packet->src16);
813 proto_item_append_text(proto_root, ", Src: %s", src_addr);
815 if (ieee_hints && ieee_hints->map_rec) {
816 /* Display inferred source address info */
817 ti = proto_tree_add_eui64(ieee802154_tree, hf_ieee802154_src64, tvb, offset, 0,
818 ieee_hints->map_rec->addr64);
819 PROTO_ITEM_SET_GENERATED(ti);
821 if ( ieee_hints->map_rec->start_fnum ) {
822 ti = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src64_origin, tvb, 0, 0,
823 ieee_hints->map_rec->start_fnum);
825 else {
826 ti = proto_tree_add_text(ieee802154_tree, tvb, 0, 0, "Origin: Pre-configured");
828 PROTO_ITEM_SET_GENERATED(ti);
832 col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_addr);
834 offset += 2;
836 else if (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) {
837 static guint64 addr; /* has to be static due to SET_ADDRESS */
839 /* Get the address. */
840 packet->src64 = tvb_get_letoh64(tvb, offset);
842 /* Copy and convert the address to network byte order. */
843 addr = pntoh64(&(packet->src64));
845 /* Display the source address. */
846 /* XXX - OUI resolution doesn't happen when displaying resolved
847 * EUI64 addresses; that should probably be fixed in
848 * epan/addr_resolv.c.
850 SET_ADDRESS(&pinfo->dl_src, AT_EUI64, 8, &addr);
851 SET_ADDRESS(&pinfo->src, AT_EUI64, 8, &addr);
852 if (tree) {
853 proto_tree_add_item(ieee802154_tree, hf_ieee802154_src64, tvb, offset, 8, ENC_LITTLE_ENDIAN);
854 proto_item_append_text(proto_root, ", Src: %s", get_eui64_name(packet->src64));
857 col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", get_eui64_name(packet->src64));
858 offset += 8;
860 else if (packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE) {
861 /* Invalid Destination Address Mode. Abort Dissection. */
862 expert_add_info(pinfo, proto_root, &ei_ieee802154_src);
863 return;
866 /*=====================================================
867 * VERIFY FRAME CHECK SEQUENCE
868 *=====================================================
870 /* Check, but don't display the FCS yet, otherwise the payload dissection
871 * may be out of place in the tree. But we want to know if the FCS is OK in
872 * case the CRC is bad (don't want to continue dissection to the NWK layer).
874 if (tvb_bytes_exist(tvb, tvb_reported_length(tvb)-IEEE802154_FCS_LEN, IEEE802154_FCS_LEN)) {
875 /* The FCS is in the last two bytes of the packet. */
876 guint16 fcs = tvb_get_letohs(tvb, tvb_reported_length(tvb)-IEEE802154_FCS_LEN);
877 /* Check if we are expecting a CC2420-style FCS*/
878 if (options & DISSECT_IEEE802154_OPTION_CC24xx) {
879 fcs_ok = (fcs & IEEE802154_CC24xx_CRC_OK);
881 else {
882 guint16 fcs_calc = ieee802154_crc_tvb(tvb, tvb_reported_length(tvb)-IEEE802154_FCS_LEN);
883 fcs_ok = (fcs == fcs_calc);
887 /*=====================================================
888 * AUXILIARY SECURITY HEADER
889 *=====================================================
891 /* The Auxiliary Security Header only exists in IEEE 802.15.4-2006 */
892 if (packet->security_enable && (packet->version == IEEE802154_VERSION_2006)) {
893 proto_tree *header_tree, *field_tree;
894 guint8 security_control;
895 guint aux_length = 5; /* Minimum length of the auxiliary header. */
897 /* Parse the security control field. */
898 security_control = tvb_get_guint8(tvb, offset);
899 packet->security_level = (ieee802154_security_level)(security_control & IEEE802154_AUX_SEC_LEVEL_MASK);
900 packet->key_id_mode = (ieee802154_key_id_mode)((security_control & IEEE802154_AUX_KEY_ID_MODE_MASK) >> IEEE802154_AUX_KEY_ID_MODE_SHIFT);
902 /* Compute the length of the auxiliary header and create a subtree. */
903 if (packet->key_id_mode != KEY_ID_MODE_IMPLICIT) aux_length++;
904 if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_4) aux_length += 4;
905 if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_8) aux_length += 8;
906 ti = proto_tree_add_text(ieee802154_tree, tvb, offset, aux_length, "Auxiliary Security Header");
907 header_tree = proto_item_add_subtree(ti, ett_ieee802154_auxiliary_security);
909 /* Security Control Field */
910 ti = proto_tree_add_text(header_tree, tvb, offset, 1, "Security Control Field (0x%02x)", security_control);
911 field_tree = proto_item_add_subtree(ti, ett_ieee802154_aux_sec_control);
912 proto_tree_add_uint(field_tree, hf_ieee802154_security_level, tvb, offset, 1, security_control & IEEE802154_AUX_SEC_LEVEL_MASK);
913 proto_tree_add_uint(field_tree, hf_ieee802154_key_id_mode, tvb, offset, 1, security_control & IEEE802154_AUX_KEY_ID_MODE_MASK);
914 proto_tree_add_uint(field_tree, hf_ieee802154_aux_sec_reserved, tvb, offset, 1, security_control & IEEE802154_AUX_KEY_RESERVED_MASK);
915 offset++;
917 /* Frame Counter Field */
918 packet->frame_counter = tvb_get_letohl (tvb, offset);
919 proto_tree_add_uint(header_tree, hf_ieee802154_aux_sec_frame_counter, tvb, offset,4, packet->frame_counter);
920 offset +=4;
922 /* Key identifier field(s). */
923 if (packet->key_id_mode != KEY_ID_MODE_IMPLICIT) {
924 /* Create a subtree. */
925 ti = proto_tree_add_text(header_tree, tvb, offset, 1, "Key Identifier Field"); /* Will fix length later. */
926 field_tree = proto_item_add_subtree(ti, ett_ieee802154_aux_sec_key_id);
927 /* Add key source, if it exists. */
928 if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_4) {
929 packet->key_source.addr32 = tvb_get_ntohl(tvb, offset);
930 proto_tree_add_uint64(field_tree, hf_ieee802154_aux_sec_key_source, tvb, offset, 4, packet->key_source.addr32);
931 proto_item_set_len(ti, 1 + 4);
932 offset += (int)sizeof (guint32);
934 if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_8) {
935 packet->key_source.addr64 = tvb_get_ntoh64(tvb, offset);
936 proto_tree_add_uint64(field_tree, hf_ieee802154_aux_sec_key_source, tvb, offset, 8, packet->key_source.addr64);
937 proto_item_set_len(ti, 1 + 8);
938 offset += 8;
940 /* Add key identifier. */
941 packet->key_index = tvb_get_guint8(tvb, offset);
942 proto_tree_add_uint(field_tree, hf_ieee802154_aux_sec_key_index, tvb, offset,1, packet->key_index);
943 offset++;
947 /*=====================================================
948 * NONPAYLOAD FIELDS
949 *=====================================================
951 /* All of the beacon fields, except the beacon payload are considered nonpayload. */
952 if (packet->frame_type == IEEE802154_FCF_BEACON) {
953 /* Parse the superframe spec. */
954 dissect_ieee802154_superframe(tvb, pinfo, ieee802154_tree, &offset);
955 /* Parse the GTS information fields. */
956 dissect_ieee802154_gtsinfo(tvb, pinfo, ieee802154_tree, &offset);
957 /* Parse the Pending address list. */
958 dissect_ieee802154_pendaddr(tvb, pinfo, ieee802154_tree, &offset);
960 /* Only the Command ID is considered nonpayload. */
961 if (packet->frame_type == IEEE802154_FCF_CMD) {
962 packet->command_id = tvb_get_guint8(tvb, offset);
963 if (tree) {
964 proto_tree_add_uint(ieee802154_tree, hf_ieee802154_cmd_id, tvb, offset, 1, packet->command_id);
966 offset++;
968 /* Display the command identifier in the info column. */
969 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
971 /* No other frame types have nonpayload fields. */
973 /*=====================================================
974 * PAYLOAD DISSECTION
975 *=====================================================
977 /* IEEE 802.15.4-2003 may have security information pre-pended to payload */
978 if (packet->security_enable && (packet->version == IEEE802154_VERSION_2003)) {
979 /* Store security suite preference in the 2006 security level identifier to simplify 2003 integration! */
980 packet->security_level = (ieee802154_security_level)ieee802154_sec_suite;
982 /* Frame Counter and Key Sequence Counter prepended to the payload of an encrypted frame */
983 if (IEEE802154_IS_ENCRYPTED(packet->security_level)) {
984 packet->frame_counter = tvb_get_letohl (tvb, offset);
985 proto_tree_add_uint(ieee802154_tree, hf_ieee802154_sec_frame_counter, tvb, offset, (int)sizeof(guint32), packet->frame_counter);
986 offset += (int)sizeof(guint32);
988 packet->key_sequence_counter = tvb_get_guint8 (tvb, offset);
989 proto_tree_add_uint(ieee802154_tree, hf_ieee802154_sec_key_sequence_counter, tvb, offset, (int)sizeof(guint8), packet->key_sequence_counter);
990 offset += (int)sizeof(guint8);
994 /* Encrypted Payload. */
995 if (packet->security_enable) {
996 payload_tvb = dissect_ieee802154_decrypt(tvb, offset, pinfo, packet, &status);
998 /* Get the unencrypted data if decryption failed. */
999 if (!payload_tvb) {
1000 /* Deal with possible truncation and the FCS field at the end. */
1001 gint reported_len = tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN;
1002 gint captured_len = tvb_length(tvb)-offset;
1003 if (reported_len < captured_len) captured_len = reported_len;
1004 payload_tvb = tvb_new_subset(tvb, offset, captured_len, reported_len);
1007 /* Display the reason for failure, and abort if the error was fatal. */
1008 switch (status) {
1009 case DECRYPT_PACKET_SUCCEEDED:
1010 case DECRYPT_NOT_ENCRYPTED:
1011 /* No problem. */
1012 break;
1014 case DECRYPT_VERSION_UNSUPPORTED:
1015 /* We don't support decryption with that version of the protocol */
1016 expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "We don't support decryption with protocol version %u", packet->version);
1017 call_dissector(data_handle, payload_tvb, pinfo, tree);
1018 goto dissect_ieee802154_fcs;
1020 case DECRYPT_PACKET_TOO_SMALL:
1021 expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "Packet was too small to include the CRC and MIC");
1022 call_dissector(data_handle, payload_tvb, pinfo, tree);
1023 goto dissect_ieee802154_fcs;
1025 case DECRYPT_PACKET_NO_EXT_SRC_ADDR:
1026 expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "No extended source address - can't decrypt");
1027 call_dissector(data_handle, payload_tvb, pinfo, tree);
1028 goto dissect_ieee802154_fcs;
1030 case DECRYPT_PACKET_NO_KEY:
1031 expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "No encryption key set - can't decrypt");
1032 call_dissector(data_handle, payload_tvb, pinfo, tree);
1033 goto dissect_ieee802154_fcs;
1035 case DECRYPT_PACKET_DECRYPT_FAILED:
1036 expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "Decrypt failed");
1037 call_dissector(data_handle, payload_tvb, pinfo, tree);
1038 goto dissect_ieee802154_fcs;
1040 case DECRYPT_PACKET_MIC_CHECK_FAILED:
1041 expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "MIC check failed");
1043 * Abort only if the payload was encrypted, in which case we
1044 * probably didn't decrypt the packet right (eg: wrong key).
1046 if (IEEE802154_IS_ENCRYPTED(packet->security_level)) {
1047 call_dissector(data_handle, payload_tvb, pinfo, tree);
1048 goto dissect_ieee802154_fcs;
1050 break;
1053 /* Plaintext Payload. */
1054 else {
1055 /* Deal with possible truncation and the FCS field at the end. */
1056 gint reported_len = tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN;
1057 gint captured_len = tvb_length(tvb)-offset;
1058 if (reported_len < captured_len) captured_len = reported_len;
1059 payload_tvb = tvb_new_subset(tvb, offset, captured_len, reported_len);
1063 * Wrap the sub-dissection in a try/catch block in case the payload is
1064 * broken. First we store the current protocol so we can fix it if an
1065 * exception is thrown by the subdissectors.
1067 saved_proto = pinfo->current_proto;
1068 /* Try to dissect the payload. */
1069 TRY {
1070 if ((packet->frame_type == IEEE802154_FCF_BEACON) ||
1071 (packet->frame_type == IEEE802154_FCF_DATA)) {
1072 /* Beacon and Data packets contain a payload. */
1073 if ((fcs_ok || !ieee802154_fcs_ok) && (tvb_reported_length(payload_tvb)>0)) {
1074 /* Attempt heuristic subdissection. */
1075 if (!dissector_try_heuristic(ieee802154_heur_subdissector_list, payload_tvb, pinfo, tree, packet)) {
1076 /* Could not subdissect, call the data dissector instead. */
1077 call_dissector(data_handle, payload_tvb, pinfo, tree);
1080 else {
1081 /* If no sub-dissector was called, call the data dissector. */
1082 call_dissector(data_handle, payload_tvb, pinfo, tree);
1085 /* If the packet is a command, try to dissect the payload. */
1086 else if (packet->frame_type == IEEE802154_FCF_CMD) {
1087 switch (packet->command_id) {
1088 case IEEE802154_CMD_ASRQ:
1089 IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
1090 (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
1091 (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE));
1092 dissect_ieee802154_assoc_req(payload_tvb, pinfo, ieee802154_tree, packet);
1093 break;
1095 case IEEE802154_CMD_ASRSP:
1096 IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
1097 (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
1098 (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
1099 dissect_ieee802154_assoc_rsp(payload_tvb, pinfo, ieee802154_tree, packet);
1100 break;
1102 case IEEE802154_CMD_DISAS:
1103 IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
1104 (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
1105 (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
1106 dissect_ieee802154_disassoc(payload_tvb, pinfo, ieee802154_tree, packet);
1107 break;
1109 case IEEE802154_CMD_DATA_RQ:
1110 IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id, packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE);
1111 /* No payload expected. */
1112 break;
1114 case IEEE802154_CMD_PANID_ERR:
1115 IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
1116 (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
1117 (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
1118 /* No payload expected. */
1119 break;
1121 case IEEE802154_CMD_ORPH_NOTIF:
1122 IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
1123 (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
1124 (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) &&
1125 (packet->dst16 == IEEE802154_BCAST_ADDR) &&
1126 (packet->src_pan == IEEE802154_BCAST_PAN) &&
1127 (packet->dst_pan == IEEE802154_BCAST_PAN));
1128 /* No payload expected. */
1129 break;
1131 case IEEE802154_CMD_BCN_RQ:
1132 IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
1133 (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) &&
1134 (packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) &&
1135 (packet->dst16 == IEEE802154_BCAST_ADDR) &&
1136 (packet->dst_pan == IEEE802154_BCAST_PAN));
1137 /* No payload expected. */
1138 break;
1140 case IEEE802154_CMD_COORD_REAL:
1141 IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
1142 (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
1143 (packet->dst_pan == IEEE802154_BCAST_PAN) &&
1144 (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE));
1145 if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) {
1146 /* If directed to a 16-bit address, check that it is being broadcast. */
1147 IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id, packet->dst16 == IEEE802154_BCAST_ADDR);
1149 dissect_ieee802154_realign(payload_tvb, pinfo, ieee802154_tree, packet);
1150 break;
1152 case IEEE802154_CMD_GTS_REQ:
1153 /* Check that the addressing is correct for this command type. */
1154 IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
1155 (packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) &&
1156 (packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) &&
1157 (packet->src16 != IEEE802154_BCAST_ADDR) &&
1158 (packet->src16 != IEEE802154_NO_ADDR16));
1159 dissect_ieee802154_gtsreq(payload_tvb, pinfo, ieee802154_tree, packet);
1160 break;
1162 default:
1163 /* Unknown Command */
1164 call_dissector(data_handle, payload_tvb, pinfo, ieee802154_tree);
1165 break;
1166 } /* switch */
1168 /* Otherwise, dump whatever is left over to the data dissector. */
1169 else {
1170 call_dissector(data_handle, payload_tvb, pinfo, tree);
1173 CATCH_ALL {
1175 * Someone encountered an error while dissecting the payload. But
1176 * we haven't yet finished processing all of our layer. Catch and
1177 * display the exception, then fall-through to finish displaying
1178 * the FCS (which we display last so the frame is ordered correctly
1179 * in the tree).
1181 show_exception(payload_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
1182 pinfo->current_proto = saved_proto;
1184 ENDTRY;
1186 /*=====================================================
1187 * FRAME CHECK SEQUENCE
1188 *=====================================================
1190 dissect_ieee802154_fcs:
1191 /* The FCS should be the last bytes of the reported packet. */
1192 offset = tvb_reported_length(tvb)-IEEE802154_FCS_LEN;
1193 /* Dissect the FCS only if it exists (captures which don't or can't get the
1194 * FCS will simply truncate the packet to omit it, but should still set the
1195 * reported length to cover the original packet length), so if the snapshot
1196 * is too short for an FCS don't make a fuss.
1198 if (tvb_bytes_exist(tvb, offset, IEEE802154_FCS_LEN) && (tree)) {
1199 proto_tree *field_tree;
1200 guint16 fcs = tvb_get_letohs(tvb, offset);
1202 /* Display the FCS depending on expected FCS format */
1203 if ((options & DISSECT_IEEE802154_OPTION_CC24xx)) {
1204 /* Create a subtree for the FCS. */
1205 ti = proto_tree_add_text(ieee802154_tree, tvb, offset, 2, "Frame Check Sequence (TI CC24xx format): FCS %s", (fcs_ok) ? "OK" : "Bad");
1206 field_tree = proto_item_add_subtree(ti, ett_ieee802154_fcs);
1207 /* Display FCS contents. */
1208 ti = proto_tree_add_int(field_tree, hf_ieee802154_rssi, tvb, offset++, 1, (gint8) (fcs & IEEE802154_CC24xx_RSSI));
1209 proto_item_append_text(ti, " dB"); /* Displaying Units */
1210 proto_tree_add_boolean(field_tree, hf_ieee802154_fcs_ok, tvb, offset, 1, (gboolean) (fcs & IEEE802154_CC24xx_CRC_OK));
1211 proto_tree_add_uint(field_tree, hf_ieee802154_correlation, tvb, offset, 1, (guint8) ((fcs & IEEE802154_CC24xx_CORRELATION) >> 8));
1213 else {
1214 ti = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_fcs, tvb, offset, 2, fcs);
1215 if (fcs_ok) {
1216 proto_item_append_text(ti, " (Correct)");
1218 else {
1219 proto_item_append_text(ti, " (Incorrect, expected FCS=0x%04x", ieee802154_crc_tvb(tvb, offset));
1221 /* To Help with filtering, add the fcs_ok field to the tree. */
1222 ti = proto_tree_add_boolean(ieee802154_tree, hf_ieee802154_fcs_ok, tvb, offset, 2, fcs_ok);
1223 PROTO_ITEM_SET_HIDDEN(ti);
1226 else if (tree) {
1227 /* Even if the FCS isn't present, add the fcs_ok field to the tree to
1228 * help with filter. Be sure not to make it visible though.
1230 ti = proto_tree_add_boolean_format_value(ieee802154_tree, hf_ieee802154_fcs_ok, tvb, offset, 2, fcs_ok, "Unknown");
1231 PROTO_ITEM_SET_HIDDEN(ti);
1234 /* If the CRC is invalid, make a note of it in the info column. */
1235 if (!fcs_ok) {
1236 col_append_str(pinfo->cinfo, COL_INFO, ", Bad FCS");
1237 if (tree) proto_item_append_text(proto_root, ", Bad FCS");
1239 /* Flag packet as having a bad crc. */
1240 expert_add_info(pinfo, proto_root, &ei_ieee802154_fcs);
1242 } /* dissect_ieee802154_common */
1244 /*FUNCTION:------------------------------------------------------
1245 * NAME
1246 * dissect_ieee802154_superframe
1247 * DESCRIPTION
1248 * Subdissector command for the Superframe specification
1249 * sub-field within the beacon frame.
1250 * PARAMETERS
1251 * tvbuff_t *tvb - pointer to buffer containing raw packet.
1252 * packet_info *pinfo - pointer to packet information fields (unused).
1253 * proto_tree *tree - pointer to command subtree.
1254 * ieee802154_packet *packet - IEEE 802.15.4 packet information (unused).
1255 * guint *offset - offset into the tvbuff to begin dissection.
1256 * RETURNS
1257 * void
1258 *---------------------------------------------------------------
1260 static void
1261 dissect_ieee802154_superframe(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint *offset)
1263 proto_tree *field_tree = NULL;
1264 proto_item *ti;
1265 guint16 superframe;
1267 /* Parse the superframe spec. */
1268 superframe = tvb_get_letohs(tvb, *offset);
1269 if (tree) {
1270 /* Add Subtree for superframe specification */
1271 ti = proto_tree_add_text(tree, tvb, *offset, 2, "Superframe Specification");
1272 field_tree = proto_item_add_subtree(ti, ett_ieee802154_superframe);
1274 /* Add Beacon Order to the superframe spec. */
1275 proto_tree_add_uint(field_tree, hf_ieee802154_beacon_order, tvb, *offset, 2, superframe & IEEE802154_BEACON_ORDER_MASK);
1276 proto_tree_add_uint(field_tree, hf_ieee802154_superframe_order, tvb, *offset, 2, superframe & IEEE802154_SUPERFRAME_ORDER_MASK);
1277 proto_tree_add_uint(field_tree, hf_ieee802154_cap, tvb, *offset, 2, superframe & IEEE802154_SUPERFRAME_CAP_MASK);
1278 proto_tree_add_boolean(field_tree, hf_ieee802154_superframe_battery_ext, tvb, *offset, 2, superframe & IEEE802154_BATT_EXTENSION_MASK);
1279 proto_tree_add_boolean(field_tree, hf_ieee802154_superframe_coord, tvb, *offset, 2, superframe & IEEE802154_SUPERFRAME_COORD_MASK);
1280 proto_tree_add_boolean(field_tree, hf_ieee802154_assoc_permit, tvb, *offset, 2, superframe & IEEE802154_ASSOC_PERMIT_MASK);
1282 (*offset) += 2;
1283 } /* dissect_ieee802154_superframe */
1285 /*FUNCTION:------------------------------------------------------
1286 * NAME
1287 * dissect_ieee802154_gtsinfo
1288 * DESCRIPTION
1289 * Subdissector command for the GTS information fields within
1290 * the beacon frame.
1291 * PARAMETERS
1292 * tvbuff_t *tvb - pointer to buffer containing raw packet.
1293 * packet_info *pinfo - pointer to packet information fields (unused).
1294 * proto_tree *tree - pointer to command subtree.
1295 * ieee802154_packet *packet - IEEE 802.15.4 packet information (unused).
1296 * guint *offset - offset into the tvbuff to begin dissection.
1297 * RETURNS
1298 * void
1299 *---------------------------------------------------------------
1301 static void
1302 dissect_ieee802154_gtsinfo(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint *offset)
1304 proto_tree *field_tree = NULL;
1305 proto_tree *subtree = NULL;
1306 proto_item *ti;
1307 guint8 gts_spec;
1308 guint8 gts_count;
1310 /* Get and display the GTS specification field */
1311 gts_spec = tvb_get_guint8(tvb, *offset);
1312 gts_count = gts_spec & IEEE802154_GTS_COUNT_MASK;
1313 if (tree) {
1314 /* Add Subtree for GTS information. */
1315 if (gts_count) {
1316 ti = proto_tree_add_text(tree, tvb, *offset, 2 + (gts_count * 3), "GTS");
1318 else {
1319 ti = proto_tree_add_text(tree, tvb, *offset, 1, "GTS");
1321 field_tree = proto_item_add_subtree(ti, ett_ieee802154_gts);
1323 proto_tree_add_uint(field_tree, hf_ieee802154_gts_count, tvb, *offset, 1, gts_count);
1324 proto_tree_add_boolean(field_tree, hf_ieee802154_gts_permit, tvb, *offset, 1, gts_spec & IEEE802154_GTS_PERMIT_MASK);
1326 (*offset) += 1;
1328 /* If the GTS descriptor count is nonzero, then the GTS directions mask and descriptor list are present. */
1329 if (gts_count) {
1330 guint8 gts_directions = tvb_get_guint8(tvb, *offset);
1331 guint gts_rx = 0;
1332 int i;
1334 /* Display the directions mask. */
1335 if (tree) {
1336 proto_tree *dir_tree = NULL;
1338 /* Create a subtree. */
1339 ti = proto_tree_add_text(field_tree, tvb, *offset, 1, "GTS Directions");
1340 dir_tree = proto_item_add_subtree(ti, ett_ieee802154_gts_direction);
1342 /* Add the directions to the subtree. */
1343 for (i=0; i<gts_count; i++) {
1344 gboolean dir = gts_directions & IEEE802154_GTS_DIRECTION_SLOT(i);
1345 proto_tree_add_boolean_format(dir_tree, hf_ieee802154_gts_direction, tvb, *offset, 1, dir, "GTS Slot %i: %s", i+1, dir?"Receive Only":"Transmit Only");
1346 if (dir) gts_rx++;
1347 } /* for */
1348 proto_item_append_text(ti, ": %i Receive & %i Transmit", gts_rx, gts_count - gts_rx);
1350 (*offset) += 1;
1352 /* Create a subtree for the GTS descriptors. */
1353 if (tree) {
1354 ti = proto_tree_add_text(field_tree, tvb, *offset, gts_count * 3, "GTS Descriptors");
1355 subtree = proto_item_add_subtree(ti, ett_ieee802154_gts_descriptors);
1358 /* Get and display the GTS descriptors. */
1359 for (i=0; i<gts_count; i++) {
1360 guint16 gts_addr = tvb_get_letohs(tvb, (*offset));
1361 guint8 gts_slot = tvb_get_guint8(tvb, (*offset)+2);
1362 guint8 gts_length = (gts_slot & IEEE802154_GTS_LENGTH_MASK) >> IEEE802154_GTS_LENGTH_SHIFT;
1364 gts_slot = (gts_slot & IEEE802154_GTS_SLOT_MASK);
1366 if (tree) {
1367 /* Add address, slot, and time length fields. */
1368 ti = proto_tree_add_text(subtree, tvb, (*offset), 3, "{Address: 0x%04x", gts_addr);
1369 proto_item_append_text(ti, ", Slot: %i", gts_slot);
1370 proto_item_append_text(ti, ", Length: %i}", gts_length);
1372 (*offset) += 3;
1373 } /* for */
1375 } /* dissect_ieee802154_gtsinfo */
1377 /*FUNCTION:------------------------------------------------------
1378 * NAME
1379 * dissect_ieee802154_pendaddr
1380 * DESCRIPTION
1381 * Subdissector command for the pending address list fields
1382 * within the beacon frame.
1383 * PARAMETERS
1384 * tvbuff_t *tvb - pointer to buffer containing raw packet.
1385 * packet_info *pinfo - pointer to packet information fields (unused).
1386 * proto_tree *tree - pointer to command subtree.
1387 * ieee802154_packet *packet - IEEE 802.15.4 packet information (unused).
1388 * guint *offset - offset into the tvbuff to begin dissection.
1389 * RETURNS
1390 * void
1391 *---------------------------------------------------------------
1393 static void
1394 dissect_ieee802154_pendaddr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint *offset)
1396 proto_tree *subtree = NULL;
1397 proto_item *ti;
1398 guint8 pend_spec;
1399 guint8 pend_num16;
1400 guint8 pend_num64;
1401 int i;
1403 /* Get the Pending Addresses specification fields */
1404 pend_spec = tvb_get_guint8(tvb, *offset);
1405 pend_num16 = pend_spec & IEEE802154_PENDADDR_SHORT_MASK;
1406 pend_num64 = (pend_spec & IEEE802154_PENDADDR_LONG_MASK) >> IEEE802154_PENDADDR_LONG_SHIFT;
1407 if (tree) {
1408 /* Add Subtree for the addresses */
1409 ti = proto_tree_add_text(tree, tvb, *offset, 1 + 2*pend_num16 + 8*pend_num64, "Pending Addresses: %i Short and %i Long", pend_num16, pend_num64);
1410 subtree = proto_item_add_subtree(ti, ett_ieee802154_pendaddr);
1412 (*offset) += 1;
1414 for (i=0; i<pend_num16; i++) {
1415 guint16 addr = tvb_get_letohs(tvb, *offset);
1416 proto_tree_add_uint(subtree, hf_ieee802154_pending16, tvb, *offset, 2, addr);
1417 (*offset) += 2;
1418 } /* for */
1419 for (i=0; i<pend_num64; i++) {
1420 proto_tree_add_item(subtree, hf_ieee802154_pending64, tvb, *offset, 8, ENC_LITTLE_ENDIAN);
1421 (*offset) += 8;
1422 } /* for */
1423 } /* dissect_ieee802154_pendaddr */
1425 /*FUNCTION:------------------------------------------------------
1426 * NAME
1427 * dissect_ieee802154_assoc_req
1428 * DESCRIPTION
1429 * Command subdissector routine for the Association request
1430 * command.
1431 * PARAMETERS
1432 * tvbuff_t *tvb - pointer to buffer containing raw packet.
1433 * packet_info *pinfo - pointer to packet information fields.
1434 * proto_tree *tree - pointer to protocol tree.
1435 * ieee802154_packet *packet - IEEE 802.15.4 packet information.
1436 * RETURNS
1437 * void
1438 *---------------------------------------------------------------
1440 static void
1441 dissect_ieee802154_assoc_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
1443 proto_tree *subtree = NULL;
1444 proto_item * ti;
1445 guint8 capability;
1447 /* Create a subtree for this command frame. */
1448 if (tree) {
1449 ti = proto_tree_add_text(tree, tvb, 0, 1, "%s", val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
1450 subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd);
1453 /* Get and display capability info. */
1454 capability = tvb_get_guint8(tvb, 0);
1455 if (tree) {
1456 /* Enter the capability bits. */
1457 proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_alt_coord, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_ALT_PAN_COORD);
1458 ti = proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_device_type, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_DEVICE_TYPE);
1459 if (capability & IEEE802154_CMD_CINFO_DEVICE_TYPE) proto_item_append_text(ti, " (FFD)");
1460 else proto_item_append_text(ti, " (RFD)");
1461 ti = proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_power_src, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_POWER_SRC);
1462 if (capability & IEEE802154_CMD_CINFO_POWER_SRC) proto_item_append_text(ti, " (AC/Mains Power)");
1463 else proto_item_append_text(ti, " (Battery)");
1464 proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_idle_rx, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_IDLE_RX);
1465 proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_sec_capable, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_SEC_CAPABLE);
1466 proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_alloc_addr, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_ALLOC_ADDR);
1469 /* Call the data dissector for any leftover bytes. */
1470 if (tvb_length(tvb) > 1) {
1471 call_dissector(data_handle, tvb_new_subset_remaining(tvb, 1), pinfo, tree);
1473 } /* dissect_ieee802154_assoc_req */
1475 /*FUNCTION:------------------------------------------------------
1476 * NAME
1477 * dissect_ieee802154_assoc_rsp
1478 * DESCRIPTION
1479 * Command subdissector routine for the Association response
1480 * command.
1481 * PARAMETERS
1482 * tvbuff_t *tvb - pointer to buffer containing raw packet.
1483 * packet_info *pinfo - pointer to packet information fields.
1484 * proto_tree *tree - pointer to protocol tree.
1485 * ieee802154_packet *packet - IEEE 802.15.4 packet information.
1486 * RETURNS
1487 * void
1488 *---------------------------------------------------------------
1490 static void
1491 dissect_ieee802154_assoc_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
1493 proto_tree *subtree = NULL;
1494 proto_item *ti;
1495 guint16 short_addr;
1496 guint8 status;
1497 guint offset = 0;
1499 /* Create a subtree for this command frame. */
1500 if (tree) {
1501 ti = proto_tree_add_text(tree, tvb, offset, 3, "%s", val_to_str_const(packet->command_id,
1502 ieee802154_cmd_names, "Unknown Command"));
1503 subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd);
1506 /* Get and display the short address. */
1507 short_addr = tvb_get_letohs(tvb, offset);
1508 if (tree) {
1509 proto_tree_add_uint(subtree, hf_ieee802154_assoc_addr, tvb, offset, 2, short_addr);
1511 offset += 2;
1513 /* Get and display the status. */
1514 status = tvb_get_guint8(tvb, offset);
1515 if (tree) {
1516 ti = proto_tree_add_uint(subtree, hf_ieee802154_assoc_status, tvb, offset, 1, status);
1517 if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) proto_item_append_text(ti, " (Association Successful)");
1518 else if (status == IEEE802154_CMD_ASRSP_PAN_FULL) proto_item_append_text(ti, " (PAN Full)");
1519 else if (status == IEEE802154_CMD_ASRSP_PAN_DENIED) proto_item_append_text(ti, " (Association Denied)");
1520 else proto_item_append_text(ti, " (Reserved)");
1522 offset += 1;
1524 /* Update the info column. */
1525 if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) {
1526 /* Association was successful. */
1527 if (packet->src_addr_mode != IEEE802154_FCF_ADDR_SHORT) {
1528 col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", packet->dst_pan);
1530 if (short_addr != IEEE802154_NO_ADDR16) {
1531 col_append_fstr(pinfo->cinfo, COL_INFO, " Addr: 0x%04x", short_addr);
1534 else {
1535 /* Association was unsuccessful. */
1536 col_append_str(pinfo->cinfo, COL_INFO, ", Unsuccessful");
1539 /* Update the address table. */
1540 if ((status == IEEE802154_CMD_ASRSP_AS_SUCCESS) && (short_addr != IEEE802154_NO_ADDR16)) {
1541 ieee802154_addr_update(&ieee802154_map, short_addr, packet->dst_pan, packet->dst64,
1542 pinfo->current_proto, pinfo->fd->num);
1545 /* Call the data dissector for any leftover bytes. */
1546 if (tvb_length(tvb) > offset) {
1547 call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree);
1549 } /* dissect_ieee802154_assoc_rsp */
1551 /*FUNCTION:------------------------------------------------------
1552 * NAME
1553 * dissect_ieee802154_disassoc
1554 * DESCRIPTION
1555 * Command subdissector routine for the Disassociate command.
1556 * PARAMETERS
1557 * tvbuff_t *tvb - pointer to buffer containing raw packet.
1558 * packet_info *pinfo - pointer to packet information fields.
1559 * proto_tree *tree - pointer to protocol tree.
1560 * ieee802154_packet *packet - IEEE 802.15.4 packet information.
1561 * RETURNS
1562 * void
1563 *---------------------------------------------------------------
1565 static void
1566 dissect_ieee802154_disassoc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
1568 proto_tree *subtree = NULL;
1569 proto_item *ti;
1570 guint8 reason;
1572 /* Create a subtree for this command frame. */
1573 if (tree) {
1574 ti = proto_tree_add_text(tree, tvb, 0, 1, "%s", val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
1575 subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd);
1578 /* Get and display the disassociation reason. */
1579 reason = tvb_get_guint8(tvb, 0);
1580 if (tree) {
1581 ti = proto_tree_add_uint(subtree, hf_ieee802154_disassoc_reason, tvb, 0, 1, reason);
1582 switch(reason) {
1583 case 0x01:
1584 proto_item_append_text(ti, " (Coordinator requests device to leave)");
1585 break;
1587 case 0x02:
1588 proto_item_append_text(ti, " (Device wishes to leave)");
1589 break;
1591 default:
1592 proto_item_append_text(ti, " (Reserved)");
1593 break;
1594 } /* switch */
1597 if (!pinfo->fd->flags.visited) {
1598 /* Update the address tables */
1599 if ( packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT ) {
1600 ieee802154_long_addr_invalidate(packet->dst64, pinfo->fd->num);
1601 } else if ( packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT ) {
1602 ieee802154_short_addr_invalidate(packet->dst16, packet->dst_pan, pinfo->fd->num);
1606 /* Call the data dissector for any leftover bytes. */
1607 if (tvb_length(tvb) > 1) {
1608 call_dissector(data_handle, tvb_new_subset_remaining(tvb, 1), pinfo, tree);
1610 } /* dissect_ieee802154_disassoc */
1612 /*FUNCTION:------------------------------------------------------
1613 * NAME
1614 * dissect_ieee802154_realign
1615 * DESCRIPTION
1616 * Command subdissector routine for the Coordinator Realignment
1617 * command.
1618 * PARAMETERS
1619 * tvbuff_t *tvb - pointer to buffer containing raw packet.
1620 * packet_info *pinfo - pointer to packet information fields.
1621 * proto_tree *tree - pointer to protocol tree.
1622 * ieee802154_packet *packet - IEEE 802.15.4 packet information.
1623 * RETURNS
1624 * void
1625 *---------------------------------------------------------------
1627 static void
1628 dissect_ieee802154_realign(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
1630 proto_tree *subtree = NULL;
1631 proto_item *ti;
1632 guint16 pan_id;
1633 guint16 coord_addr;
1634 guint8 channel;
1635 guint16 short_addr;
1636 guint offset = 0;
1638 /* Create a subtree for this command frame. */
1639 if (tree) {
1640 ti = proto_tree_add_text(tree, tvb, offset, 0, "%s", val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
1641 subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd);
1644 /* Get and display the command PAN ID. */
1645 pan_id = tvb_get_letohs(tvb, offset);
1646 proto_tree_add_uint(subtree, hf_ieee802154_realign_pan, tvb, offset, 2, pan_id);
1647 col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", pan_id);
1648 offset += 2;
1650 /* Get and display the coordinator address. */
1651 coord_addr = tvb_get_letohs(tvb, offset);
1652 proto_tree_add_uint(subtree, hf_ieee802154_realign_caddr, tvb, offset, 2, coord_addr);
1653 col_append_fstr(pinfo->cinfo, COL_INFO, ", Coordinator: 0x%04x", coord_addr);
1654 offset += 2;
1656 /* Get and display the channel. */
1657 channel = tvb_get_guint8(tvb, offset);
1658 proto_tree_add_uint(subtree, hf_ieee802154_realign_channel, tvb, offset, 1, channel);
1659 col_append_fstr(pinfo->cinfo, COL_INFO, ", Channel: %u", channel);
1660 offset += 1;
1662 /* Get and display the short address. */
1663 short_addr = tvb_get_letohs(tvb, offset);
1664 if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_addr, tvb, offset, 2, short_addr);
1665 if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT)
1666 && (short_addr != IEEE802154_NO_ADDR16)) {
1667 col_append_fstr(pinfo->cinfo, COL_INFO, ", Addr: 0x%04x", short_addr);
1669 offset += 2;
1670 /* Update the address table. */
1671 if ((short_addr != IEEE802154_NO_ADDR16) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT)) {
1672 ieee802154_addr_update(&ieee802154_map, short_addr, packet->dst_pan, packet->dst64,
1673 pinfo->current_proto, pinfo->fd->num);
1676 /* Get and display the channel page, if it exists. Added in IEEE802.15.4-2006 */
1677 if (tvb_bytes_exist(tvb, offset, 1)) {
1678 guint8 channel_page = tvb_get_guint8(tvb, offset);
1679 if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_channel_page, tvb, offset, 1, channel_page);
1680 offset += 1;
1683 /* Fix the length of the command subtree. */
1684 if (tree) {
1685 proto_item_set_len(subtree, offset);
1688 /* Call the data dissector for any leftover bytes. */
1689 if (tvb_length(tvb) > offset) {
1690 call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree);
1692 } /* dissect_ieee802154_realign */
1694 /*FUNCTION:------------------------------------------------------
1695 * NAME
1696 * dissect_ieee802154_gtsreq
1697 * DESCRIPTION
1698 * Command subdissector routine for the GTS request command.
1700 * Assumes that COL_INFO will be set to the command name,
1701 * command name will already be appended to the command subtree
1702 * and protocol root. In addition, assumes that the command ID
1703 * has already been parsed.
1704 * PARAMETERS
1705 * tvbuff_t *tvb - pointer to buffer containing raw packet.
1706 * packet_info *pinfo - pointer to packet information fields (unused).
1707 * proto_tree *tree - pointer to protocol tree.
1708 * ieee802154_packet *packet - IEEE 802.15.4 packet information (unused).
1709 * RETURNS
1710 * void
1711 *---------------------------------------------------------------
1713 static void
1714 dissect_ieee802154_gtsreq(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
1716 proto_tree *subtree = NULL;
1717 proto_item *ti;
1718 guint8 characteristics;
1719 guint8 length;
1720 guint8 direction;
1721 guint8 type;
1723 /* Create a subtree for this command frame. */
1724 if (tree) {
1725 ti = proto_tree_add_text(tree, tvb, 0, 1, "%s", val_to_str_const(packet->command_id, ieee802154_cmd_names,
1726 "Unknown Command"));
1727 subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd);
1730 /* Get the characteristics field. */
1731 characteristics = tvb_get_guint8(tvb, 0);
1732 length = characteristics & IEEE802154_CMD_GTS_REQ_LEN;
1733 direction = characteristics & IEEE802154_CMD_GTS_REQ_DIR;
1734 type = characteristics & IEEE802154_CMD_GTS_REQ_TYPE;
1736 /* Display the characteristics field. */
1737 if (tree) {
1738 proto_tree_add_uint(subtree, hf_ieee802154_gtsreq_len, tvb, 0, 1, length);
1739 ti = proto_tree_add_boolean(subtree, hf_ieee802154_gtsreq_dir, tvb, 0, 1, direction);
1740 if (direction) proto_item_append_text(ti, " (Receive)");
1741 else proto_item_append_text(ti, " (Transmit)");
1742 ti = proto_tree_add_boolean(subtree, hf_ieee802154_gtsreq_type, tvb, 0, 1, type);
1743 if (type) proto_item_append_text(ti, " (Allocate GTS)");
1744 else proto_item_append_text(ti, " (Deallocate GTS)");
1747 /* Call the data dissector for any leftover bytes. */
1748 if (tvb_length(tvb) > 1) {
1749 call_dissector(data_handle, tvb_new_subset_remaining(tvb, 1), pinfo, tree);
1751 } /* dissect_ieee802154_gtsreq */
1753 /*FUNCTION:------------------------------------------------------
1754 * NAME
1755 * dissect_ieee802154_decrypt
1756 * DESCRIPTION
1757 * IEEE 802.15.4 decryption algorithm. Tries to find the
1758 * appropriate key from the information in the IEEE 802.15.4
1759 * packet structure and dissector config.
1761 * This function implements the security proceedures for the
1762 * 2006 version of the spec only. IEEE 802.15.4-2003 is
1763 * unsupported.
1764 * PARAMETERS
1765 * tvbuff_t *tvb - IEEE 802.15.4 packet.
1766 * packet_info * pinfo - Packet info structure.
1767 * guint offset - Offset where the ciphertext 'c' starts.
1768 * ieee802154_packet *packet - IEEE 802.15.4 packet information.
1769 * ws_decrypt_status *status - status of decryption returned through here on failure.
1770 * RETURNS
1771 * tvbuff_t * - Decrypted payload.
1772 *---------------------------------------------------------------
1774 static tvbuff_t *
1775 dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ieee802154_packet * packet, ws_decrypt_status * status)
1777 tvbuff_t * ptext_tvb;
1778 gboolean have_mic = FALSE;
1779 guint64 srcAddr;
1780 unsigned char key[16];
1781 unsigned char tmp[16];
1782 unsigned char rx_mic[16];
1783 guint M;
1784 gint captured_len;
1785 gint reported_len;
1786 ieee802154_hints_t *ieee_hints;
1789 * Check the version; we only support IEEE 802.15.4-2003 and IEEE 802.15.4-2006.
1790 * We must do this first, as, if this isn't IEEE 802.15.4-2003 or IEEE 802.15.4-2006,
1791 * we don't have the Auxiliary Security Header, and haven't
1792 * filled in the information for it, and none of the stuff
1793 * we do afterwards, which uses that information, is doable.
1795 if ((packet->version != IEEE802154_VERSION_2006) && (packet->version != IEEE802154_VERSION_2003)) {
1796 *status = DECRYPT_VERSION_UNSUPPORTED;
1797 return NULL;
1800 ieee_hints = (ieee802154_hints_t *)p_get_proto_data(pinfo->fd, proto_ieee802154, 0);
1802 /* Get the captured and on-the-wire length of the payload. */
1803 M = IEEE802154_MIC_LENGTH(packet->security_level);
1804 reported_len = tvb_reported_length_remaining(tvb, offset) - IEEE802154_FCS_LEN - M;
1805 if (reported_len < 0) {
1806 *status = DECRYPT_PACKET_TOO_SMALL;
1807 return NULL;
1809 /* Check of the payload is truncated. */
1810 if (tvb_bytes_exist(tvb, offset, reported_len)) {
1811 captured_len = reported_len;
1813 else {
1814 captured_len = tvb_length_remaining(tvb, offset);
1817 /* Check if the MIC is present in the captured data. */
1818 have_mic = tvb_bytes_exist(tvb, offset + reported_len, M);
1819 if (have_mic) {
1820 tvb_memcpy(tvb, rx_mic, offset + reported_len, M);
1823 /*=====================================================
1824 * Key Lookup - Need to find the appropriate key.
1825 *=====================================================
1828 * Oh God! The specification is so bad. This is the worst
1829 * case of design-by-committee I've ever seen in my life.
1830 * The IEEE has created an unintelligable mess in order
1831 * to decipher which key is used for which message.
1833 * Let's hope it's simpler to implement for dissecting only.
1835 * Also need to find the extended address of the sender.
1837 if (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) {
1838 /* The source EUI-64 is included in the headers. */
1839 srcAddr = packet->src64;
1841 else if (ieee_hints && ieee_hints->map_rec && ieee_hints->map_rec->addr64) {
1842 /* Use the hint */
1843 srcAddr = ieee_hints->map_rec->addr64;
1845 else {
1846 /* Lookup failed. */
1847 *status = DECRYPT_PACKET_NO_EXT_SRC_ADDR;
1848 return NULL;
1851 /* Lookup the key. */
1853 * TODO: What this dissector really needs is a UAT to store multiple keys
1854 * and a variety of key configuration data. However, a single shared key
1855 * should be sufficient to get packet encryption off to a start.
1857 if (!ieee802154_key_valid) {
1858 *status = DECRYPT_PACKET_NO_KEY;
1859 return NULL;
1861 memcpy(key, ieee802154_key, IEEE802154_CIPHER_SIZE);
1863 /*=====================================================
1864 * CCM* - CTR mode payload encryption
1865 *=====================================================
1867 /* Create the CCM* initial block for decryption (Adata=0, M=0, counter=0). */
1868 ccm_init_block(tmp, FALSE, 0, srcAddr, packet, 0);
1870 /* Decrypt the ciphertext, and place the plaintext in a new tvb. */
1871 if (IEEE802154_IS_ENCRYPTED(packet->security_level) && captured_len) {
1872 guint8 * text;
1874 * Make a copy of the ciphertext in heap memory.
1876 * We will decrypt the message in-place and then use the buffer as the
1877 * real data for the new tvb.
1879 text = (guint8 *)tvb_memdup(NULL, tvb, offset, captured_len);
1881 /* Perform CTR-mode transformation. */
1882 if (!ccm_ctr_encrypt(key, tmp, rx_mic, text, captured_len)) {
1883 g_free(text);
1884 *status = DECRYPT_PACKET_DECRYPT_FAILED;
1885 return NULL;
1888 /* Create a tvbuff for the plaintext. */
1889 ptext_tvb = tvb_new_child_real_data(tvb, text, captured_len, reported_len);
1890 tvb_set_free_cb(ptext_tvb, g_free);
1891 add_new_data_source(pinfo, ptext_tvb, "Decrypted IEEE 802.15.4 payload");
1892 *status = DECRYPT_PACKET_SUCCEEDED;
1894 /* There is no ciphertext. Wrap the plaintext in a new tvb. */
1895 else {
1896 /* Decrypt the MIC (if present). */
1897 if ((have_mic) && (!ccm_ctr_encrypt(key, tmp, rx_mic, NULL, 0))) {
1898 *status = DECRYPT_PACKET_DECRYPT_FAILED;
1899 return NULL;
1902 /* Create a tvbuff for the plaintext. This might result in a zero-length tvbuff. */
1903 ptext_tvb = tvb_new_subset(tvb, offset, captured_len, reported_len);
1904 *status = DECRYPT_PACKET_SUCCEEDED;
1907 /*=====================================================
1908 * CCM* - CBC-mode message authentication
1909 *=====================================================
1911 /* We can only verify the message if the MIC wasn't truncated. */
1912 if (have_mic) {
1913 unsigned char dec_mic[16];
1914 guint l_m = captured_len;
1915 guint l_a = offset;
1917 /* Adjust the lengths of the plantext and additional data if unencrypted. */
1918 if (!IEEE802154_IS_ENCRYPTED(packet->security_level)) {
1919 l_a += l_m;
1920 l_m = 0;
1922 else if ((packet->version == IEEE802154_VERSION_2003) && !ieee802154_extend_auth)
1923 l_a -= 5; /* Exclude Frame Counter (4 bytes) and Key Sequence Counter (1 byte) from authentication data */
1926 /* Create the CCM* initial block for authentication (Adata!=0, M!=0, counter=l(m)). */
1927 ccm_init_block(tmp, TRUE, M, srcAddr, packet, l_m);
1929 /* Compute CBC-MAC authentication tag. */
1931 * And yes, despite the warning in tvbuff.h, I think tvb_get_ptr is the
1932 * right function here since either A) the payload wasn't encrypted, in
1933 * which case l_m is zero, or B) the payload was encrypted, and the tvb
1934 * already points to contiguous memory, since we just allocated it in
1935 * decryption phase.
1937 if (!ccm_cbc_mac(key, tmp, (const gchar *)tvb_memdup(wmem_packet_scope(), tvb, 0, l_a), l_a, tvb_get_ptr(ptext_tvb, 0, l_m), l_m, dec_mic)) {
1938 *status = DECRYPT_PACKET_MIC_CHECK_FAILED;
1940 /* Compare the received MIC with the one we generated. */
1941 else if (memcmp(rx_mic, dec_mic, M) != 0) {
1942 *status = DECRYPT_PACKET_MIC_CHECK_FAILED;
1946 /* Done! */
1947 return ptext_tvb;
1948 } /* dissect_ieee802154_decrypt */
1950 /*FUNCTION:------------------------------------------------------
1951 * NAME
1952 * ccm_init_block
1953 * DESCRIPTION
1954 * Creates the CCM* initial block value for IEEE 802.15.4.
1955 * PARAMETERS
1956 * gchar *block - Output pointer for the initial block.
1957 * gboolean adata - TRUE if additional auth data is present
1958 * gint M - CCM* parameter M.
1959 * guint64 addr - Source extended address.
1960 * ieee802154_packet *packet - IEEE 802.15.4 packet information.
1961 * guint16 ctr_val - Value in the last L bytes of the block.
1962 * RETURNS
1963 * void
1964 *---------------------------------------------------------------
1966 static void
1967 ccm_init_block(gchar *block, gboolean adata, gint M, guint64 addr, ieee802154_packet * packet, gint ctr_val)
1969 gint i = 0;
1971 /* Flags: Reserved(0) || Adata || (M-2)/2 || (L-1) */
1972 block[i] = (0x2 - 1); /* (L-1) */
1973 if (M > 0) block[i] |= (((M-2)/2) << 3); /* (M-2)/2 */
1974 if (adata) block[i] |= (1 << 6); /* Adata */
1975 i++;
1976 /* 2003 CCM Nonce: Source Address || Frame Counter || Key Sequence Counter */
1977 /* 2006 CCM* Nonce: Source Address || Frame Counter || Security Level */
1978 block[i++] = (guint8)((addr >> 56) & 0xff);
1979 block[i++] = (guint8)((addr >> 48) & 0xff);
1980 block[i++] = (guint8)((addr >> 40) & 0xff);
1981 block[i++] = (guint8)((addr >> 32) & 0xff);
1982 block[i++] = (guint8)((addr >> 24) & 0xff);
1983 block[i++] = (guint8)((addr >> 16) & 0xff);
1984 block[i++] = (guint8)((addr >> 8) & 0xff);
1985 block[i++] = (guint8)((addr >> 0) & 0xff);
1986 block[i++] = (guint8)((packet->frame_counter >> 24) & 0xff);
1987 block[i++] = (guint8)((packet->frame_counter >> 16) & 0xff);
1988 block[i++] = (guint8)((packet->frame_counter >> 8) & 0xff);
1989 block[i++] = (guint8)((packet->frame_counter >> 0) & 0xff);
1990 if (packet->version == IEEE802154_VERSION_2003)
1991 block[i++] = packet->key_sequence_counter;
1992 else
1993 block[i++] = packet->security_level;
1994 /* Plaintext length. */
1995 block[i++] = (guint8)((ctr_val >> 8) & 0xff);
1996 block[i] = (guint8)((ctr_val >> 0) & 0xff);
1997 } /* ccm_init_block */
1999 /*FUNCTION:------------------------------------------------------
2000 * NAME
2001 * ccm_ctr_encrypt
2002 * DESCRIPTION
2003 * Performs an in-place CTR-mode encryption/decryption.
2004 * PARAMETERS
2005 * const gchar *key - Encryption Key.
2006 * const gchar *iv - Counter initial value.
2007 * gchar *mic - MIC to encrypt/decrypt.
2008 * gchar *data - Buffer to encrypt/decrypt.
2009 * gint length - Length of the buffer.
2010 * RETURNS
2011 * gboolean - TRUE on SUCCESS, FALSE on error.
2012 *---------------------------------------------------------------
2014 static gboolean
2015 ccm_ctr_encrypt(const gchar *key _U_, const gchar *iv _U_, gchar *mic _U_, gchar *data _U_, gint length _U_)
2017 #ifdef HAVE_LIBGCRYPT
2018 gcry_cipher_hd_t cipher_hd;
2020 /* Open the cipher. */
2021 if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0)) {
2022 return FALSE;
2025 /* Set the key and initial value. */
2026 if (gcry_cipher_setkey(cipher_hd, key, 16)) {
2027 gcry_cipher_close(cipher_hd);
2028 return FALSE;
2030 if (gcry_cipher_setctr(cipher_hd, iv, 16)) {
2031 gcry_cipher_close(cipher_hd);
2032 return FALSE;
2035 /* Decrypt the MIC. */
2036 if (gcry_cipher_encrypt(cipher_hd, mic, 16, NULL, 0)) {
2037 gcry_cipher_close(cipher_hd);
2038 return FALSE;
2040 /* Decrypt the payload. */
2041 if (gcry_cipher_encrypt(cipher_hd, data, length, NULL, 0)) {
2042 gcry_cipher_close(cipher_hd);
2043 return FALSE;
2046 /* Done with the cipher. */
2047 gcry_cipher_close(cipher_hd);
2048 return TRUE;
2049 #else
2050 return FALSE;
2051 #endif
2052 } /* ccm_ctr_encrypt */
2054 /*FUNCTION:------------------------------------------------------
2055 * NAME
2056 * ccm_cbc_mac
2057 * DESCRIPTION
2058 * Generates a CBC-MAC of the decrypted payload and additional
2059 * authentication headers.
2060 * PARAMETERS
2061 * const gchar key - Encryption Key.
2062 * const gchar iv - Counter initial value.
2063 * const gchar a - Additional auth headers.
2064 * gint a_len - Length of the additional headers.
2065 * const gchar m - Plaintext message.
2066 * gint m_len - Length of plaintext message.
2067 * gchar *mic - Output for CBC-MAC.
2068 * RETURNS
2069 * gboolean - TRUE on SUCCESS, FALSE on error.
2070 *---------------------------------------------------------------
2072 static gboolean
2073 ccm_cbc_mac(const gchar *key _U_, const gchar *iv _U_, const gchar *a _U_, gint a_len _U_, const gchar *m _U_, gint m_len _U_, gchar *mic _U_)
2075 #ifdef HAVE_LIBGCRYPT
2076 gcry_cipher_hd_t cipher_hd;
2077 guint i = 0;
2078 unsigned char block[16];
2080 /* Open the cipher. */
2081 if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_MAC)) return FALSE;
2083 /* Set the key. */
2084 if (gcry_cipher_setkey(cipher_hd, key, 16)) {
2085 gcry_cipher_close(cipher_hd);
2086 return FALSE;
2089 /* Process the initial value. */
2090 if (gcry_cipher_encrypt(cipher_hd, mic, 16, iv, 16)) {
2091 gcry_cipher_close(cipher_hd);
2092 return FALSE;
2095 /* Encode L(a) */
2096 i = 0;
2097 #if (GINT_MAX >= (1LL << 32))
2098 if (a_len >= (1LL << 32)) {
2099 block[i++] = 0xff;
2100 block[i++] = 0xff;
2101 block[i++] = (a_len >> 56) & 0xff;
2102 block[i++] = (a_len >> 48) & 0xff;
2103 block[i++] = (a_len >> 40) & 0xff;
2104 block[i++] = (a_len >> 32) & 0xff;
2105 block[i++] = (a_len >> 24) & 0xff;
2106 block[i++] = (a_len >> 16) & 0xff;
2107 block[i++] = (a_len >> 8) & 0xff;
2108 block[i++] = (a_len >> 0) & 0xff;
2110 else
2111 #endif
2112 if (a_len >= ((1 << 16) - (1 << 8))) {
2113 block[i++] = 0xff;
2114 block[i++] = 0xfe;
2115 block[i++] = (a_len >> 24) & 0xff;
2116 block[i++] = (a_len >> 16) & 0xff;
2117 block[i++] = (a_len >> 8) & 0xff;
2118 block[i++] = (a_len >> 0) & 0xff;
2120 else {
2121 block[i++] = (a_len >> 8) & 0xff;
2122 block[i++] = (a_len >> 0) & 0xff;
2124 /* Append a to get the first block of input (pad if we encounter the end of a). */
2125 while ((i < sizeof(block)) && (a_len-- > 0)) block[i++] = *a++;
2126 while (i < sizeof(block)) block[i++] = 0;
2128 /* Process the first block of AuthData. */
2129 if (gcry_cipher_encrypt(cipher_hd, mic, 16, block, 16)) {
2130 gcry_cipher_close(cipher_hd);
2131 return FALSE;
2134 /* Transform and process the remainder of a. */
2135 while (a_len > 0) {
2136 /* Copy and pad. */
2137 if ((guint)a_len >= sizeof(block)) memcpy(block, a, sizeof(block));
2138 else {memcpy(block, a, a_len); memset(block+a_len, 0, sizeof(block)-a_len);}
2139 /* Adjust pointers. */
2140 a += sizeof(block);
2141 a_len -= (int)sizeof(block);
2142 /* Execute the CBC-MAC algorithm. */
2143 if (gcry_cipher_encrypt(cipher_hd, mic, 16, block, sizeof(block))) {
2144 gcry_cipher_close(cipher_hd);
2145 return FALSE;
2147 } /* while */
2149 /* Process the message, m. */
2150 while (m_len > 0) {
2151 /* Copy and pad. */
2152 if ((guint)m_len >= sizeof(block)) memcpy(block, m, sizeof(block));
2153 else {memcpy(block, m, m_len); memset(block+m_len, 0, sizeof(block)-m_len);}
2154 /* Adjust pointers. */
2155 m += sizeof(block);
2156 m_len -= (int)sizeof(block);
2157 /* Execute the CBC-MAC algorithm. */
2158 if (gcry_cipher_encrypt(cipher_hd, mic, 16, block, sizeof(block))) {
2159 gcry_cipher_close(cipher_hd);
2160 return FALSE;
2164 /* Done with the cipher. */
2165 gcry_cipher_close(cipher_hd);
2166 return TRUE;
2167 #else
2168 return FALSE;
2169 #endif
2170 } /* ccm_cbc_mac */
2172 /* Key hash function. */
2173 guint ieee802154_short_addr_hash(gconstpointer key)
2175 return (((ieee802154_short_addr *)key)->addr) | (((ieee802154_short_addr *)key)->pan << 16);
2178 /* Key equal function. */
2179 gboolean ieee802154_short_addr_equal(gconstpointer a, gconstpointer b)
2181 return (((ieee802154_short_addr *)a)->pan == ((ieee802154_short_addr *)b)->pan) &&
2182 (((ieee802154_short_addr *)a)->addr == ((ieee802154_short_addr *)b)->addr);
2185 /* Key hash function. */
2186 guint ieee802154_long_addr_hash(gconstpointer key)
2188 return (guint)(((ieee802154_long_addr *)key)->addr) & 0xFFFFFFFF;
2191 /* Key equal function. */
2192 gboolean ieee802154_long_addr_equal(gconstpointer a, gconstpointer b)
2194 return (((ieee802154_long_addr *)a)->addr == ((ieee802154_long_addr *)b)->addr);
2197 /*FUNCTION:------------------------------------------------------
2198 * NAME
2199 * ieee802154_addr_update
2200 * DESCRIPTION
2201 * Creates a record that maps the given short address and pan
2202 * to a long (extended) address.
2203 * PARAMETERS
2204 * guint16 short_addr - 16-bit short address
2205 * guint16 pan - 16-bit PAN id
2206 * guint64 long_addr - 64-bit long (extended) address
2207 * const char * - Pointer to name of current protocol
2208 * guint - Frame number this mapping became valid
2209 * RETURNS
2210 * TRUE - Record was updated
2211 * FALSE - Couldn't find it
2212 *---------------------------------------------------------------
2214 ieee802154_map_rec *ieee802154_addr_update(ieee802154_map_tab_t *au_ieee802154_map,
2215 guint16 short_addr, guint16 pan, guint64 long_addr, const char *proto, guint fnum)
2217 ieee802154_short_addr addr16;
2218 ieee802154_map_rec *p_map_rec;
2219 gpointer old_key;
2221 /* Look up short address hash */
2222 addr16.pan = pan;
2223 addr16.addr = short_addr;
2224 p_map_rec = (ieee802154_map_rec *)g_hash_table_lookup(au_ieee802154_map->short_table, &addr16);
2226 /* Update mapping record */
2227 if (p_map_rec) {
2228 /* record already exists */
2229 if ( p_map_rec->addr64 == long_addr ) {
2230 /* no change */
2231 return p_map_rec;
2233 else {
2234 /* mark current mapping record invalid */
2235 p_map_rec->end_fnum = fnum;
2239 /* create a new mapping record */
2240 p_map_rec = wmem_new(wmem_file_scope(), ieee802154_map_rec);
2241 p_map_rec->proto = proto;
2242 p_map_rec->start_fnum = fnum;
2243 p_map_rec->end_fnum = 0;
2244 p_map_rec->addr64 = long_addr;
2246 /* link new mapping record to addr hash tables */
2247 if ( g_hash_table_lookup_extended(au_ieee802154_map->short_table, &addr16, &old_key, NULL) ) {
2248 /* update short addr hash table, reusing pointer to old key */
2249 g_hash_table_insert(au_ieee802154_map->short_table, old_key, p_map_rec);
2250 } else {
2251 /* create new hash entry */
2252 g_hash_table_insert(au_ieee802154_map->short_table, wmem_memdup(wmem_file_scope(), &addr16, sizeof(addr16)), p_map_rec);
2255 if ( g_hash_table_lookup_extended(au_ieee802154_map->long_table, &long_addr, &old_key, NULL) ) {
2256 /* update long addr hash table, reusing pointer to old key */
2257 g_hash_table_insert(au_ieee802154_map->long_table, old_key, p_map_rec);
2258 } else {
2259 /* create new hash entry */
2260 g_hash_table_insert(au_ieee802154_map->long_table, wmem_memdup(wmem_file_scope(), &long_addr, sizeof(long_addr)), p_map_rec);
2263 return p_map_rec;
2264 } /* ieee802154_addr_update */
2266 /*FUNCTION:------------------------------------------------------
2267 * NAME
2268 * ieee802154_short_addr_invalidate
2269 * DESCRIPTION
2270 * Marks a mapping record associated with device with short_addr
2271 * as invalid at a certain frame number, typically when a
2272 * dissassociation occurs.
2273 * PARAMETERS
2274 * guint16 short_addr - 16-bit short address
2275 * guint16 pan - 16-bit PAN id
2276 * guint - Frame number when mapping became invalid
2277 * RETURNS
2278 * TRUE - Record was updated
2279 * FALSE - Couldn't find it
2280 *---------------------------------------------------------------
2282 gboolean ieee802154_short_addr_invalidate(guint16 short_addr, guint16 pan, guint fnum)
2284 ieee802154_short_addr addr16;
2285 ieee802154_map_rec *map_rec;
2287 addr16.pan = pan;
2288 addr16.addr = short_addr;
2290 map_rec = (ieee802154_map_rec *)g_hash_table_lookup(ieee802154_map.short_table, &addr16);
2291 if ( map_rec ) {
2292 /* indicates this mapping is invalid at frame fnum */
2293 map_rec->end_fnum = fnum;
2294 return TRUE;
2297 return FALSE;
2298 } /* ieee802154_short_addr_invalidate */
2300 /*FUNCTION:------------------------------------------------------
2301 * NAME
2302 * ieee802154_long_addr_invalidate
2303 * DESCRIPTION
2304 * Marks a mapping record associated with device with long_addr
2305 * as invalid at a certain frame number, typically when a
2306 * dissassociation occurs.
2307 * PARAMETERS
2308 * guint64 long_addr - 16-bit short address
2309 * guint - Frame number when mapping became invalid
2310 * RETURNS
2311 * TRUE - If record was updated
2312 * FALSE - If record wasn't updated
2313 *---------------------------------------------------------------
2315 gboolean ieee802154_long_addr_invalidate(guint64 long_addr, guint fnum)
2317 ieee802154_map_rec *map_rec;
2319 map_rec = (ieee802154_map_rec *)g_hash_table_lookup(ieee802154_map.long_table, &long_addr);
2320 if ( map_rec ) {
2321 /* indicates this mapping is invalid at frame fnum */
2322 map_rec->end_fnum = fnum;
2323 return TRUE;
2326 return FALSE;
2327 } /* ieee802154_long_addr_invalidate */
2330 /*FUNCTION:------------------------------------------------------
2331 * NAME
2332 * proto_init_ieee802154
2333 * DESCRIPTION
2334 * Init routine for the IEEE 802.15.4 dissector. Creates hash
2335 * tables for mapping between 16-bit to 64-bit addresses and
2336 * populates them with static address pairs from a UAT
2337 * preference table.
2338 * PARAMETERS
2339 * none
2340 * RETURNS
2341 * void
2342 *---------------------------------------------------------------
2344 static void
2345 proto_init_ieee802154(void)
2347 guint i;
2349 /* Destroy hash tables, if they exist. */
2350 if (ieee802154_map.short_table)
2351 g_hash_table_destroy(ieee802154_map.short_table);
2352 if (ieee802154_map.long_table)
2353 g_hash_table_destroy(ieee802154_map.long_table);
2355 /* Create the hash tables. */
2356 ieee802154_map.short_table = g_hash_table_new(ieee802154_short_addr_hash, ieee802154_short_addr_equal);
2357 ieee802154_map.long_table = g_hash_table_new(ieee802154_long_addr_hash, ieee802154_long_addr_equal);
2358 /* Re-load the hash table from the static address UAT. */
2359 for (i=0; (i<num_static_addrs) && (static_addrs); i++) {
2360 ieee802154_addr_update(&ieee802154_map,(guint16)static_addrs[i].addr16, (guint16)static_addrs[i].pan,
2361 pntoh64(static_addrs[i].eui64), ieee802154_user, IEEE802154_USER_MAPPING);
2362 } /* for */
2363 } /* proto_init_ieee802154 */
2366 /*FUNCTION:------------------------------------------------------
2367 * NAME
2368 * proto_register_ieee802154
2369 * DESCRIPTION
2370 * IEEE 802.15.4 protocol registration routine.
2371 * PARAMETERS
2372 * none
2373 * RETURNS
2374 * void
2375 *---------------------------------------------------------------
2377 void proto_register_ieee802154(void)
2379 /* Protocol fields */
2380 static hf_register_info hf_phy[] = {
2381 /* PHY level */
2383 { &hf_ieee802154_nonask_phy_preamble,
2384 { "Preamble", "wpan-nonask-phy.preamble", FT_UINT32, BASE_HEX, NULL, 0x0,
2385 NULL, HFILL }},
2387 { &hf_ieee802154_nonask_phy_sfd,
2388 { "Start of Frame Delimiter", "wpan-nonask-phy.sfd", FT_UINT8, BASE_HEX, NULL, 0x0,
2389 NULL, HFILL }},
2391 { &hf_ieee802154_nonask_phy_length,
2392 { "Frame Length", "wpan-nonask-phy.frame_length", FT_UINT8, BASE_HEX, NULL,
2393 IEEE802154_PHY_LENGTH_MASK, NULL, HFILL }},
2396 static hf_register_info hf[] = {
2398 { &hf_ieee802154_frame_length,
2399 { "Frame Length", "wpan.frame_length", FT_UINT8, BASE_DEC, NULL, 0x0,
2400 "Frame Length as reported from lower layer", HFILL }},
2402 { &hf_ieee802154_frame_type,
2403 { "Frame Type", "wpan.frame_type", FT_UINT16, BASE_HEX, VALS(ieee802154_frame_types),
2404 IEEE802154_FCF_TYPE_MASK, NULL, HFILL }},
2406 { &hf_ieee802154_security,
2407 { "Security Enabled", "wpan.security", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_SEC_EN,
2408 "Whether security operations are performed at the MAC layer or not.", HFILL }},
2410 { &hf_ieee802154_pending,
2411 { "Frame Pending", "wpan.pending", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_FRAME_PND,
2412 "Indication of additional packets waiting to be transferred from the source device.", HFILL }},
2414 { &hf_ieee802154_ack_request,
2415 { "Acknowledge Request", "wpan.ack_request", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_ACK_REQ,
2416 "Whether the sender of this packet requests acknowledgement or not.", HFILL }},
2418 { &hf_ieee802154_intra_pan,
2419 { "Intra-PAN", "wpan.intra_pan", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_INTRA_PAN,
2420 "Whether this packet originated and terminated within the same PAN or not.", HFILL }},
2422 { &hf_ieee802154_seqno,
2423 { "Sequence Number", "wpan.seq_no", FT_UINT8, BASE_DEC, NULL, 0x0,
2424 NULL, HFILL }},
2426 { &hf_ieee802154_dst_addr_mode,
2427 { "Destination Addressing Mode", "wpan.dst_addr_mode", FT_UINT16, BASE_HEX, VALS(ieee802154_addr_modes),
2428 IEEE802154_FCF_DADDR_MASK, NULL, HFILL }},
2430 { &hf_ieee802154_src_addr_mode,
2431 { "Source Addressing Mode", "wpan.src_addr_mode", FT_UINT16, BASE_HEX, VALS(ieee802154_addr_modes),
2432 IEEE802154_FCF_SADDR_MASK, NULL, HFILL }},
2434 { &hf_ieee802154_version,
2435 { "Frame Version", "wpan.version", FT_UINT16, BASE_DEC, NULL, IEEE802154_FCF_VERSION,
2436 NULL, HFILL }},
2438 { &hf_ieee802154_dst_panID,
2439 { "Destination PAN", "wpan.dst_pan", FT_UINT16, BASE_HEX, NULL, 0x0,
2440 NULL, HFILL }},
2442 { &hf_ieee802154_dst16,
2443 { "Destination", "wpan.dst16", FT_UINT16, BASE_HEX, NULL, 0x0,
2444 NULL, HFILL }},
2446 { &hf_ieee802154_dst64,
2447 { "Destination", "wpan.dst64", FT_EUI64, BASE_NONE, NULL, 0x0,
2448 NULL, HFILL }},
2450 { &hf_ieee802154_src_panID,
2451 { "Source PAN", "wpan.src_pan", FT_UINT16, BASE_HEX, NULL, 0x0,
2452 NULL, HFILL }},
2454 { &hf_ieee802154_src16,
2455 { "Source", "wpan.src16", FT_UINT16, BASE_HEX, NULL, 0x0,
2456 NULL, HFILL }},
2458 { &hf_ieee802154_src64,
2459 { "Extended Source", "wpan.src64", FT_EUI64, BASE_NONE, NULL, 0x0,
2460 NULL, HFILL }},
2462 { &hf_ieee802154_src64_origin,
2463 { "Origin", "wpan.src64.origin", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2464 NULL, HFILL }},
2466 { &hf_ieee802154_fcs,
2467 { "FCS", "wpan.fcs", FT_UINT16, BASE_HEX, NULL, 0x0,
2468 NULL, HFILL }},
2470 { &hf_ieee802154_rssi,
2471 { "RSSI", "wpan.rssi", FT_INT8, BASE_DEC, NULL, 0x0,
2472 "Received Signal Strength", HFILL }},
2474 { &hf_ieee802154_fcs_ok,
2475 { "FCS Valid", "wpan.fcs_ok", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2476 NULL, HFILL }},
2478 { &hf_ieee802154_correlation,
2479 { "LQI Correlation Value", "wpan.correlation", FT_UINT8, BASE_DEC, NULL, 0x0,
2480 NULL, HFILL }},
2482 /* Command Frame Specific Fields */
2483 /*--------------------------------*/
2485 { &hf_ieee802154_cmd_id,
2486 { "Command Identifier", "wpan.cmd", FT_UINT8, BASE_HEX, VALS(ieee802154_cmd_names), 0x0,
2487 NULL, HFILL }},
2489 /* Capability Information Fields */
2490 { &hf_ieee802154_cinfo_alt_coord,
2491 { "Alternate PAN Coordinator", "wpan.cinfo.alt_coord", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALT_PAN_COORD,
2492 "Whether this device can act as a PAN coordinator or not.", HFILL }},
2494 { &hf_ieee802154_cinfo_device_type,
2495 { "Device Type", "wpan.cinfo.device_type", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_DEVICE_TYPE,
2496 "Whether this device is RFD (reduced-function device) or FFD (full-function device).", HFILL }},
2498 { &hf_ieee802154_cinfo_power_src,
2499 { "Power Source", "wpan.cinfo.power_src", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_POWER_SRC,
2500 "Whether this device is operating on AC/mains or battery power.", HFILL }},
2502 { &hf_ieee802154_cinfo_idle_rx,
2503 { "Receive On When Idle", "wpan.cinfo.idle_rx", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_IDLE_RX,
2504 "Whether this device can receive packets while idle or not.", HFILL }},
2506 { &hf_ieee802154_cinfo_sec_capable,
2507 { "Security Capability", "wpan.cinfo.sec_capable", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_SEC_CAPABLE,
2508 "Whether this device is capable of receiving encrypted packets.", HFILL }},
2510 { &hf_ieee802154_cinfo_alloc_addr,
2511 { "Allocate Address", "wpan.cinfo.alloc_addr", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALLOC_ADDR,
2512 "Whether this device wishes to use a 16-bit short address instead of its IEEE 802.15.4 64-bit long address.", HFILL }},
2514 /* Association response fields */
2515 { &hf_ieee802154_assoc_addr,
2516 { "Short Address", "wpan.asoc.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
2517 "The short address that the device should assume. An address of 0xfffe indicates that the device should use its IEEE 64-bit long address.", HFILL }},
2519 { &hf_ieee802154_assoc_status,
2520 { "Association Status", "wpan.assoc.status", FT_UINT8, BASE_HEX, NULL, 0x0,
2521 NULL, HFILL }},
2523 { &hf_ieee802154_disassoc_reason,
2524 { "Disassociation Reason", "wpan.disassoc.reason", FT_UINT8, BASE_HEX, NULL, 0x0,
2525 NULL, HFILL }},
2527 /* Coordinator Realignment fields */
2528 { &hf_ieee802154_realign_pan,
2529 { "PAN ID", "wpan.realign.pan", FT_UINT16, BASE_HEX, NULL, 0x0,
2530 "The PAN identifier the coordinator wishes to use for future communication.", HFILL }},
2532 { &hf_ieee802154_realign_caddr,
2533 { "Coordinator Short Address", "wpan.realign.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
2534 "The 16-bit address the coordinator wishes to use for future communication.", HFILL }},
2536 { &hf_ieee802154_realign_channel,
2537 { "Logical Channel", "wpan.realign.channel", FT_UINT8, BASE_DEC, NULL, 0x0,
2538 "The logical channel the coordinator wishes to use for future communication.", HFILL }},
2540 { &hf_ieee802154_realign_addr,
2541 { "Short Address", "wpan.realign.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
2542 "A short-address that the orphaned device shall assume if applicable.", HFILL }},
2544 { &hf_ieee802154_realign_channel_page,
2545 { "Channel Page", "wpan.realign.channel_page", FT_UINT8, BASE_DEC, NULL, 0x0,
2546 "The logical channel page the coordinator wishes to use for future communication.", HFILL }},
2548 { &hf_ieee802154_gtsreq_len,
2549 { "GTS Length", "wpan.gtsreq.length", FT_UINT8, BASE_DEC, NULL, IEEE802154_CMD_GTS_REQ_LEN,
2550 "Number of superframe slots the device is requesting.", HFILL }},
2552 { &hf_ieee802154_gtsreq_dir,
2553 { "GTS Direction", "wpan.gtsreq.direction", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_GTS_REQ_DIR,
2554 "The direction of traffic in the guaranteed timeslot.", HFILL }},
2556 { &hf_ieee802154_gtsreq_type,
2557 { "Characteristic Type", "wpan.gtsreq.type", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_GTS_REQ_TYPE,
2558 "Whether this request is to allocate or deallocate a timeslot.", HFILL }},
2560 /* Beacon Frame Specific Fields */
2561 /*-------------------------------*/
2562 { &hf_ieee802154_beacon_order,
2563 { "Beacon Interval", "wpan.beacon_order", FT_UINT16, BASE_DEC, NULL, IEEE802154_BEACON_ORDER_MASK,
2564 "Specifies the transmission interval of the beacons.", HFILL }},
2566 { &hf_ieee802154_superframe_order,
2567 { "Superframe Interval", "wpan.superframe_order", FT_UINT16, BASE_DEC, NULL,
2568 IEEE802154_SUPERFRAME_ORDER_MASK,
2569 "Specifies the length of time the coordinator will interact with the PAN.", HFILL }},
2571 { &hf_ieee802154_cap,
2572 { "Final CAP Slot", "wpan.cap", FT_UINT16, BASE_DEC, NULL, IEEE802154_SUPERFRAME_CAP_MASK,
2573 "Specifies the final superframe slot used by the CAP.", HFILL }},
2575 { &hf_ieee802154_superframe_battery_ext,
2576 { "Battery Extension", "wpan.battery_ext", FT_BOOLEAN, 16, NULL, IEEE802154_BATT_EXTENSION_MASK,
2577 "Whether transmissions may not extend past the length of the beacon frame.", HFILL }},
2579 { &hf_ieee802154_superframe_coord,
2580 { "PAN Coordinator", "wpan.bcn_coord", FT_BOOLEAN, 16, NULL, IEEE802154_SUPERFRAME_COORD_MASK,
2581 "Whether this beacon frame is being transmitted by the PAN coordinator or not.", HFILL }},
2583 { &hf_ieee802154_assoc_permit,
2584 { "Association Permit", "wpan.assoc_permit", FT_BOOLEAN, 16, NULL, IEEE802154_ASSOC_PERMIT_MASK,
2585 "Whether this PAN is accepting association requests or not.", HFILL }},
2587 { &hf_ieee802154_gts_count,
2588 { "GTS Descriptor Count", "wpan.gts.count", FT_UINT8, BASE_DEC, NULL, 0x0,
2589 "The number of GTS descriptors present in this beacon frame.", HFILL }},
2591 { &hf_ieee802154_gts_permit,
2592 { "GTS Permit", "wpan.gts.permit", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2593 "Whether the PAN coordinator is accepting GTS requests or not.", HFILL }},
2595 { &hf_ieee802154_gts_direction,
2596 { "Direction", "wpan.gts.direction", FT_BOOLEAN, BASE_NONE, TFS(&ieee802154_gts_direction_tfs), 0x0,
2597 "A flag defining the direction of the GTS Slot.", HFILL }},
2599 { &hf_ieee802154_pending16,
2600 { "Address", "wpan.pending16", FT_UINT16, BASE_HEX, NULL, 0x0,
2601 "Device with pending data to receive.", HFILL }},
2603 { &hf_ieee802154_pending64,
2604 { "Address", "wpan.pending64", FT_EUI64, BASE_NONE, NULL, 0x0,
2605 "Device with pending data to receive.", HFILL }},
2607 /* Auxiliary Security Header Fields */
2608 /*----------------------------------*/
2609 { &hf_ieee802154_security_level,
2610 { "Security Level", "wpan.aux_sec.sec_level", FT_UINT8, BASE_HEX, VALS(ieee802154_sec_level_names),
2611 IEEE802154_AUX_SEC_LEVEL_MASK, "The Security Level of the frame", HFILL }},
2613 { &hf_ieee802154_key_id_mode,
2614 { "Key Identifier Mode", "wpan.aux_sec.key_id_mode", FT_UINT8, BASE_HEX, VALS(ieee802154_key_id_mode_names),
2615 IEEE802154_AUX_KEY_ID_MODE_MASK,
2616 "The scheme to use by the recipient to lookup the key in its key table", HFILL }},
2618 { &hf_ieee802154_aux_sec_reserved,
2619 { "Reserved", "wpan.aux_sec.reserved", FT_UINT8, BASE_HEX, NULL, IEEE802154_AUX_KEY_RESERVED_MASK,
2620 NULL, HFILL }},
2622 { &hf_ieee802154_aux_sec_frame_counter,
2623 { "Frame Counter", "wpan.aux_sec.frame_counter", FT_UINT32, BASE_DEC, NULL, 0x0,
2624 "Frame counter of the originator of the protected frame", HFILL }},
2626 { &hf_ieee802154_aux_sec_key_source,
2627 { "Key Source", "wpan.aux_sec.key_source", FT_UINT64, BASE_HEX, NULL, 0x0,
2628 "Key Source for processing of the protected frame", HFILL }},
2630 { &hf_ieee802154_aux_sec_key_index,
2631 { "Key Index", "wpan.aux_sec.key_index", FT_UINT8, BASE_HEX, NULL, 0x0,
2632 "Key Index for processing of the protected frame", HFILL }},
2634 /* IEEE 802.15.4-2003 Security Header Fields */
2635 { &hf_ieee802154_sec_frame_counter,
2636 { "Frame Counter", "wpan.sec_frame_counter", FT_UINT32, BASE_HEX, NULL, 0x0,
2637 "Frame counter of the originator of the protected frame (802.15.4-2003)", HFILL }},
2639 { &hf_ieee802154_sec_key_sequence_counter,
2640 { "Key Sequence Counter", "wpan.sec_key_sequence_counter", FT_UINT8, BASE_HEX, NULL, 0x0,
2641 "Key Sequence counter of the originator of the protected frame (802.15.4-2003)", HFILL }}
2644 /* Subtrees */
2645 static gint *ett[] = {
2646 &ett_ieee802154_nonask_phy,
2647 &ett_ieee802154_nonask_phy_phr,
2648 &ett_ieee802154,
2649 &ett_ieee802154_fcf,
2650 &ett_ieee802154_auxiliary_security,
2651 &ett_ieee802154_aux_sec_control,
2652 &ett_ieee802154_aux_sec_key_id,
2653 &ett_ieee802154_fcs,
2654 &ett_ieee802154_cmd,
2655 &ett_ieee802154_superframe,
2656 &ett_ieee802154_gts,
2657 &ett_ieee802154_gts_direction,
2658 &ett_ieee802154_gts_descriptors,
2659 &ett_ieee802154_pendaddr
2662 static ei_register_info ei[] = {
2663 { &ei_ieee802154_invalid_addressing, { "wpan.invalid_addressing", PI_MALFORMED, PI_WARN, "Invalid Addressing", EXPFILL }},
2664 { &ei_ieee802154_dst, { "wpan.dst_invalid", PI_MALFORMED, PI_ERROR, "Invalid Destination Address Mode", EXPFILL }},
2665 { &ei_ieee802154_src, { "wpan.src_invalid", PI_MALFORMED, PI_ERROR, "Invalid Source Address Mode", EXPFILL }},
2666 { &ei_ieee802154_decrypt_error, { "wpan.decrypt_error", PI_UNDECODED, PI_WARN, "Decryption error", EXPFILL }},
2667 { &ei_ieee802154_fcs, { "wpan.fcs.bad", PI_CHECKSUM, PI_WARN, "Bad FCS", EXPFILL }},
2670 /* Preferences. */
2671 module_t *ieee802154_module;
2672 expert_module_t* expert_ieee802154;
2674 static uat_field_t addr_uat_flds[] = {
2675 UAT_FLD_HEX(addr_uat,addr16,"Short Address",
2676 "16-bit short address in hexadecimal."),
2677 UAT_FLD_HEX(addr_uat,pan,"PAN Identifier",
2678 "16-bit PAN identifier in hexadecimal."),
2679 UAT_FLD_BUFFER(addr_uat,eui64,"EUI-64",
2680 "64-bit extended unique identifier."),
2681 UAT_END_FIELDS
2684 /* Register the init routine. */
2685 register_init_routine(proto_init_ieee802154);
2687 /* Register Protocol name and description. */
2688 proto_ieee802154 = proto_register_protocol("IEEE 802.15.4 Low-Rate Wireless PAN", "IEEE 802.15.4",
2689 IEEE802154_PROTOABBREV_WPAN);
2690 proto_ieee802154_nonask_phy = proto_register_protocol("IEEE 802.15.4 Low-Rate Wireless PAN non-ASK PHY",
2691 "IEEE 802.15.4 non-ASK PHY", "wpan-nonask-phy");
2693 /* Register header fields and subtrees. */
2694 proto_register_field_array(proto_ieee802154, hf, array_length(hf));
2695 proto_register_field_array(proto_ieee802154, hf_phy, array_length(hf_phy));
2697 proto_register_subtree_array(ett, array_length(ett));
2699 expert_ieee802154 = expert_register_protocol(proto_ieee802154);
2700 expert_register_field_array(expert_ieee802154, ei, array_length(ei));
2702 /* add a user preference to set the 802.15.4 ethertype */
2703 ieee802154_module = prefs_register_protocol(proto_ieee802154,
2704 proto_reg_handoff_ieee802154);
2705 prefs_register_uint_preference(ieee802154_module, "802154_ethertype",
2706 "802.15.4 Ethertype (in hex)",
2707 "(Hexadecimal) Ethertype used to indicate IEEE 802.15.4 frame.",
2708 16, &ieee802154_ethertype);
2709 prefs_register_bool_preference(ieee802154_module, "802154_cc24xx",
2710 "TI CC24xx FCS format",
2711 "Set if the FCS field is in TI CC24xx format.",
2712 &ieee802154_cc24xx);
2713 prefs_register_bool_preference(ieee802154_module, "802154_fcs_ok",
2714 "Dissect only good FCS",
2715 "Dissect payload only if FCS is valid.",
2716 &ieee802154_fcs_ok);
2718 /* Create a UAT for static address mappings. */
2719 static_addr_uat = uat_new("Static Addresses",
2720 sizeof(static_addr_t), /* record size */
2721 "802154_addresses", /* filename */
2722 TRUE, /* from_profile */
2723 (void**)&static_addrs, /* data_ptr */
2724 &num_static_addrs, /* numitems_ptr */
2725 UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
2726 NULL, /* help */
2727 NULL, /* copy callback */
2728 addr_uat_update_cb, /* update callback */
2729 NULL, /* free callback */
2730 NULL, /* post update callback */
2731 addr_uat_flds); /* UAT field definitions */
2732 prefs_register_uat_preference(ieee802154_module, "static_addr",
2733 "Static Addresses",
2734 "A table of static address mappings between 16-bit short addressing and EUI-64 addresses",
2735 static_addr_uat);
2737 /* Register preferences for a decryption key */
2738 /* TODO: Implement a UAT for multiple keys, and with more advanced key management. */
2739 prefs_register_string_preference(ieee802154_module, "802154_key", "Decryption key",
2740 "128-bit decryption key in hexadecimal format", (const char **)&ieee802154_key_str);
2742 prefs_register_enum_preference(ieee802154_module, "802154_sec_suite",
2743 "Security Suite (802.15.4-2003)",
2744 "Specifies the security suite to use for 802.15.4-2003 secured frames"
2745 " (only supported suites are listed). Option ignored for 802.15.4-2006"
2746 " and unsecured frames.",
2747 &ieee802154_sec_suite, ieee802154_2003_sec_suite_enums, FALSE);
2749 prefs_register_bool_preference(ieee802154_module, "802154_extend_auth",
2750 "Extend authentication data (802.15.4-2003)",
2751 "Set if the manufacturer extends the authentication data with the"
2752 " security header. Option ignored for 802.15.4-2006 and unsecured frames.",
2753 &ieee802154_extend_auth);
2755 /* Register the subdissector list */
2756 register_heur_dissector_list(IEEE802154_PROTOABBREV_WPAN, &ieee802154_heur_subdissector_list);
2758 /* Register dissectors with Wireshark. */
2759 register_dissector(IEEE802154_PROTOABBREV_WPAN, dissect_ieee802154, proto_ieee802154);
2760 register_dissector("wpan_nofcs", dissect_ieee802154_nofcs, proto_ieee802154);
2761 register_dissector("wpan_cc24xx", dissect_ieee802154_cc24xx, proto_ieee802154);
2762 register_dissector("wpan-nonask-phy", dissect_ieee802154_nonask_phy, proto_ieee802154_nonask_phy);
2763 } /* proto_register_ieee802154 */
2766 /*FUNCTION:------------------------------------------------------
2767 * NAME
2768 * proto_reg_handoff_ieee802154
2769 * DESCRIPTION
2770 * Registers the IEEE 802.15.4 dissector with Wireshark.
2771 * Will be called every time 'apply' is pressed in the preferences menu.
2772 * as well as during Wireshark initialization
2773 * PARAMETERS
2774 * none
2775 * RETURNS
2776 * void
2777 *---------------------------------------------------------------
2779 void proto_reg_handoff_ieee802154(void)
2781 static gboolean prefs_initialized = FALSE;
2782 static dissector_handle_t ieee802154_handle;
2783 static dissector_handle_t ieee802154_nonask_phy_handle;
2784 static dissector_handle_t ieee802154_nofcs_handle;
2785 static unsigned int old_ieee802154_ethertype;
2786 GByteArray *bytes;
2787 gboolean res;
2789 if (!prefs_initialized){
2790 /* Get the dissector handles. */
2791 ieee802154_handle = find_dissector(IEEE802154_PROTOABBREV_WPAN);
2792 ieee802154_nonask_phy_handle = find_dissector("wpan-nonask-phy");
2793 ieee802154_nofcs_handle = find_dissector("wpan_nofcs");
2794 data_handle = find_dissector("data");
2796 dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE802_15_4, ieee802154_handle);
2797 dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE802_15_4_NONASK_PHY, ieee802154_nonask_phy_handle);
2798 dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE802_15_4_NOFCS, ieee802154_nofcs_handle);
2799 dissector_add_uint("sll.ltype", LINUX_SLL_P_IEEE802154, ieee802154_handle);
2801 prefs_initialized = TRUE;
2802 } else {
2803 dissector_delete_uint("ethertype", old_ieee802154_ethertype, ieee802154_handle);
2806 old_ieee802154_ethertype = ieee802154_ethertype;
2808 /* Get the IEEE 802.15.4 decryption key. */
2809 bytes = g_byte_array_new();
2810 res = hex_str_to_bytes(ieee802154_key_str, bytes, FALSE);
2811 ieee802154_key_valid = (res && bytes->len >= IEEE802154_CIPHER_SIZE);
2812 if (ieee802154_key_valid) {
2813 memcpy(ieee802154_key, bytes->data, IEEE802154_CIPHER_SIZE);
2815 g_byte_array_free(bytes, TRUE);
2817 /* Register dissector handles. */
2818 dissector_add_uint("ethertype", ieee802154_ethertype, ieee802154_handle);
2819 } /* proto_reg_handoff_ieee802154 */