/* packet-ieee802154.c * * $Id$ * * IEEE 802.15.4 Dissectors for Wireshark * By Owen Kirby * Copyright 2007 Exegin Technologies Limited * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *------------------------------------------------------------ * * In IEEE 802.15.4 packets, all fields are little endian. And * Each byte is transmitted least significan bit first (reflected * bit ordering). *------------------------------------------------------------ * * IEEE 802.15.4 Packets have the following format: * | FCF |Seq No| Addressing | Data | FCS | * |2 bytes|1 byte|0 to 20 bytes|Length-(Overhead) bytes|2 Bytes| *------------------------------------------------------------ * * CRC16 is calculated using the x^16 + x^12 + x^5 + 1 polynomial * as specified by ITU-T, and is calculated over the IEEE 802.15.4 * packet (excluding the FCS) as transmitted over the air. Note, * that because the least significan bits are transmitted first, this * will require reversing the bit-order in each byte. Also, unlike * most CRC algorithms, IEEE 802.15.4 uses an initial and final value * of 0x0000, instead of 0xffff (which is used by the CCITT). *------------------------------------------------------------ * * This dissector supports both link-layer IEEE 802.15.4 captures * and IEEE 802.15.4 packets encapsulated within other layers. * Additionally, support has been provided for various formats * of the frame check sequence: * - IEEE 802.15.4 compliant FCS. * - ChipCon/Texas Instruments CC24xx style FCS. * - No FCS at all. *------------------------------------------------------------ * * No support has been provided for decryption. Maybe a TODO * item, but this is unlikely as the decryption process requires * the extended source address (to build the nonce/initial value) * which will be absent most of the time. *------------------------------------------------------------ */ /* Include files */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVEHCONFIG_H */ #include #include #include #include #include #include #include #include #include #include #include #include #include "packet-ieee802154.h" #include "packet-frame.h" /* For Exception Handling */ /* Dissection Options for dissect_ieee802154_common */ #define DISSECT_IEEE802154_OPTION_CC24xx 0x00000001 /* FCS field contains a TI CC24xx style FCS. */ #define DISSECT_IEEE802154_OPTION_LINUX 0x00000002 /* Addressing fields are padded DLT_IEEE802_15_4_LINUX, not implemented. */ /* ethertype for 802.15.4 tag - encapsulating an Ethernet packet */ static unsigned int ieee802154_ethertype = 0x809A; /* Function declarations */ /* Register Functions. Loads the dissector into Wireshark. */ void proto_reg_handoff_ieee802154 (void); void proto_register_ieee802154 (void); /* Dissection Routines. */ static void dissect_ieee802154_nonask_phy (tvbuff_t *, packet_info *, proto_tree *); static void dissect_ieee802154 (tvbuff_t *, packet_info *, proto_tree *); static void dissect_ieee802154_nofcs (tvbuff_t *, packet_info *, proto_tree *); static void dissect_ieee802154_cc24xx (tvbuff_t *, packet_info *, proto_tree *); /*static void dissect_ieee802154_linux (tvbuff_t *, packet_info *, proto_tree *); TODO: Implement Me. */ static void dissect_ieee802154_common (tvbuff_t *, packet_info *, proto_tree *, guint); static void dissect_ieee802154_beacon (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *); static void dissect_ieee802154_cmd (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *); /* Sub-dissector helpers. */ static void dissect_ieee802154_fcf (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *); static void dissect_ieee802154_cmd_asreq (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *); static void dissect_ieee802154_cmd_asrsp (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *); static void dissect_ieee802154_cmd_disas (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *); static void dissect_ieee802154_cmd_realign (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *); static void dissect_ieee802154_cmd_gtsrq (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *); /* Initialize Protocol and Registered fields */ static int proto_ieee802154_nonask_phy = -1; static int hf_ieee802154_nonask_phy_preamble = -1; static int hf_ieee802154_nonask_phy_sfd = -1; static int hf_ieee802154_nonask_phy_length = -1; static int proto_ieee802154 = -1; static int hf_ieee802154_frame_type = -1; static int hf_ieee802154_security = -1; static int hf_ieee802154_pending = -1; static int hf_ieee802154_ack_request = -1; static int hf_ieee802154_intra_pan = -1; static int hf_ieee802154_seqno = -1; static int hf_ieee802154_src_addr_mode = -1; static int hf_ieee802154_dst_addr_mode = -1; static int hf_ieee802154_version = -1; static int hf_ieee802154_dst_pan = -1; static int hf_ieee802154_dst_addr16 = -1; static int hf_ieee802154_dst_addr64 = -1; static int hf_ieee802154_src_panID = -1; static int hf_ieee802154_src_addr16 = -1; static int hf_ieee802154_src_addr64 = -1; static int hf_ieee802154_fcs = -1; static int hf_ieee802154_rssi = -1; static int hf_ieee802154_fcs_ok = -1; static int hf_ieee802154_correlation; /* Registered fields for Command Packets */ static int hf_ieee802154_cmd_id = -1; static int hf_ieee802154_cmd_cinfo_alt_coord = -1; static int hf_ieee802154_cmd_cinfo_device_type = -1; static int hf_ieee802154_cmd_cinfo_power_src = -1; static int hf_ieee802154_cmd_cinfo_idle_rx = -1; static int hf_ieee802154_cmd_cinfo_sec_capable = -1; static int hf_ieee802154_cmd_cinfo_alloc_addr = -1; static int hf_ieee802154_cmd_asrsp_addr = -1; static int hf_ieee802154_cmd_asrsp_status = -1; static int hf_ieee802154_cmd_disas_reason = -1; static int hf_ieee802154_cmd_coord_pan = -1; static int hf_ieee802154_cmd_coord_caddr = -1; static int hf_ieee802154_cmd_coord_channel = -1; static int hf_ieee802154_cmd_coord_addr = -1; static int hf_ieee802154_cmd_coord_channel_page = -1; static int hf_ieee802154_cmd_gts_req_len = -1; static int hf_ieee802154_cmd_gts_req_dir = -1; static int hf_ieee802154_cmd_gts_req_type = -1; /* Registered fields for Beacon Packets */ static int hf_ieee802154_bcn_beacon_order = -1; static int hf_ieee802154_bcn_superframe_order = -1; static int hf_ieee802154_bcn_cap = -1; static int hf_ieee802154_bcn_battery_ext = -1; static int hf_ieee802154_bcn_coord = -1; static int hf_ieee802154_bcn_assoc_permit = -1; static int hf_ieee802154_bcn_gts_count = -1; static int hf_ieee802154_bcn_gts_permit = -1; static int hf_ieee802154_bcn_gts_direction = -1; static int hf_ieee802154_bcn_pending16 = -1; static int hf_ieee802154_bcn_pending64 = -1; /* Initialize Subtree Pointers */ static gint ett_ieee802154_nonask_phy = -1; static gint ett_ieee802154_nonask_phy_phr = -1; static gint ett_ieee802154 = -1; static gint ett_ieee802154_fcf = -1; static gint ett_ieee802154_fcs = -1; static gint ett_ieee802154_cmd = -1; static gint ett_ieee802154_cmd_cinfo = -1; static gint ett_ieee802154_bcn = -1; static gint ett_ieee802154_bcn_superframe_spec = -1; static gint ett_ieee802154_bcn_gts_spec = -1; static gint ett_ieee802154_bcn_gts_direction = -1; static gint ett_ieee802154_bcn_gts_descriptors = -1; static gint ett_ieee802154_bcn_pending = -1; /* Dissector handles */ static dissector_handle_t data_handle; static heur_dissector_list_t ieee802154_heur_subdissector_list; /* Name Strings */ static const value_string ieee802154_frame_types[] = { { IEEE802154_FCF_BEACON, "Beacon" }, { IEEE802154_FCF_DATA, "Data" }, { IEEE802154_FCF_ACK, "Ack" }, { IEEE802154_FCF_CMD, "Command" }, { 0, NULL } }; static const value_string ieee802154_addr_modes[] = { { IEEE802154_FCF_ADDR_NONE, "None" }, { IEEE802154_FCF_ADDR_SHORT, "Short/16-bit" }, { IEEE802154_FCF_ADDR_EXT, "Long/64-bit" }, { 0, NULL } }; static const value_string ieee802154_cmd_names[] = { { IEEE802154_CMD_ASRQ, "Association Request" }, { IEEE802154_CMD_ASRSP, "Association Response" }, { IEEE802154_CMD_DISAS, "Disassociation Notification" }, { IEEE802154_CMD_DATA_RQ, "Data Request" }, { IEEE802154_CMD_PANID_ERR, "PAN ID Conflict" }, { IEEE802154_CMD_ORPH_NOTIF,"Orphan Notification" }, { IEEE802154_CMD_BCN_RQ, "Beacon Request" }, { IEEE802154_CMD_COORD_REAL,"Coordinator Realignment" }, { IEEE802154_CMD_GTS_REQ, "GTS Request" }, { 0, NULL } }; /* CRC definitions. IEEE 802.15.4 CRCs vary from CCITT by using an initial value of * 0x0000, and no XOR out. IEEE802154_CRC_XOR is defined as 0xFFFF in order to un-XOR * the output from the CCITT CRC routines in Wireshark. */ #define IEEE802154_CRC_SEED 0x0000 #define IEEE802154_CRC_XOROUT 0xFFFF #define ieee802154_crc_tvb(tvb, offset) (crc16_ccitt_tvb_seed(tvb, offset, IEEE802154_CRC_SEED) ^ IEEE802154_CRC_XOROUT) /*FUNCTION:------------------------------------------------------ * NAME * get_by_mask * DESCRIPTION * Extracts an integer sub-field from an int with a given mask * if the mask is 0, this will return 0, if the mask is non- * continuos the output is undefined. * PARAMETERS * guint input * guint mask * RETURNS * guint *--------------------------------------------------------------- */ guint get_by_mask(guint input, guint mask) { /* Sanity Check, don't want infinite loops. */ if (mask == 0) return 0; /* Shift input and mask together. */ while (!(mask & 0x1)) { input >>= 1; mask >>=1; } /* while */ return (input & mask); } /* get_by_mask */ #define EUI64_STRLEN (3*(sizeof(guint64)+1)) /*FUNCTION:------------------------------------------------------ * NAME * print_eui64 * DESCRIPTION * Prints an EUI-64 address in a string. Does not attempt to * resolve the OUI value. * * PARAMETERS * guint64 addr * RETURNS * gchar* *--------------------------------------------------------------- */ gchar * print_eui64(guint64 addr) { address eui64addr; /* Endian-swap the address to put it into network order. */ addr = pntoh64(&addr); /* Fill in the address struct. */ eui64addr.type = AT_EUI64; eui64addr.len = sizeof(guint64); eui64addr.data = &addr; /* Print the address. */ return address_to_str(&eui64addr); } /* print_eui64 */ /*FUNCTION:------------------------------------------------------ * NAME * print_eui64_oui * DESCRIPTION * Prints an EUI-64 address in a string. Attempts to lookup * the vendor name from the OUI, * * PARAMETERS * guint64 addr * RETURNS * gchar* *--------------------------------------------------------------- */ gchar * print_eui64_oui(guint64 addr) { const gchar *manuf_name; address eui64addr; /* Endian-swap the address to put it into network order. */ addr = pntoh64(&addr); /* Fill in the address struct. */ eui64addr.type = AT_EUI64; eui64addr.len = sizeof(guint64); eui64addr.data = &addr; /* Attempt an OUI lookup. */ manuf_name = get_manuf_name_if_known(eui64addr.data); if (manuf_name == NULL) { /* Could not find an OUI. */ return address_to_str(&eui64addr); } else { /* Found an address string. */ gchar *output_str = ep_alloc(64); g_snprintf(output_str, 64, "%s_%02x:%02x:%02x:%02x:%02x", manuf_name, ((guint8 *)(eui64addr.data))[3], ((guint8 *)(eui64addr.data))[4], ((guint8 *)(eui64addr.data))[5], ((guint8 *)(eui64addr.data))[6], ((guint8 *)(eui64addr.data))[7]); return output_str; } } /* print_eui64_oui */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_fcf * DESCRIPTION * Dissector helper, parses and displays the frame control * field. * * PARAMETERS * ieee802154_packet *packet - Packet info structure. * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree ethereal uses to display packet. * ieee802154_packet *packet - IEEE 802.15.4 packet information. * guint offset - offset into the tvb to find the FCF. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_fcf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet, guint *offset) { guint16 fcf; proto_tree *field_tree; proto_item *ti; /* Get the FCF field. */ fcf = tvb_get_letohs(tvb, *offset); /* Parse FCF Flags. */ packet->frame_type = get_by_mask(fcf, IEEE802154_FCF_TYPE_MASK); packet->security_enable = get_by_mask(fcf, IEEE802154_FCF_SEC_EN); packet->frame_pending = get_by_mask(fcf, IEEE802154_FCF_FRAME_PND); packet->ack_request = get_by_mask(fcf, IEEE802154_FCF_ACK_REQ); packet->intra_pan = get_by_mask(fcf, IEEE802154_FCF_INTRA_PAN); packet->version = get_by_mask(fcf, IEEE802154_FCF_VERSION); packet->dst_addr_mode = get_by_mask(fcf, IEEE802154_FCF_DADDR_MASK); packet->src_addr_mode = get_by_mask(fcf, IEEE802154_FCF_SADDR_MASK); /* Display the frame type. */ if (tree) proto_item_append_text(tree, " %s", val_to_str(packet->frame_type, ieee802154_frame_types, "Reserved")); if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, val_to_str(packet->frame_type, ieee802154_frame_types, "Reserved")); /* Add the FCF to the protocol tree. */ if (tree) { /* Create the FCF subtree. */ ti = proto_tree_add_text(tree, tvb, *offset, sizeof(guint16), "Frame Control Field: %s (0x%04x)", val_to_str(packet->frame_type, ieee802154_frame_types, "Unknown"), fcf); field_tree = proto_item_add_subtree(ti, ett_ieee802154_fcf); /* FCF Fields. */ proto_tree_add_uint(field_tree, hf_ieee802154_frame_type, tvb, *offset, sizeof(guint8), fcf & IEEE802154_FCF_TYPE_MASK); proto_tree_add_boolean(field_tree, hf_ieee802154_security, tvb, *offset, sizeof(guint8), fcf & IEEE802154_FCF_SEC_EN); proto_tree_add_boolean(field_tree, hf_ieee802154_pending, tvb, *offset, sizeof(guint8), fcf & IEEE802154_FCF_FRAME_PND); proto_tree_add_boolean(field_tree, hf_ieee802154_ack_request, tvb, *offset, sizeof(guint8), fcf & IEEE802154_FCF_ACK_REQ); proto_tree_add_boolean(field_tree, hf_ieee802154_intra_pan, tvb, *offset, sizeof(guint8), fcf & IEEE802154_FCF_INTRA_PAN); proto_tree_add_uint(field_tree, hf_ieee802154_dst_addr_mode, tvb, (*offset)+sizeof(guint8), sizeof(guint8), fcf & IEEE802154_FCF_DADDR_MASK); proto_tree_add_uint(field_tree, hf_ieee802154_version, tvb, (*offset)+sizeof(guint8), sizeof(guint8), fcf & IEEE802154_FCF_VERSION); proto_tree_add_uint(field_tree, hf_ieee802154_src_addr_mode, tvb, (*offset)+sizeof(guint8), sizeof(guint8), fcf & IEEE802154_FCF_SADDR_MASK); } *offset += sizeof(guint16); } /* dissect_ieee802154_fcf */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_nonask_phy * DESCRIPTION * Dissector for IEEE 802.15.4 non-ASK PHY packet with an FCS containing * a 16-bit CRC value. * * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree ethereal uses to display packet. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_nonask_phy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *ieee802154_tree = NULL; proto_item *proto_root = NULL; guint offset=0; guint32 preamble; guint8 sfd,phr; tvbuff_t* mac; /* Create the protocol tree. */ if (tree) { proto_root = proto_tree_add_protocol_format(tree, proto_ieee802154_nonask_phy, tvb, 0, tvb_length(tvb), "IEEE 802.15.4 non-ASK PHY"); ieee802154_tree = proto_item_add_subtree(proto_root, ett_ieee802154_nonask_phy); } /* Add the protocol name. */ if(check_col(pinfo->cinfo, COL_PROTOCOL)){ col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEEE 802.15.4 non-ASK PHY"); } /* Add the packet length. */ if(check_col(pinfo->cinfo, COL_PACKET_LENGTH)){ col_clear(pinfo->cinfo, COL_PACKET_LENGTH); col_add_fstr(pinfo->cinfo, COL_PACKET_LENGTH, "%i", tvb_length(tvb)); } preamble=tvb_get_letohl(tvb,offset); sfd=tvb_get_guint8(tvb,offset+sizeof(guint32)); phr=tvb_get_guint8(tvb,offset+sizeof(guint32)+sizeof(guint8)); if(tree) { proto_tree *phr_tree; proto_item *pi; guint loffset=offset; proto_tree_add_uint(ieee802154_tree, hf_ieee802154_nonask_phy_preamble, tvb, loffset, sizeof(guint32), preamble); loffset+=sizeof(guint32); proto_tree_add_uint(ieee802154_tree, hf_ieee802154_nonask_phy_sfd, tvb, loffset, sizeof(guint8), sfd); loffset+=sizeof(guint8); pi = proto_tree_add_text(ieee802154_tree, tvb, loffset, sizeof(guint8), "PHR: 0x%02x", phr); phr_tree = proto_item_add_subtree(pi, ett_ieee802154_nonask_phy_phr); proto_tree_add_uint(phr_tree, hf_ieee802154_nonask_phy_length, tvb, loffset, sizeof(guint8), phr); } offset+=sizeof(guint32)+2*sizeof(guint8); mac=tvb_new_subset(tvb,offset,-1, phr & IEEE802154_PHY_LENGTH_MASK); /* Call the common dissector. */ dissect_ieee802154(mac, pinfo, ieee802154_tree); } /* dissect_ieee802154_nonask_phy */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154 * DESCRIPTION * Dissector for IEEE 802.15.4 packet with an FCS containing * a 16-bit CRC value. * * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree ethereal uses to display packet. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Call the common dissector. */ dissect_ieee802154_common(tvb, pinfo, tree, 0); } /* dissect_ieee802154 */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_nofcs * DESCRIPTION * Dissector for IEEE 802.15.4 packet with no FCS present. * * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree ethereal uses to display packet. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_nofcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { tvbuff_t *new_tvb; /* If there is no FCS present in the reported packet, then the length of * the true IEEE 802.15.4 packet is actually 2 bytes longer. Re-create * the buffer with an extended reported length so that the packet will * be handled as though the FCS were truncated. * * Note, we can't just call tvb_set_reported_length(), because it includes * checks to ensure that the new reported length is not longer than the old * reported length (why?), and will throw an exception. */ new_tvb = tvb_new_subset(tvb, 0, -1, tvb_reported_length(tvb)+IEEE802154_FCS_LEN); /* Call the common dissector. */ dissect_ieee802154_common(new_tvb, pinfo, tree, 0); } /* dissect_ieee802154_nofcs */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_cc24xx * DESCRIPTION * Dissector for IEEE 802.15.4 packet with a ChipCon/Texas * Instruments compatible FCS. This is typically called by * layers encapsulating an IEEE 802.15.4 packet. * * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree ethereal uses to display packet. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_cc24xx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Call the common dissector. */ dissect_ieee802154_common(tvb, pinfo, tree, DISSECT_IEEE802154_OPTION_CC24xx); } /* dissect_ieee802154_cc24xx */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_common * DESCRIPTION * IEEE 802.15.4 packet dissection routine for Ethereal. * This function extracts all the information first before displaying. * If payload exists, that portion will be passed into another dissector * for further processing. * * This is called after the individual dissect_ieee802154* functions * have been called to determine what sort of FCS is present. * The dissect_ieee802154* functions will set the parameters * in the ieee802154_packet structure, and pass it to this one * through the pinfo->private_data pointer. * * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree ethereal uses to display packet. * guint options - bitwise or of dissector options (see DISSECT_IEEE802154_OPTION_xxx). * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint options) { tvbuff_t *volatile payload_tvb; proto_tree *volatile ieee802154_tree = NULL; proto_item *volatile proto_root = NULL; proto_item *ti; guint offset = 0; volatile gboolean fcs_ok = TRUE; const char *saved_proto; ieee802154_packet *packet = ep_alloc(sizeof(ieee802154_packet)); /* Link our packet info structure into the private data field for the * Network-Layer heuristic subdissectors. */ pinfo->private_data = packet; /* Create the protocol tree. */ if (tree) { proto_root = proto_tree_add_protocol_format(tree, proto_ieee802154, tvb, 0, tvb_length(tvb), "IEEE 802.15.4"); ieee802154_tree = proto_item_add_subtree(proto_root, ett_ieee802154); } /* Add the protocol name. */ if(check_col(pinfo->cinfo, COL_PROTOCOL)){ col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEEE 802.15.4"); } /* Add the packet length. */ if(check_col(pinfo->cinfo, COL_PACKET_LENGTH)){ col_clear(pinfo->cinfo, COL_PACKET_LENGTH); col_add_fstr(pinfo->cinfo, COL_PACKET_LENGTH, "%i", tvb_length(tvb)); } /*===================================================== * FRAME CONTROL FIELD *===================================================== */ dissect_ieee802154_fcf(tvb, pinfo, ieee802154_tree, packet, &offset); /*===================================================== * SEQUENCE NUMBER *===================================================== */ packet->seqno = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(ieee802154_tree, hf_ieee802154_seqno, tvb, offset, 1, packet->seqno); /* For Ack packets display this in the root. */ if (packet->frame_type == IEEE802154_FCF_ACK) { proto_item_append_text(proto_root, ", Sequence Number: %u", packet->seqno); } } offset += sizeof(guint8); /*===================================================== * ADDRESSING FIELDS *===================================================== */ /* Clear out the addressing strings. */ SET_ADDRESS(&pinfo->dst, AT_NONE, 0, NULL); SET_ADDRESS(&pinfo->src, AT_NONE, 0, NULL); SET_ADDRESS(&pinfo->dl_dst, AT_NONE, 0, NULL); SET_ADDRESS(&pinfo->dl_src, AT_NONE, 0, NULL); SET_ADDRESS(&pinfo->net_dst, AT_NONE, 0, NULL); SET_ADDRESS(&pinfo->net_src, AT_NONE, 0, NULL); /* Get and display the destination PAN, if present. */ if ( (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) || (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) ) { packet->dst_pan = tvb_get_letohs(tvb, offset); if (tree) { proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_pan, tvb, offset, sizeof(guint16), packet->dst_pan); } offset += sizeof(guint16); } /* Get destination address. */ if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) { /* Dynamic (not stack) memory required for address column. */ gchar *dst_addr = ep_alloc(32); /* Get the address. */ packet->dst.addr16 = tvb_get_letohs(tvb, offset); /* Display the destination address. */ if(packet->dst.addr16==IEEE802154_BCAST_ADDR) g_snprintf(dst_addr, 32, "Broadcast"); else g_snprintf(dst_addr, 32, "0x%04x", packet->dst.addr16); SET_ADDRESS(&pinfo->dl_dst, AT_STRINGZ, (int)strlen(dst_addr)+1, dst_addr); SET_ADDRESS(&pinfo->dst, AT_STRINGZ, (int)strlen(dst_addr)+1, dst_addr); if (tree) { proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_addr16, tvb, offset, sizeof(guint16), packet->dst.addr16); proto_item_append_text(proto_root, ", Dst: %s", dst_addr); } if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_addr); } offset += sizeof(guint16); } else if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) { /* Dynamic (not stack) memory required for address column. */ gchar *addr = ep_alloc(sizeof(guint64)); gchar *dst, *dst_oui; /* Get the address */ packet->dst.addr64 = tvb_get_letoh64(tvb, offset); /* print the address strings. */ dst = print_eui64(packet->dst.addr64); dst_oui = print_eui64_oui(packet->dst.addr64); /* Copy and convert the address to network byte order. */ *(guint64 *)(addr) = pntoh64(&(packet->dst.addr64)); /* Display the destination address. */ /* NOTE: OUI resolution doesn't happen when displaying EUI64 addresses * might want to switch to AT_STRINZ type to display the OUI in * the address columns. */ SET_ADDRESS(&pinfo->dl_dst, AT_EUI64, sizeof(guint64), addr); SET_ADDRESS(&pinfo->dst, AT_EUI64, sizeof(guint64), addr); if (tree) { proto_tree_add_uint64_format_value(ieee802154_tree, hf_ieee802154_dst_addr64, tvb, offset, sizeof(guint64), packet->dst.addr64, "%s (%s)", dst_oui, dst); proto_item_append_text(proto_root, ", Dst: %s", dst_oui); } if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_oui); } offset += sizeof(guint64); } else if (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE) { /* Invalid Destination Address Mode. Abort Dissection. */ expert_add_info_format(pinfo, proto_root, PI_MALFORMED, PI_ERROR, "Invalid Destination Address Mode"); return; } /* Get the source PAN if it exists. The source address will be present if: * - The Source addressing exists and * - The Destination addressing doesn't exist, or the Intra-PAN bit is unset. */ if ( ((packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) || (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT)) && ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) || (!packet->intra_pan)) ) { /* Source PAN is present, extract it and add it to the tree. */ packet->src_pan = tvb_get_letohs(tvb, offset); if (tree) { proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_panID, tvb, offset, sizeof(guint16), packet->src_pan); } offset += sizeof(guint16); } else { /* Set the panID field in case the intra-pan condition was met. */ packet->src_pan = packet->dst_pan; } /* Get source address if present. */ if (packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) { /* Dynamic (not stack) memory required for address column. */ gchar *src_addr = ep_alloc(32); /* Get the address. */ packet->src.addr16 = tvb_get_letohs(tvb, offset); /* Update the Address fields. */ if(packet->src.addr16==IEEE802154_BCAST_ADDR) g_snprintf(src_addr, 32, "Broadcast"); else g_snprintf(src_addr, 32, "0x%04x", packet->src.addr16); SET_ADDRESS(&pinfo->dl_src, AT_STRINGZ, (int)strlen(src_addr)+1, src_addr); SET_ADDRESS(&pinfo->src, AT_STRINGZ, (int)strlen(src_addr)+1, src_addr); /* Add the addressing info to the tree. */ if (tree) { proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_addr16, tvb, offset, sizeof(guint16), packet->src.addr16); proto_item_append_text(proto_root, ", Src: %s", src_addr); } if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_addr); } offset += sizeof(guint16); } else if (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) { /* Dynamic (not stack) memory required for address column. */ gchar *addr = ep_alloc(sizeof(guint64)); gchar *src, *src_oui; /* Get the address. */ packet->src.addr64 = tvb_get_letoh64(tvb, offset); /* Print the address strings. */ src = print_eui64(packet->src.addr64); src_oui = print_eui64_oui(packet->src.addr64); /* Copy and convert the address to network byte order. */ *(guint64 *)(addr) = pntoh64(&(packet->src.addr64)); /* Display the source address. */ /* NOTE: OUI resolution doesn't happen when displaying EUI64 addresses * might want to switch to AT_STRINZ type to display the OUI in * the address columns. */ SET_ADDRESS(&pinfo->dl_src, AT_EUI64, sizeof(guint64), addr); SET_ADDRESS(&pinfo->src, AT_EUI64, sizeof(guint64), addr); if (tree) { proto_tree_add_uint64_format_value(ieee802154_tree, hf_ieee802154_src_addr64, tvb, offset, sizeof(guint64), packet->src.addr64, "%s (%s)", src_oui, src); proto_item_append_text(proto_root, ", Src: %s", src_oui); } if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_oui); } offset += sizeof(guint64); } else if (packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE) { /* Invalid Destination Address Mode. Abort Dissection. */ expert_add_info_format(pinfo, proto_root, PI_MALFORMED, PI_ERROR, "Invalid Source Address Mode"); return; } /*===================================================== * FRAME CHECK SEQUENCE VERIFICATION *===================================================== */ /* Check, but don't display the FCS yet, otherwise the payload dissection * may be out of place in the tree. But we want to know if the FCS is OK in * case the CRC is bad (don't want to continue dissection to the NWK layer). */ if (tvb_bytes_exist(tvb, tvb_reported_length(tvb)-IEEE802154_FCS_LEN, IEEE802154_FCS_LEN)) { /* The FCS is in the last two bytes of the packet. */ guint16 fcs = tvb_get_letohs(tvb, tvb_reported_length(tvb)-IEEE802154_FCS_LEN); /* Check if we are expecting a CC2420-style FCS*/ if (options & DISSECT_IEEE802154_OPTION_CC24xx) { fcs_ok = (fcs & IEEE802154_CC24xx_CRC_OK); } else { guint16 fcs_calc = ieee802154_crc_tvb(tvb, tvb_reported_length(tvb)-IEEE802154_FCS_LEN); fcs_ok = (fcs == fcs_calc); } } /*===================================================== * PAYLOAD DISSECTION *===================================================== */ /* Create the payload buffer. */ payload_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN); /* Just being safe to ensure that real_length <= reported_length. The tvbuff * code should ensure this condition when creating the subset, but I don't * think it does. */ tvb_set_reported_length(payload_tvb, tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN); /* We can't handle encryption, so if the packet is encrypted, give up. */ if (packet->security_enable) { /* Payload is encrypted. We can't handle this. Maybe a future feature? */ expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "Encrypted Payload"); call_dissector(data_handle, payload_tvb, pinfo, tree); goto dissect_ieee802154_fcs; } /* * Wrap the sub-dissection in a try/catch block in case the payload is * broken. First we store the current protocol so we can fix it if an * exception is thrown by the subdissectors. */ saved_proto = pinfo->current_proto; /* Try to dissect the payload. */ TRY { switch (packet->frame_type) { case IEEE802154_FCF_BEACON: dissect_ieee802154_beacon(payload_tvb, pinfo, ieee802154_tree, packet); break; case IEEE802154_FCF_CMD: dissect_ieee802154_cmd(payload_tvb, pinfo, ieee802154_tree, packet); break; case IEEE802154_FCF_DATA: if (fcs_ok && (tvb_reported_length(payload_tvb)>0)) { /* Attempt heuristic subdissection. */ if (dissector_try_heuristic(ieee802154_heur_subdissector_list, payload_tvb, pinfo, tree)) { /* found a sub-dissector! */ break; } } /* If no sub-dissector was called, call the data dissector. */ call_dissector(data_handle, payload_tvb, pinfo, tree); break; case IEEE802154_FCF_ACK: /* Ack should not contain a payload. */ if (tvb_reported_length(payload_tvb) > 0) { expert_add_info_format(pinfo, proto_root, PI_MALFORMED, PI_WARN, "Unexpected Payload in Acknowledgement"); } call_dissector(data_handle, payload_tvb, pinfo, tree); break; default: /* Unknown frame type! */ call_dissector(data_handle, payload_tvb, pinfo, tree); break; } /* switch */ } CATCH_ALL { /* * Someone encountered an error while dissecting the payload. But * we haven't yet finished processing all of our layer. Catch and * display the exception, then fall-through to finish displaying * the FCS (which we display last so the frame is ordered correctly * in the tree). */ show_exception(payload_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); pinfo->current_proto = saved_proto; } ENDTRY; /*===================================================== * FRAME CHECK SEQUENCE *===================================================== */ dissect_ieee802154_fcs: /* The FCS should be the last bytes of the reported packet. */ offset = tvb_reported_length(tvb)-IEEE802154_FCS_LEN; /* Dissect the FCS only if it exists (captures which don't or can't get the * FCS will simply truncate the packet to omit it, but should still set the * reported length to cover the original packet length), so if the snapshot * is too short for an FCS don't make a fuss. */ if (tvb_bytes_exist(tvb, offset, IEEE802154_FCS_LEN) && (tree)) { proto_tree *field_tree; guint16 fcs = tvb_get_letohs(tvb, offset); /* Display the FCS depending on expected FCS format */ if ((options & DISSECT_IEEE802154_OPTION_CC24xx)) { /* Create a subtree for the FCS. */ ti = proto_tree_add_text(ieee802154_tree, tvb, offset, sizeof(guint16), "Frame Check Sequence: FCS %s", (fcs_ok) ? "OK" : "Bad"); field_tree = proto_item_add_subtree(ti, ett_ieee802154_fcs); /* Display FCS contents. */ ti = proto_tree_add_int(field_tree, hf_ieee802154_rssi, tvb, offset, sizeof(guint16), get_by_mask(fcs, IEEE802154_CC24xx_RSSI)); proto_item_append_text(ti, " dBm"); /* Displaying Units */ proto_tree_add_boolean(field_tree, hf_ieee802154_fcs_ok, tvb, offset, sizeof(guint16), get_by_mask(fcs, IEEE802154_CC24xx_CRC_OK)); proto_tree_add_uint(field_tree, hf_ieee802154_correlation, tvb, offset, sizeof(guint16), get_by_mask(fcs, IEEE802154_CC24xx_CORRELATION)); } else { ti = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_fcs, tvb, offset, sizeof(guint16), fcs); if (fcs_ok) { proto_item_append_text(ti, " (Correct)"); } else { proto_item_append_text(ti, " (Incorrect, expected FCS=0x%04x", ieee802154_crc_tvb(tvb, offset)); } /* To Help with filtering, add the fcs_ok field to the tree. */ ti = proto_tree_add_boolean(ieee802154_tree, hf_ieee802154_fcs_ok, tvb, offset, sizeof(guint16), fcs_ok); PROTO_ITEM_SET_HIDDEN(ti); } } else if (tree) { /* Even if the FCS isn't present, add the fcs_ok field to the tree to * help with filter. Be sure not to make it visible though. */ ti = proto_tree_add_boolean(ieee802154_tree, hf_ieee802154_fcs_ok, tvb, offset, sizeof(guint16), fcs_ok); PROTO_ITEM_SET_HIDDEN(ti); } /* If the CRC is invalid, make a note of it in the info column. */ if (!fcs_ok) { if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", Bad FCS"); if (tree) proto_item_append_text(proto_root, ", Bad FCS"); /* Flag packet as having a bad crc. */ expert_add_info_format(pinfo, proto_root, PI_CHECKSUM, PI_WARN, "Bad FCS"); } } /* dissect_ieee802154_common */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_beacon * DESCRIPTION * ZigBee packet dissection routine for beacon packets.Please refer * to section 7.2.2.1 in the IEEE 802.15.4 document on Beacon frame format * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree ethereal uses to display packet. * ieee802154_packet *packet - IEEE 802.15.4 packet information. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_beacon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet) { proto_tree *field_tree = NULL; proto_tree *bcn_tree = NULL; proto_item *ti; guint8 superframe_spec_hi; guint8 superframe_spec_lo; guint8 gts_spec; guint8 gts_desc_count; guint8 paddr_spec; guint8 paddr_num16; guint8 paddr_num64; guint8 bcn_payload_len; gint i; gint offset = 0; /* Parse the superframe spec. */ superframe_spec_hi = tvb_get_guint8(tvb, offset); superframe_spec_lo = tvb_get_guint8(tvb, offset+1); if(tree){ guint8 bo = superframe_spec_hi & IEEE802154_BCN_BO_MASK; guint8 sfo = (superframe_spec_hi & IEEE802154_BCN_SFO_MASK)>>IEEE802154_BCN_SFO_SHIFT; /* Add Subtree for beacon frame */ ti = proto_tree_add_text(tree, tvb, 0, tvb_length(tvb), "Beacon Frame"); bcn_tree = proto_item_add_subtree(ti, ett_ieee802154_bcn); /* 'Light' Assert to check for valid addressing. */ if (packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) { expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_WARN, "Missing Source Address in Beacon" ); } /* Add Subtree for superframe specification */ ti = proto_tree_add_text(bcn_tree, tvb, offset, 2, "Superframe Specification"); field_tree = proto_item_add_subtree(ti, ett_ieee802154_bcn_superframe_spec); /* Add Beacon Order to the superframe spec. */ ti = proto_tree_add_uint_format(field_tree, hf_ieee802154_bcn_beacon_order, tvb, offset, 1, bo, "Beacon Order: "); if(bo == 0xf) proto_item_append_text(ti, "Beacons Disabled"); else proto_item_append_text(ti, "%i", IEEE802154_BCN_SFRM_DURATION*(1<> IEEE802154_BCN_GTS_LENGTH_SHIFT; if (tree) { /* Add address, slot, and time length fields. */ ti = proto_tree_add_text(field_tree, tvb, offset, 2, "{Address: 0x%04x", gts_addr); proto_item_append_text(ti, ", Slot: %i", gts_slot); proto_item_append_text(ti, ", Length: %i}", gts_slot_len); } offset += sizeof(guint16)+sizeof(guint8); } /* for */ } /* Get the Pending Addresses specification fields */ paddr_spec = tvb_get_guint8(tvb, offset); paddr_num16 = paddr_spec & IEEE802154_BCN_PADDR_SHORT_MASK; paddr_num64 = (paddr_spec & IEEE802154_BCN_PADDR_LONG_MASK) >> IEEE802154_BCN_PADDR_LONG_SHIFT; if(tree){ /* Add Subtree for the addresses */ ti = proto_tree_add_text(bcn_tree, tvb, offset, 1 + 2*paddr_num16 + 8*paddr_num64, "Pending Addresses: %i Short and %i Long", paddr_num16, paddr_num64); field_tree = proto_item_add_subtree(ti, ett_ieee802154_bcn_pending); } offset += sizeof(guint8); for (i=0; icinfo, COL_INFO)) { col_set_str(pinfo->cinfo, COL_INFO, val_to_str(cmd_id, ieee802154_cmd_names, "Unknown Command")); } if (tree) { /* Create a subtree for this command frame. */ cmd_root = proto_tree_add_text(tree, tvb, 0, tvb_length(tvb), "Command Frame, %s", val_to_str(cmd_id, ieee802154_cmd_names, "Unknown Command")); cmd_tree = proto_item_add_subtree(cmd_root, ett_ieee802154_cmd); /* Add the command ID to the subtree. */ ti = proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_id, tvb, offset, sizeof(guint8), cmd_id); } /* Increment the offset field. */ offset += sizeof(guint8); /* Parse the Command Payloads. */ switch(cmd_id){ case IEEE802154_CMD_ASRQ: /* Check that the addressing is correct for this command type. */ CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE)); dissect_ieee802154_cmd_asreq(tvb, pinfo, cmd_tree, packet, &offset); break; case IEEE802154_CMD_ASRSP: /* Check that the addressing is correct for this command type. */ CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT)); dissect_ieee802154_cmd_asrsp(tvb, pinfo, cmd_tree, packet, &offset); break; case IEEE802154_CMD_DISAS: /* Check that the addressing is correct for this command type. */ CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT)); dissect_ieee802154_cmd_disas(tvb, pinfo, cmd_tree, packet, &offset); break; case IEEE802154_CMD_DATA_RQ: /* Check that the addressing is correct for this command type. */ CMD_ADDR_CHECK(packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE); /* Data Req contains no payload. */ break; case IEEE802154_CMD_PANID_ERR: /* Check that the addressing is correct for this command type. */ CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT)); /* PANID Err contains no payload. */ break; case IEEE802154_CMD_ORPH_NOTIF: /* Check that the addressing is correct for this command type. */ CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) && (packet->dst.addr16 == IEEE802154_BCAST_ADDR) && (packet->src_pan == IEEE802154_BCAST_PAN) && (packet->dst_pan == IEEE802154_BCAST_PAN)); /* Orphan Notification contains no payload. */ break; case IEEE802154_CMD_BCN_RQ: /* Check that the addressing is correct for this command type. */ CMD_ADDR_CHECK((packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) && (packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) && (packet->dst.addr16 == IEEE802154_BCAST_ADDR) && (packet->dst_pan == IEEE802154_BCAST_PAN)); /* Beacon Request contains no payload. */ break; case IEEE802154_CMD_COORD_REAL: /* Check that the addressing is correct for this command type. */ CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && (packet->dst_pan == IEEE802154_BCAST_PAN) && (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE)); if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) { /* If directed to a 16-bit address, check that it is being broadcast. */ CMD_ADDR_CHECK(packet->dst.addr16 == IEEE802154_BCAST_ADDR); } dissect_ieee802154_cmd_realign(tvb, pinfo, cmd_tree, packet, &offset); break; case IEEE802154_CMD_GTS_REQ: /* Check that the addressing is correct for this command type. */ CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) && (packet->src.addr16 != IEEE802154_BCAST_ADDR) && (packet->src.addr16 != IEEE802154_NO_ADDR16)); dissect_ieee802154_cmd_gtsrq(tvb, pinfo, cmd_tree, packet, &offset); break; default: break; } /* switch */ #undef CMD_ADDR_CHECK /* If there are bytes leftover, call the data dissector to handle them. */ if (offset < tvb_length(tvb)) { guint leftover_len = tvb_length(tvb) - offset; proto_tree *root = proto_tree_get_root(tree); tvbuff_t *leftover_tvb = tvb_new_subset(tvb, offset, leftover_len, leftover_len); /* Call the data dissector. */ if (leftover_tvb) call_dissector(data_handle, leftover_tvb, pinfo, root); } } /* dissect_ieee802154_cmd */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_cmd_asreq * DESCRIPTION * Command subdissector routine for the Association request * command. * * Assumes that COL_INFO will be set to the command name, * command name will already be appended to the command subtree * and protocol root. In addition, assumes that the command ID * has already been parsed. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields (unused). * proto_tree *tree - pointer to command subtree. * ieee802154_packet *packet - IEEE 802.15.4 packet information (unused). * guint *offset - offset into the tvbuff to begin dissection. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_cmd_asreq(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, ieee802154_packet *packet _U_, guint *offset) { proto_item *ti; proto_tree *field_tree; guint8 capability_info; /* Get the capability info. */ capability_info = tvb_get_guint8(tvb, *offset); /* Display capability info. */ if (tree) { ti = proto_tree_add_text(tree, tvb, *offset, sizeof(guint8), "Capability Information"); field_tree = proto_item_add_subtree(ti, ett_ieee802154_cmd_cinfo); /* Enter the capability bits. */ proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_alt_coord, tvb, *offset, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_ALT_PAN_COORD); ti = proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_device_type, tvb, *offset, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_DEVICE_TYPE); if (capability_info & IEEE802154_CMD_CINFO_DEVICE_TYPE) proto_item_append_text(ti, " (FFD)"); else proto_item_append_text(ti, " (RFD)"); ti = proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_power_src, tvb, *offset, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_POWER_SRC); if (capability_info & IEEE802154_CMD_CINFO_POWER_SRC) proto_item_append_text(ti, " (AC/Mains Power)"); else proto_item_append_text(ti, " (Battery)"); proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_idle_rx, tvb, *offset, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_IDLE_RX); proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_sec_capable, tvb, *offset, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_SEC_CAPABLE); proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_alloc_addr, tvb, *offset, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_ALLOC_ADDR); } /* Increase the offset. */ (*offset) += sizeof(guint8); } /* dissect_ieee802154_cmd_asreq */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_cmd_asrsp * DESCRIPTION * Command subdissector routine for the Association response * command. * * Assumes that COL_INFO will be set to the command name, * command name will already be appended to the command subtree * and protocol root. In addition, assumes that the command ID * has already been parsed. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to command subtree. * ieee802154_packet *packet - IEEE 802.15.4 packet information (unused). * guint *offset - offset into the tvbuff to begin dissection. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_cmd_asrsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet _U_, guint *offset) { proto_item *ti; guint16 short_addr; guint8 status; /* Get and display the short address. */ short_addr = tvb_get_letohs(tvb, *offset); if (tree) { proto_tree_add_uint(tree, hf_ieee802154_cmd_asrsp_addr, tvb, *offset, sizeof(guint16), short_addr); } (*offset) += sizeof(guint16); /* Get and display the status. */ status = tvb_get_guint8(tvb, *offset); if (tree) { ti = proto_tree_add_uint(tree, hf_ieee802154_cmd_asrsp_status, tvb, *offset, sizeof(guint8), status); if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) proto_item_append_text(ti, " (Association Successful)"); else if (status == IEEE802154_CMD_ASRSP_PAN_FULL) proto_item_append_text(ti, " (PAN Full)"); else if (status == IEEE802154_CMD_ASRSP_PAN_DENIED) proto_item_append_text(ti, " (Association Denied)"); else proto_item_append_text(ti, " (Reserved)"); } (*offset) += sizeof(guint8); /* Update the info column. */ if (check_col(pinfo->cinfo, COL_INFO)) { if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) { /* Association was successful. */ if (packet->src_addr_mode != IEEE802154_FCF_ADDR_SHORT) { col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", packet->dst_pan); } if (short_addr != IEEE802154_NO_ADDR16) { col_append_fstr(pinfo->cinfo, COL_INFO, " Addr: 0x%04x", short_addr); } } else { /* Association was unsuccessful. */ col_append_fstr(pinfo->cinfo, COL_INFO, ", Unsuccessful"); } } } /* dissect_ieee802154_cmd_asrsp */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_cmd_disas * DESCRIPTION * Command subdissector routine for the Disassociate command. * * Assumes that COL_INFO will be set to the command name, * command name will already be appended to the command subtree * and protocol root. In addition, assumes that the command ID * has already been parsed. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields (unused). * proto_tree *tree - pointer to command subtree. * ieee802154_packet *packet - IEEE 802.15.4 packet information (unused). * guint *offset - offset into the tvbuff to begin dissection. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_cmd_disas(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, ieee802154_packet *packet _U_, guint *offset) { proto_item *ti; guint8 reason; /* Get and display the dissasociation reason. */ reason = tvb_get_guint8(tvb, *offset); if (tree) { ti = proto_tree_add_uint(tree, hf_ieee802154_cmd_disas_reason, tvb, *offset, sizeof(guint8), reason); switch(reason) { case 0x01: proto_item_append_text(ti, " (Coordinator requests device to leave)"); break; case 0x02: proto_item_append_text(ti, " (Device wishes to leave)"); break; default: proto_item_append_text(ti, " (Reserved)"); break; } /* switch */ } /* Adjust offset */ (*offset) += sizeof(guint8); } /* dissect_ieee802154_cmd_disas */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_cmd_gtsrq * DESCRIPTION * Command subdissector routine for the Coordinator Realignment * command. * * Assumes that COL_INFO will be set to the command name, * command name will already be appended to the command subtree * and protocol root. In addition, assumes that the command ID * has already been parsed. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to command subtree. * ieee802154_packet *packet - IEEE 802.15.4 packet information. * guint *offset - offset into the tvbuff to begin dissection. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_cmd_realign(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet, guint *offset) { guint16 pan_id; guint16 coord_addr; guint8 channel; guint16 short_addr; /* Get and display the command PAN ID. */ pan_id = tvb_get_letohs(tvb, *offset); if (tree) proto_tree_add_uint(tree, hf_ieee802154_cmd_coord_pan, tvb, *offset, sizeof(guint16), pan_id); if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", pan_id); (*offset) += sizeof(guint16); /* Get and display the coordinator address. */ coord_addr = tvb_get_letohs(tvb, *offset); if (tree) proto_tree_add_uint(tree, hf_ieee802154_cmd_coord_caddr, tvb, *offset, sizeof(guint16), coord_addr); if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", Coordinator: 0x%04x", coord_addr); (*offset) += sizeof(guint16); /* Get and display the channel. */ channel = tvb_get_guint8(tvb, *offset); if (tree) proto_tree_add_uint(tree, hf_ieee802154_cmd_coord_channel, tvb, *offset, sizeof(guint8), channel); if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", Channel: %u", channel); (*offset) += sizeof(guint8); /* Get and display the short address. */ short_addr = tvb_get_letohs(tvb, *offset); if (tree) proto_tree_add_uint(tree, hf_ieee802154_cmd_coord_addr, tvb, *offset, sizeof(guint16), short_addr); if ( (check_col(pinfo->cinfo, COL_INFO)) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) && (short_addr != IEEE802154_NO_ADDR16)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Addr: 0x%04x", short_addr); } (*offset) += sizeof(guint16); /* Get and display the channel page, if it exists. Added in IEEE802.15.4-2006 */ if (tvb_bytes_exist(tvb, *offset, sizeof(guint8))) { guint8 channel_page = tvb_get_guint8(tvb, *offset); if (tree) proto_tree_add_uint(tree, hf_ieee802154_cmd_coord_channel_page, tvb, *offset, sizeof(guint8), channel_page); (*offset) += sizeof(guint8); } } /* dissect_ieee802154_cmd_realign */ /*FUNCTION:------------------------------------------------------ * NAME * dissect_ieee802154_cmd_gtsrq * DESCRIPTION * Command subdissector routine for the GTS request command. * * Assumes that COL_INFO will be set to the command name, * command name will already be appended to the command subtree * and protocol root. In addition, assumes that the command ID * has already been parsed. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields (unused). * proto_tree *tree - pointer to command subtree. * ieee802154_packet *packet - IEEE 802.15.4 packet information (unused). * guint *offset - offset into the tvbuff to begin dissection. * RETURNS * void *--------------------------------------------------------------- */ static void dissect_ieee802154_cmd_gtsrq(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, ieee802154_packet *packet _U_, guint *offset) { proto_item *ti; guint8 characteristics; guint8 length; guint8 direction; guint8 type; /* Get the characteristics field. */ characteristics = tvb_get_guint8(tvb, *offset); length = characteristics & IEEE802154_CMD_GTS_REQ_LEN; direction = characteristics & IEEE802154_CMD_GTS_REQ_DIR; type = characteristics & IEEE802154_CMD_GTS_REQ_TYPE; /* Display the characteristics field. */ if (tree) { proto_tree_add_uint(tree, hf_ieee802154_cmd_gts_req_len, tvb, *offset, sizeof(guint8), length); ti = proto_tree_add_boolean(tree, hf_ieee802154_cmd_gts_req_dir, tvb, *offset, sizeof(guint8), direction); if (direction) proto_item_append_text(ti, " (Receive)"); else proto_item_append_text(ti, " (Transmit)"); ti = proto_tree_add_boolean(tree, hf_ieee802154_cmd_gts_req_type, tvb, *offset, sizeof(guint8), type); if (type) proto_item_append_text(ti, " (Allocate GTS)"); else proto_item_append_text(ti, " (Deallocate GTS)"); } /* Adjust offset */ (*offset) += sizeof(guint8); } /* dissect_ieee802154_cmd_gtsrq */ /*FUNCTION:------------------------------------------------------ * NAME * proto_register_ieee802154 * DESCRIPTION * IEEE 802.15.4 protocol registration routine. * PARAMETERS * none * RETURNS * void *--------------------------------------------------------------- */ void proto_register_ieee802154(void) { static hf_register_info hf_phy[] = { /* PHY level */ { &hf_ieee802154_nonask_phy_preamble, { "Preamble", "wpan-nonask-phy.preamble", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_nonask_phy_sfd, { "Start of Frame Delimiter", "wpan-nonask-phy.sfd", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_nonask_phy_length, { "Frame Length", "wpan-nonask-phy.frame_length", FT_UINT8, BASE_HEX, NULL, IEEE802154_PHY_LENGTH_MASK, "", HFILL }}, }; static hf_register_info hf[] = { { &hf_ieee802154_frame_type, { "Frame Type", "wpan.frame_type", FT_UINT16, BASE_HEX, VALS(ieee802154_frame_types), IEEE802154_FCF_TYPE_MASK, "", HFILL }}, { &hf_ieee802154_security, { "Security Enabled", "wpan.security", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_SEC_EN, "Whether security operations are performed at the MAC layer or not.", HFILL }}, { &hf_ieee802154_pending, { "Frame Pending", "wpan.pending", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_FRAME_PND, "Indication of additional packets waiting to be transferred from the source device.", HFILL }}, { &hf_ieee802154_ack_request, { "Acknowledge Request", "wpan.ack_request", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_ACK_REQ, "Whether the sender of this packet requests acknowledgement or not.", HFILL }}, { &hf_ieee802154_intra_pan, { "Intra-PAN", "wpan.intra_pan", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_INTRA_PAN, "Whether this packet originated and terminated within the same PAN or not.", HFILL }}, { &hf_ieee802154_seqno, { "Sequence Number", "wpan.seq_no", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_dst_addr_mode, { "Destination Addressing Mode", "wpan.dst_addr_mode", FT_UINT16, BASE_HEX, VALS(ieee802154_addr_modes), IEEE802154_FCF_DADDR_MASK, "", HFILL }}, { &hf_ieee802154_src_addr_mode, { "Source Addressing Mode", "wpan.src_addr_mode", FT_UINT16, BASE_HEX, VALS(ieee802154_addr_modes), IEEE802154_FCF_SADDR_MASK, "", HFILL }}, { &hf_ieee802154_version, { "Frame Version", "wpan.version", FT_UINT16, BASE_DEC, NULL, IEEE802154_FCF_VERSION, "", HFILL }}, { &hf_ieee802154_dst_pan, { "Destination PAN", "wpan.dst_pan", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_dst_addr16, { "Destination", "wpan.dst_addr16", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_dst_addr64, { "Destination", "wpan.dst_addr64", FT_UINT64, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_src_panID, { "Source PAN", "wpan.src_pan", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_src_addr16, { "Source", "wpan.src_addr16", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_src_addr64, { "Source", "wpan.src_addr64", FT_UINT64, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_fcs, { "FCS", "wpan.fcs", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_rssi, { "RSSI", "wpan.rssi", FT_INT8, BASE_DEC, NULL, 0x0, "Received Signal Strength", HFILL }}, { &hf_ieee802154_fcs_ok, { "FCS Valid", "wpan.fcs_ok", FT_BOOLEAN, 8, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_correlation, { "LQI Correlation Value", "wpan.correlation", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, /* Command Frame Specific Fields */ /*--------------------------------*/ { &hf_ieee802154_cmd_id, { "Command Identifier", "wpan.cmd.id", FT_UINT8, BASE_HEX, VALS(ieee802154_cmd_names), 0x0, "", HFILL }}, /* Capability Information Fields */ { &hf_ieee802154_cmd_cinfo_alt_coord, { "Alternate PAN Coordinator", "wpan.cmd.cinfo.alt_coord", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALT_PAN_COORD, "Whether this device can act as a PAN coordinator or not.", HFILL }}, { &hf_ieee802154_cmd_cinfo_device_type, { "Device Type", "wpan.cmd.cinfo.device_type", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_DEVICE_TYPE, "Whether this device is RFD (reduced-function device) or FFD (full-function device).", HFILL }}, { &hf_ieee802154_cmd_cinfo_power_src, { "Power Source", "wpan.cmd.cinfo.power_src", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_POWER_SRC, "Whether this device is operating on AC/mains or battery power.", HFILL }}, { &hf_ieee802154_cmd_cinfo_idle_rx, { "Receive On When Idle", "wpan.cmd.cinfo.idle_rx", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_IDLE_RX, "Whether this device can receive packets while idle or not.", HFILL }}, { &hf_ieee802154_cmd_cinfo_sec_capable, { "Security Capability", "wpan.cmd.cinfo.sec_capable", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_SEC_CAPABLE, "Whether this device is capable of receiving encrypted packets.", HFILL }}, { &hf_ieee802154_cmd_cinfo_alloc_addr, { "Allocate Address", "wpan.cmd.cinfo.alloc_addr", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALLOC_ADDR, "Whether this device wishes to use a 16-bit short address instead of its IEEE 802.15.4 64-bit long address.", HFILL }}, /* Association response fields */ { &hf_ieee802154_cmd_asrsp_addr, { "Short Address", "wpan.cmd.asrsp.addr", FT_UINT16, BASE_HEX, NULL, 0x0, "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 }}, { &hf_ieee802154_cmd_asrsp_status, { "Association Status", "wpan.cmd.asrsp.status", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ieee802154_cmd_disas_reason, { "Disassociation Reason", "wpan.cmd.disas.reason", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }}, /* Coordinator Realignment fields */ { &hf_ieee802154_cmd_coord_pan, { "PAN ID", "wpan.cmd.coord.pan", FT_UINT16, BASE_HEX, NULL, 0x0, "The PAN identifier the coordinator wishes to use for future communication.", HFILL }}, { &hf_ieee802154_cmd_coord_caddr, { "Coordinator Short Address", "wpan.cmd.coord.addr", FT_UINT16, BASE_HEX, NULL, 0x0, "The 16-bit address the coordinator wishes to use for future communication.", HFILL }}, { &hf_ieee802154_cmd_coord_channel, { "Logical Channel", "wpan.cmd.coord.channel", FT_UINT8, BASE_DEC, NULL, 0x0, "The logical channel the coordinator wishes to use for future communication.", HFILL }}, { &hf_ieee802154_cmd_coord_addr, { "Short Address", "wpan.cmd.coord.addr", FT_UINT16, BASE_HEX, NULL, 0x0, "A short-address that the orphaned device shall assume if applicable.", HFILL }}, { &hf_ieee802154_cmd_coord_channel_page, { "Channel Page", "wpan.cmd.coord.channel_page", FT_UINT8, BASE_DEC, NULL, 0x0, "The logical channel page the coordinator wishes to use for future communication.", HFILL }}, { &hf_ieee802154_cmd_gts_req_len, { "GTS Length", "wpan.cmd.gts.length", FT_UINT8, BASE_DEC, NULL, IEEE802154_CMD_GTS_REQ_LEN, "Number of superframe slots the device is requesting.", HFILL }}, { &hf_ieee802154_cmd_gts_req_dir, { "GTS Direction", "wpan.cmd.gts.direction", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_GTS_REQ_DIR, "The direction of traffic in the guaranteed timeslot.", HFILL }}, { &hf_ieee802154_cmd_gts_req_type, { "Characteristic Type", "wpan.cmd.gts.type", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_GTS_REQ_TYPE, "Whether this request is to allocate or deallocate a timeslot.", HFILL }}, /* Beacon Frame Specific Fields */ /*-------------------------------*/ { &hf_ieee802154_bcn_beacon_order, { "Beacon Interval", "wpan.bcn.beacon_order", FT_UINT8, BASE_DEC, NULL, 0x0, "Specifies the transmission interval of the beacons.", HFILL }}, { &hf_ieee802154_bcn_superframe_order, { "Superframe Interval", "wpan.bcn.superframe_order", FT_UINT8, BASE_DEC, NULL, 0x0, "Specifies the length of time the coordinator will interact with the PAN.", HFILL }}, { &hf_ieee802154_bcn_cap, { "Final CAP Slot", "wpan.bcn.cap", FT_UINT8, BASE_DEC, NULL, 0x0, "Specifies the final superframe slot used by the CAP.", HFILL }}, { &hf_ieee802154_bcn_battery_ext, { "Battery Extension", "wpan.bcn.battery_ext", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_BATT_EXTN_MASK, "Whether transmissions may not extend past the length of the beacon frame.", HFILL }}, { &hf_ieee802154_bcn_coord, { "PAN Coordinator", "wpan.bcn.coord", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_COORD_MASK, "Whether this beacon frame is being transmitted by the PAN coordinator or not.", HFILL }}, { &hf_ieee802154_bcn_assoc_permit, { "Association Permit", "wpan.bcn.assoc_permit", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_ASSOC_PERM_MASK, "Whether this PAN is accepting association requests or not.", HFILL }}, { &hf_ieee802154_bcn_gts_count, { "GTS Descriptor Count", "wpan.bcn.gts.count", FT_UINT8, BASE_DEC, NULL, 0x0, "The number of GTS descriptors present in this beacon frame.", HFILL }}, { &hf_ieee802154_bcn_gts_permit, { "GTS Permit", "wpan.bcn.gts.permit", FT_BOOLEAN, 8, NULL, 0x0, "Whether the PAN coordinator is accepting GTS requests or not.", HFILL }}, { &hf_ieee802154_bcn_gts_direction, { "Direction", "wpan.bcn.gts.direction", FT_BOOLEAN, 8, NULL, 0x0, "A flag defining the direction of the GTS Slot.", HFILL }}, { &hf_ieee802154_bcn_pending16, { "Address", "wpan.bcn.pending16", FT_UINT16, BASE_HEX, NULL, 0x0, "Device with pending data to receive.", HFILL }}, { &hf_ieee802154_bcn_pending64, { "Address", "wpan.bcn.pending64", FT_UINT64, BASE_HEX, NULL, 0x0, "Device with pending data to receive.", HFILL }} }; static gint *ett[] = { &ett_ieee802154_nonask_phy, &ett_ieee802154_nonask_phy_phr, &ett_ieee802154, &ett_ieee802154_fcf, &ett_ieee802154_fcs, &ett_ieee802154_cmd, &ett_ieee802154_cmd_cinfo, &ett_ieee802154_bcn, &ett_ieee802154_bcn_superframe_spec, &ett_ieee802154_bcn_gts_spec, &ett_ieee802154_bcn_gts_direction, &ett_ieee802154_bcn_gts_descriptors, &ett_ieee802154_bcn_pending }; module_t *ieee802154_module; /* Register Protocol name and description. */ proto_ieee802154 = proto_register_protocol("IEEE 802.15.4 Low-Rate Wireless PAN", "IEEE 802.15.4", "wpan"); proto_ieee802154_nonask_phy = proto_register_protocol("IEEE 802.15.4 Low-Rate Wireless PAN non-ASK PHY", "IEEE 802.15.4 non-ASK PHY", "wpan-nonask-phy"); /* Register header fields and subtrees. */ proto_register_field_array(proto_ieee802154, hf, array_length(hf)); proto_register_field_array(proto_ieee802154, hf_phy, array_length(hf_phy)); proto_register_subtree_array(ett, array_length(ett)); /* add a user preference to set the 802.15.4 ethertype */ ieee802154_module = prefs_register_protocol(proto_ieee802154, proto_reg_handoff_ieee802154); prefs_register_uint_preference(ieee802154_module, "802154_ethertype", "802.15.4 Ethertype (in hex)", "(Hexadecimal) Ethertype used to indicate IEEE 802.15.4 frame.", 16, &ieee802154_ethertype); /* Register the subdissector list */ register_heur_dissector_list("wpan", &ieee802154_heur_subdissector_list); /* Register dissectors with Ethereal. */ register_dissector("wpan", dissect_ieee802154, proto_ieee802154); register_dissector("wpan_nofcs", dissect_ieee802154_nofcs, proto_ieee802154); register_dissector("wpan_cc24xx", dissect_ieee802154_cc24xx, proto_ieee802154); register_dissector("wpan-nonask-phy", dissect_ieee802154_nonask_phy, proto_ieee802154_nonask_phy); } /* proto_register_ieee802154 */ /*FUNCTION:------------------------------------------------------ * NAME * proto_reg_handoff_ieee802154 * DESCRIPTION * Registers the zigbee dissector with Wireshark. * Will be called every time 'apply' is pressed in the preferences menu. * as well as during Wireshark initialization * PARAMETERS * none * RETURNS * void *--------------------------------------------------------------- */ void proto_reg_handoff_ieee802154(void) { static gboolean prefs_initialized = FALSE; static dissector_handle_t ieee802154_handle; static dissector_handle_t ieee802154_nonask_phy_handle; static unsigned int old_ieee802154_ethertype; if (!prefs_initialized){ /* Get the dissector handles. */ ieee802154_handle = find_dissector("wpan"); ieee802154_nonask_phy_handle = find_dissector("wpan-nonask-phy"); data_handle = find_dissector("data"); dissector_add("wtap_encap", WTAP_ENCAP_IEEE802_15_4, ieee802154_handle); dissector_add("wtap_encap", WTAP_ENCAP_IEEE802_15_4_NONASK_PHY, ieee802154_nonask_phy_handle); prefs_initialized = TRUE; } else { dissector_delete("ethertype", old_ieee802154_ethertype, ieee802154_handle); } old_ieee802154_ethertype = ieee802154_ethertype; /* Register dissector handles. */ dissector_add("ethertype", ieee802154_ethertype, ieee802154_handle); } /* proto_reg_handoff_ieee802154 */