summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-6lowpan.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-6lowpan.c')
-rw-r--r--epan/dissectors/packet-6lowpan.c3737
1 files changed, 3737 insertions, 0 deletions
diff --git a/epan/dissectors/packet-6lowpan.c b/epan/dissectors/packet-6lowpan.c
new file mode 100644
index 00000000..068b9a6e
--- /dev/null
+++ b/epan/dissectors/packet-6lowpan.c
@@ -0,0 +1,3737 @@
+/* packet-6lowpan.c
+ *
+ * Add Selective Fragment Recovery per
+ * https://tools.ietf.org/html/draft-ietf-6lo-fragment-recovery-02
+ * By James Ko <jck@exegin.com>
+ * Copyright 2019 Exegin Technologies Limited
+ *
+ * Routines for 6LoWPAN packet disassembly
+ * By Owen Kirby <osk@exegin.com>
+ * Copyright 2009 Owen Kirby
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "config.h"
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/expert.h>
+#include <epan/reassemble.h>
+#include <epan/ipproto.h>
+#include <epan/addr_resolv.h>
+#include <epan/proto_data.h>
+#include <epan/etypes.h>
+#include "packet-6lowpan.h"
+#include "packet-btl2cap.h"
+#include "packet-zbee.h"
+
+void proto_register_6lowpan(void);
+void proto_reg_handoff_6lowpan(void);
+
+/* Definitions for 6lowpan packet disassembly structures and routines */
+
+/* 6LoWPAN Patterns */
+#define LOWPAN_PATTERN_NALP 0x00
+#define LOWPAN_PATTERN_NALP_BITS 2
+#define LOWPAN_PATTERN_IPV6 0x41
+#define LOWPAN_PATTERN_IPV6_BITS 8
+#define LOWPAN_PATTERN_HC1 0x42 /* Deprecated - replaced with IPHC. */
+#define LOWPAN_PATTERN_HC1_BITS 8
+#define LOWPAN_PATTERN_BC0 0x50
+#define LOWPAN_PATTERN_BC0_BITS 8
+#define LOWPAN_PATTERN_IPHC 0x03 /* See draft-ietf-6lowpan-hc-15.txt */
+#define LOWPAN_PATTERN_IPHC_BITS 3
+#define LOWPAN_PATTERN_ESC 0x7f
+#define LOWPAN_PATTERN_ESC_BITS 8
+#define LOWPAN_PATTERN_MESH 0x02
+#define LOWPAN_PATTERN_MESH_BITS 2
+#define LOWPAN_PATTERN_FRAG1 0x18
+#define LOWPAN_PATTERN_FRAGN 0x1c
+#define LOWPAN_PATTERN_FRAG_BITS 5
+#define LOWPAN_PATTERN_RFRAG 0x74
+#define LOWPAN_PATTERN_RFRAG_ACK 0x75
+#define LOWPAN_PATTERN_RFRAG_BITS 7
+
+#define LOWPAN_RFRAG_SEQUENCE_BITS 5
+#define LOWPAN_RFRAG_FRAG_SZ_BITS 10
+
+/* RFC8025 and RFC8138 */
+#define LOWPAN_PATTERN_PAGING_DISPATCH 0xf
+#define LOWPAN_PATTERN_PAGING_DISPATCH_BITS 4
+#define LOWPAN_PATTERN_6LORHC 0x04
+#define LOWPAN_PATTERN_6LORHE 0x05
+#define LOWPAN_PATTERN_6LORHE_CLASS 0xe000
+#define LOWPAN_PATTERN_6LORHE_CLASS_BITS 13
+#define LOWPAN_PATTERN_6LORHE_LENGTH 0x1f00
+#define LOWPAN_PATTERN_6LORHE_LENGTH_BITS 8
+#define LOWPAN_PATTERN_6LORHE_TYPE 0x00ff
+#define LOWPAN_PATTERN_6LORH_TYPE0 0x00
+#define LOWPAN_PATTERN_6LORH_TYPE1 0x01
+#define LOWPAN_PATTERN_6LORH_TYPE2 0x02
+#define LOWPAN_PATTERN_6LORH_TYPE3 0x03
+#define LOWPAN_PATTERN_6LORH_TYPE4 0x04
+#define LOWPAN_PATTERN_6LORH_TYPE5 0x05
+#define LOWPAN_PATTERN_6LORH_TYPE6 0x06
+#define LOWPAN_PATTERN_6LORH_TYPE15 0x0F
+#define LOWPAN_PATTERN_6LORH_TYPE16 0x10
+#define LOWPAN_PATTERN_6LORH_TYPE17 0x11
+#define LOWPAN_PATTERN_6LORH_TYPE18 0x12
+#define LOWPAN_PATTERN_6LORH_TYPE19 0x13
+#define LOWPAN_5_RPI_BIT_O 0x1000
+#define LOWPAN_5_RPI_BIT_R 0x0800
+#define LOWPAN_5_RPI_BIT_F 0x0400
+#define LOWPAN_5_RPI_BIT_I 0x0200
+#define LOWPAN_5_RPI_BIT_K 0x0100
+#define LOWPAN_5_RPI_BITS_IK 0x0300
+#define LOWPAN_6LORH_GENERAL_FORMAT 0x8000
+#define LOWPAN_IP_IN_IP_6LORH 6
+#define BITS_IK_0 0
+#define BITS_IK_1 1
+#define BITS_IK_2 2
+#define BITS_IK_3 3
+#define BITS_IK_4 4
+#define IPV6_ADDR_COMPRESSED_1_BYTE 0
+#define IPV6_ADDR_COMPRESSED_2_BYTE 1
+#define IPV6_ADDR_COMPRESSED_4_BYTE 2
+#define IPV6_ADDR_COMPRESSED_8_BYTE 3
+#define IPV6_ADDR_COMPRESSED_16_BYTE 4
+
+/* 6LoWPAN HC1 Header */
+#define LOWPAN_HC1_SOURCE_PREFIX 0x80
+#define LOWPAN_HC1_SOURCE_IFC 0x40
+#define LOWPAN_HC1_DEST_PREFIX 0x20
+#define LOWPAN_HC1_DEST_IFC 0x10
+#define LOWPAN_HC1_TRAFFIC_CLASS 0x08
+#define LOWPAN_HC1_NEXT 0x06
+#define LOWPAN_HC1_MORE 0x01
+
+/* IPv6 header field lengths (in bits) */
+#define LOWPAN_IPV6_TRAFFIC_CLASS_BITS 8
+#define LOWPAN_IPV6_FLOW_LABEL_BITS 20
+#define LOWPAN_IPV6_NEXT_HEADER_BITS 8
+#define LOWPAN_IPV6_HOP_LIMIT_BITS 8
+#define LOWPAN_IPV6_PREFIX_BITS 64
+#define LOWPAN_IPV6_INTERFACE_BITS 64
+
+/* HC_UDP header field lengths (in bits). */
+#define LOWPAN_UDP_PORT_BITS 16
+#define LOWPAN_UDP_PORT_COMPRESSED_BITS 4
+#define LOWPAN_UDP_LENGTH_BITS 16
+#define LOWPAN_UDP_CHECKSUM_BITS 16
+
+/* HC1 Next Header compression modes. */
+#define LOWPAN_HC1_NEXT_NONE 0x00
+#define LOWPAN_HC1_NEXT_UDP 0x01
+#define LOWPAN_HC1_NEXT_ICMP 0x02
+#define LOWPAN_HC1_NEXT_TCP 0x03
+
+/* HC_UDP Header */
+#define LOWPAN_HC2_UDP_SRCPORT 0x80
+#define LOWPAN_HC2_UDP_DSTPORT 0x40
+#define LOWPAN_HC2_UDP_LENGTH 0x20
+#define LOWPAN_HC2_UDP_RESERVED 0x1f
+
+/* IPHC Base flags */
+#define LOWPAN_IPHC_FLAG_FLOW 0x1800
+#define LOWPAN_IPHC_FLAG_NHDR 0x0400
+#define LOWPAN_IPHC_FLAG_HLIM 0x0300
+#define LOWPAN_IPHC_FLAG_CONTEXT_ID 0x0080
+#define LOWPAN_IPHC_FLAG_SRC_COMP 0x0040
+#define LOWPAN_IPHC_FLAG_SRC_MODE 0x0030
+#define LOWPAN_IPHC_FLAG_MCAST_COMP 0x0008
+#define LOWPAN_IPHC_FLAG_DST_COMP 0x0004
+#define LOWPAN_IPHC_FLAG_DST_MODE 0x0003
+#define LOWPAN_IPHC_FLAG_SCI 0xf0
+#define LOWPAN_IPHC_FLAG_DCI 0x0f
+/* Offsets for extracting integer fields. */
+#define LOWPAN_IPHC_FLAG_OFFSET_FLOW 11
+#define LOWPAN_IPHC_FLAG_OFFSET_HLIM 8
+#define LOWPAN_IPHC_FLAG_OFFSET_SRC_MODE 4
+#define LOWPAN_IPHC_FLAG_OFFSET_DST_MODE 0
+#define LOWPAN_IPHC_FLAG_OFFSET_SCI 4
+#define LOWPAN_IPHC_FLAG_OFFSET_DCI 0
+
+/* IPHC Flow encoding values. */
+#define LOWPAN_IPHC_FLOW_CLASS_LABEL 0x0
+#define LOWPAN_IPHC_FLOW_ECN_LABEL 0x1
+#define LOWPAN_IPHC_FLOW_CLASS 0x2
+#define LOWPAN_IPHC_FLOW_COMPRESSED 0x3
+
+/* IPHC Hop limit encoding. */
+#define LOWPAN_IPHC_HLIM_INLINE 0x0
+#define LOWPAN_IPHC_HLIM_1 0x1
+#define LOWPAN_IPHC_HLIM_64 0x2
+#define LOWPAN_IPHC_HLIM_255 0x3
+
+/* IPHC address modes. */
+#define LOWPAN_IPHC_ADDR_SRC_UNSPEC 0x0
+#define LOWPAN_IPHC_ADDR_FULL_INLINE 0x0
+#define LOWPAN_IPHC_ADDR_64BIT_INLINE 0x1
+#define LOWPAN_IPHC_ADDR_16BIT_INLINE 0x2
+#define LOWPAN_IPHC_ADDR_COMPRESSED 0x3
+
+/* IPHC multicast address modes. */
+#define LOWPAN_IPHC_MCAST_FULL 0x0
+#define LOWPAN_IPHC_MCAST_48BIT 0x1
+#define LOWPAN_IPHC_MCAST_32BIT 0x2
+#define LOWPAN_IPHC_MCAST_8BIT 0x3
+
+#define LOWPAN_IPHC_MCAST_STATEFUL_48BIT 0x0
+
+/* IPHC Traffic class and flow label field sizes (in bits) */
+#define LOWPAN_IPHC_ECN_BITS 2
+#define LOWPAN_IPHC_DSCP_BITS 6
+#define LOWPAN_IPHC_LABEL_BITS 20
+
+/* NHC Patterns. */
+#define LOWPAN_NHC_PATTERN_EXT 0x0e
+#define LOWPAN_NHC_PATTERN_EXT_BITS 4
+#define LOWPAN_NHC_PATTERN_UDP 0x1e
+#define LOWPAN_NHC_PATTERN_UDP_BITS 5
+/* IP-in-IP tunneling is handled as a separate NHC pattern. */
+#define LOWPAN_NHC_PATTERN_EXT_IPV6 ((LOWPAN_NHC_PATTERN_EXT << LOWPAN_NHC_EXT_EID_BITS) | LOWPAN_NHC_EID_IPV6)
+#define LOWPAN_NHC_PATTERN_EXT_IPV6_BITS (LOWPAN_NHC_PATTERN_EXT_BITS + LOWPAN_NHC_EXT_EID_BITS)
+
+/* NHC Extension header fields. */
+#define LOWPAN_NHC_EXT_EID 0x0e
+#define LOWPAN_NHC_EXT_EID_OFFSET 1
+#define LOWPAN_NHC_EXT_EID_BITS 3
+#define LOWPAN_NHC_EXT_NHDR 0x01
+
+/* Extension header ID codes. */
+#define LOWPAN_NHC_EID_HOP_BY_HOP 0x00
+#define LOWPAN_NHC_EID_ROUTING 0x01
+#define LOWPAN_NHC_EID_FRAGMENT 0x02
+#define LOWPAN_NHC_EID_DEST_OPTIONS 0x03
+#define LOWPAN_NHC_EID_MOBILITY 0x04
+#define LOWPAN_NHC_EID_IPV6 0x07
+
+/* NHC UDP fields. */
+#define LOWPAN_NHC_UDP_CHECKSUM 0x04
+#define LOWPAN_NHC_UDP_PORTS 0x03
+
+/* 6LoWPAN Mesh Header */
+#define LOWPAN_MESH_HEADER_V 0x20
+#define LOWPAN_MESH_HEADER_F 0x10
+#define LOWPAN_MESH_HEADER_HOPS 0x0f
+
+/* 6LoWPAN First Fragment Header */
+#define LOWPAN_FRAG_DGRAM_SIZE_BITS 11
+
+/* Uncompressed IPv6 Option types */
+#define IP6OPT_PAD1 0x00
+#define IP6OPT_PADN 0x01
+
+/* UDP port compression encoding */
+#define LOWPAN_NHC_UDP_PORT_INLINE 0x0
+#define LOWPAN_NHC_UDP_PORT_8BIT_DST 0x1
+#define LOWPAN_NHC_UDP_PORT_8BIT_SRC 0x2
+#define LOWPAN_NHC_UDP_PORT_12BIT 0x3
+
+/* Compressed port number offset. */
+#define LOWPAN_PORT_8BIT_OFFSET 0xf000
+#define LOWPAN_PORT_12BIT_OFFSET 0xf0b0
+
+/* 6LoWPAN interface identifier length. */
+#define LOWPAN_IFC_ID_LEN 8
+/* Protocol fields handles. */
+static int proto_6lowpan = -1;
+static int hf_6lowpan_pattern = -1;
+static int hf_6lowpan_nhc_pattern = -1;
+static int hf_6lowpan_padding = -1;
+
+/* Header compression fields. */
+static int hf_6lowpan_hc1_encoding = -1;
+static int hf_6lowpan_hc1_source_prefix = -1;
+static int hf_6lowpan_hc1_source_ifc = -1;
+static int hf_6lowpan_hc1_dest_prefix = -1;
+static int hf_6lowpan_hc1_dest_ifc = -1;
+static int hf_6lowpan_hc1_class = -1;
+static int hf_6lowpan_hc1_next = -1;
+static int hf_6lowpan_hc1_more = -1;
+static int hf_6lowpan_hc2_udp_encoding = -1;
+static int hf_6lowpan_hc2_udp_src = -1;
+static int hf_6lowpan_hc2_udp_dst = -1;
+static int hf_6lowpan_hc2_udp_len = -1;
+
+/* 6loRH */
+static int hf_6lowpan_pagenb = -1;
+static int hf_6lowpan_routing_header = -1;
+static int hf_6lowpan_6lorhe_length = -1;
+static int hf_6lowpan_6lorhe_size = -1;
+static int hf_6lowpan_6lorhc_size = -1;
+static int hf_6lowpan_6lorhe_type = -1;
+static int hf_6lowpan_6lorhe_hoplimit = -1;
+static int hf_6lowpan_6lorhe_bitmap = -1;
+static int hf_6lowpan_5_bit_o = -1;
+static int hf_6lowpan_5_bit_r = -1;
+static int hf_6lowpan_5_bit_f = -1;
+static int hf_6lowpan_5_bit_i = -1;
+static int hf_6lowpan_5_bit_k = -1;
+static int hf_6lowpan_sender_rank1 = -1;
+static int hf_6lowpan_sender_rank2 = -1;
+static int hf_6lowpan_rpl_instance = -1;
+static int hf_6lowpan_6lorhc_address_hop0 = -1;
+static int hf_6lowpan_6lorhc_address_hop2 = -1;
+static int hf_6lowpan_6lorhc_address_hop3 = -1;
+static int hf_6lowpan_6lorhc_address_hop4 = -1;
+static int hf_6lowpan_6lorhc_address_hop1 = -1;
+static int hf_6lowpan_6lorhc_address_src = -1;
+
+/* IPHC header field. */
+static int hf_6lowpan_iphc_flag_tf = -1;
+static int hf_6lowpan_iphc_flag_nhdr = -1;
+static int hf_6lowpan_iphc_flag_hlim = -1;
+static int hf_6lowpan_iphc_flag_cid = -1;
+static int hf_6lowpan_iphc_flag_sac = -1;
+static int hf_6lowpan_iphc_flag_sam = -1;
+static int hf_6lowpan_iphc_flag_mcast = -1;
+static int hf_6lowpan_iphc_flag_dac = -1;
+static int hf_6lowpan_iphc_flag_dam = -1;
+static int hf_6lowpan_iphc_sci = -1;
+static int hf_6lowpan_iphc_dci = -1;
+
+static int hf_6lowpan_iphc_sctx_prefix = -1;
+static int hf_6lowpan_iphc_sctx_origin = -1;
+static int hf_6lowpan_iphc_dctx_prefix = -1;
+static int hf_6lowpan_iphc_dctx_origin = -1;
+
+/* NHC IPv6 extension header fields. */
+static int hf_6lowpan_nhc_ext_eid = -1;
+static int hf_6lowpan_nhc_ext_nh = -1;
+static int hf_6lowpan_nhc_ext_next = -1;
+static int hf_6lowpan_nhc_ext_length = -1;
+static int hf_6lowpan_nhc_ext_reserved = -1;
+
+/* NHC UDP compression header fields. */
+static int hf_6lowpan_nhc_udp_checksum = -1;
+static int hf_6lowpan_nhc_udp_ports = -1;
+
+/* Inline IPv6 header fields. */
+static int hf_6lowpan_traffic_class = -1;
+static int hf_6lowpan_flow_label = -1;
+static int hf_6lowpan_ecn = -1;
+static int hf_6lowpan_dscp = -1;
+static int hf_6lowpan_next_header = -1;
+static int hf_6lowpan_hop_limit = -1;
+static int hf_6lowpan_source = -1;
+static int hf_6lowpan_dest = -1;
+
+/* Inline UDP header fields. */
+static int hf_6lowpan_udp_src = -1;
+static int hf_6lowpan_udp_dst = -1;
+static int hf_6lowpan_udp_len = -1;
+static int hf_6lowpan_udp_checksum = -1;
+
+/* Broadcast header fields. */
+static int hf_6lowpan_bcast_seqnum = -1;
+
+/* Mesh header fields. */
+static int hf_6lowpan_mesh_v = -1;
+static int hf_6lowpan_mesh_f = -1;
+static int hf_6lowpan_mesh_hops = -1;
+static int hf_6lowpan_mesh_hops8 = -1;
+static int hf_6lowpan_mesh_orig16 = -1;
+static int hf_6lowpan_mesh_orig64 = -1;
+static int hf_6lowpan_mesh_dest16 = -1;
+static int hf_6lowpan_mesh_dest64 = -1;
+
+/* Fragmentation header fields. */
+static int hf_6lowpan_frag_dgram_size = -1;
+static int hf_6lowpan_frag_dgram_tag = -1;
+static int hf_6lowpan_frag_dgram_offset = -1;
+
+/* Recoverable Fragmentation header fields. */
+static int hf_6lowpan_rfrag_congestion = -1;
+static int hf_6lowpan_rfrag_ack_requested = -1;
+static int hf_6lowpan_rfrag_dgram_tag = -1;
+static int hf_6lowpan_rfrag_sequence = -1;
+static int hf_6lowpan_rfrag_size = -1;
+static int hf_6lowpan_rfrag_dgram_size = -1;
+static int hf_6lowpan_rfrag_offset = -1;
+static int hf_6lowpan_rfrag_ack_bitmap = -1;
+
+/* Protocol tree handles. */
+static gint ett_6lowpan = -1;
+static gint ett_6lowpan_hc1 = -1;
+static gint ett_6lowpan_hc1_encoding = -1;
+static gint ett_6lowpan_hc2_udp = -1;
+static gint ett_6lowpan_iphc = -1;
+static gint ett_lowpan_routing_header_dispatch = -1;
+static gint ett_6lowpan_nhc_ext = -1;
+static gint ett_6lowpan_nhc_udp = -1;
+static gint ett_6lowpan_bcast = -1;
+static gint ett_6lowpan_mesh = -1;
+static gint ett_6lowpan_mesh_flags = -1;
+static gint ett_6lowpan_frag = -1;
+
+static expert_field ei_6lowpan_hc1_more_bits = EI_INIT;
+static expert_field ei_6lowpan_illegal_dest_addr_mode = EI_INIT;
+static expert_field ei_6lowpan_bad_ipv6_header_length = EI_INIT;
+static expert_field ei_6lowpan_bad_ext_header_length = EI_INIT;
+
+/* Subdissector handles. */
+static dissector_handle_t handle_6lowpan;
+static dissector_handle_t ipv6_handle;
+
+/* Value Strings */
+static const value_string lowpan_patterns [] = {
+ { LOWPAN_PATTERN_NALP, "Not a LoWPAN frame" },
+ { LOWPAN_PATTERN_IPV6, "Uncompressed IPv6" },
+ { LOWPAN_PATTERN_HC1, "Header compression" },
+ { LOWPAN_PATTERN_BC0, "Broadcast" },
+ { LOWPAN_PATTERN_IPHC, "IP header compression" },
+ { LOWPAN_PATTERN_ESC, "Escape" },
+ { LOWPAN_PATTERN_MESH, "Mesh" },
+ { LOWPAN_PATTERN_FRAG1, "First fragment" },
+ { LOWPAN_PATTERN_FRAGN, "Fragment" },
+ { LOWPAN_PATTERN_RFRAG, "Recoverable Fragment" },
+ { LOWPAN_PATTERN_RFRAG_ACK, "Recoverable Fragment ACK" },
+ { 0, NULL }
+};
+static const true_false_string lowpan_compression = {
+ "Compressed",
+ "Inline"
+};
+static const value_string lowpan_hc1_next [] = {
+ { LOWPAN_HC1_NEXT_NONE, "Inline" },
+ { LOWPAN_HC1_NEXT_UDP, "UDP" },
+ { LOWPAN_HC1_NEXT_ICMP, "ICMP" },
+ { LOWPAN_HC1_NEXT_TCP, "TCP" },
+ { 0, NULL }
+};
+static const value_string lowpan_iphc_traffic [] = {
+ { LOWPAN_IPHC_FLOW_CLASS_LABEL, "Traffic class and flow label inline" },
+ { LOWPAN_IPHC_FLOW_ECN_LABEL, "ECN and flow label inline" },
+ { LOWPAN_IPHC_FLOW_CLASS, "Traffic class inline" },
+ { LOWPAN_IPHC_FLOW_COMPRESSED, "Version, traffic class, and flow label compressed" },
+ { 0, NULL }
+};
+static const value_string lowpan_iphc_hop_limit [] = {
+ { LOWPAN_IPHC_HLIM_INLINE, "Inline" },
+ { LOWPAN_IPHC_HLIM_1, "1" },
+ { LOWPAN_IPHC_HLIM_64, "64" },
+ { LOWPAN_IPHC_HLIM_255, "255" },
+ { 0, NULL }
+};
+static const true_false_string lowpan_iphc_addr_compression = {
+ "Stateful",
+ "Stateless"
+};
+static const value_string lowpan_iphc_addr_modes [] = {
+ { LOWPAN_IPHC_ADDR_FULL_INLINE, "Inline" },
+ { LOWPAN_IPHC_ADDR_64BIT_INLINE,"64-bits inline" },
+ { LOWPAN_IPHC_ADDR_16BIT_INLINE,"16-bits inline" },
+ { LOWPAN_IPHC_ADDR_COMPRESSED, "Compressed" },
+ { 0, NULL }
+};
+static const value_string lowpan_iphc_saddr_stateful_modes [] = {
+ { LOWPAN_IPHC_ADDR_FULL_INLINE, "Unspecified address (::)" },
+ { LOWPAN_IPHC_ADDR_64BIT_INLINE,"64-bits inline" },
+ { LOWPAN_IPHC_ADDR_16BIT_INLINE,"16-bits inline" },
+ { LOWPAN_IPHC_ADDR_COMPRESSED, "Compressed" },
+ { 0, NULL }
+};
+static const value_string lowpan_iphc_daddr_stateful_modes [] = {
+ { LOWPAN_IPHC_ADDR_64BIT_INLINE,"64-bits inline" },
+ { LOWPAN_IPHC_ADDR_16BIT_INLINE,"16-bits inline" },
+ { LOWPAN_IPHC_ADDR_COMPRESSED, "Compressed" },
+ { 0, NULL }
+};
+static const value_string lowpan_iphc_mcast_modes [] = {
+ { LOWPAN_IPHC_MCAST_FULL, "Inline" },
+ { LOWPAN_IPHC_MCAST_48BIT, "48-bits inline" },
+ { LOWPAN_IPHC_MCAST_32BIT, "32-bits inline" },
+ { LOWPAN_IPHC_MCAST_8BIT, "8-bits inline" },
+ { 0, NULL }
+};
+static const value_string lowpan_iphc_mcast_stateful_modes [] = {
+ { LOWPAN_IPHC_MCAST_STATEFUL_48BIT, "48-bits inline" },
+ { 0, NULL }
+};
+static const value_string lowpan_nhc_patterns [] = {
+ { LOWPAN_NHC_PATTERN_EXT, "IPv6 extension header" },
+ { LOWPAN_NHC_PATTERN_UDP, "UDP compression header" },
+ { 0, NULL }
+};
+static const value_string lowpan_nhc_eid [] = {
+ { LOWPAN_NHC_EID_HOP_BY_HOP, "IPv6 hop-by-hop options" },
+ { LOWPAN_NHC_EID_ROUTING, "IPv6 routing" },
+ { LOWPAN_NHC_EID_FRAGMENT, "IPv6 fragment" },
+ { LOWPAN_NHC_EID_DEST_OPTIONS, "IPv6 destination options" },
+ { LOWPAN_NHC_EID_MOBILITY, "IPv6 mobility header" },
+ { LOWPAN_NHC_EID_IPV6, "IPv6 header" },
+ { 0, NULL }
+};
+static const value_string lowpan_udp_ports [] = {
+ { LOWPAN_NHC_UDP_PORT_INLINE, "Inline" },
+ { LOWPAN_NHC_UDP_PORT_8BIT_DST, "Source port inline, first 8 bits of destination port elided" },
+ { LOWPAN_NHC_UDP_PORT_8BIT_SRC, "Destination port inline, first 8 bits of source port elided" },
+ { LOWPAN_NHC_UDP_PORT_12BIT, "12 bits of both ports elided" },
+ { 0, NULL }
+};
+/* 6loRH */
+static const value_string lowpan_patterns_rh_type [] = {
+ { LOWPAN_PATTERN_6LORH_TYPE0, "Routing Header 3, 1 byte compression" },
+ { LOWPAN_PATTERN_6LORH_TYPE1, "Routing Header 3, 2 byte compression" },
+ { LOWPAN_PATTERN_6LORH_TYPE2, "Routing Header 3, 4 byte compression" },
+ { LOWPAN_PATTERN_6LORH_TYPE3, "Routing Header 3, 8 byte compression" },
+ { LOWPAN_PATTERN_6LORH_TYPE4, "Routing Header 3, 16 byte compression" },
+ { LOWPAN_PATTERN_6LORH_TYPE5, "Routing Protocol Information" },
+ { LOWPAN_PATTERN_6LORH_TYPE6, "IP in IP" },
+ { LOWPAN_PATTERN_6LORH_TYPE15, "BIER Header, bit-by-bit encoding, no control fields, 32 bits word size" },
+ { LOWPAN_PATTERN_6LORH_TYPE16, "BIER Header, Bloom filter encoding, 2* 1-byte HashID control fields, 32 bits word size" },
+ { LOWPAN_PATTERN_6LORH_TYPE17, "BIER Header, bit-by-bit encoding, no control fields, 128 bits word size" },
+ { LOWPAN_PATTERN_6LORH_TYPE18, "BIER Header, Bloom filter encoding, 8* 1-byte HashID control fields, 128 bits word size" },
+ { LOWPAN_PATTERN_6LORH_TYPE19, "BIER Header, bit-by-bit encoding, 1-byte GroupID control fields, 128 bits word size" },
+ { 0, NULL }
+};
+static const value_string lowpan_patterns_rh [] = {
+ { LOWPAN_PATTERN_6LORHC, "Critical Routing Header" },
+ { LOWPAN_PATTERN_6LORHE, "Elective Routing Header" },
+ { 0, NULL }
+};
+static const true_false_string bit_I_RPL = {
+ "Elided (RPL Instance ID: 0)",
+ "Present"
+};
+static const true_false_string bit_K_RPL = {
+ "1 byte",
+ "2 bytes"
+};
+
+/* Reassembly Data */
+static int hf_6lowpan_fragments = -1;
+static int hf_6lowpan_fragment = -1;
+static int hf_6lowpan_fragment_overlap = -1;
+static int hf_6lowpan_fragment_overlap_conflicts = -1;
+static int hf_6lowpan_fragment_multiple_tails = -1;
+static int hf_6lowpan_fragment_too_long_fragment = -1;
+static int hf_6lowpan_fragment_error = -1;
+static int hf_6lowpan_fragment_count = -1;
+static int hf_6lowpan_reassembled_in = -1;
+static int hf_6lowpan_reassembled_length = -1;
+static gint ett_6lowpan_fragment = -1;
+static gint ett_6lowpan_fragments = -1;
+
+static const fragment_items lowpan_frag_items = {
+ /* Fragment subtrees */
+ &ett_6lowpan_fragment,
+ &ett_6lowpan_fragments,
+ /* Fragment fields */
+ &hf_6lowpan_fragments,
+ &hf_6lowpan_fragment,
+ &hf_6lowpan_fragment_overlap,
+ &hf_6lowpan_fragment_overlap_conflicts,
+ &hf_6lowpan_fragment_multiple_tails,
+ &hf_6lowpan_fragment_too_long_fragment,
+ &hf_6lowpan_fragment_error,
+ &hf_6lowpan_fragment_count,
+ /* Reassembled in field */
+ &hf_6lowpan_reassembled_in,
+ /* Reassembled length field */
+ &hf_6lowpan_reassembled_length,
+ /* Reassembled data field */
+ NULL,
+ /* Tag */
+ "6LoWPAN fragments"
+};
+
+static reassembly_table lowpan_reassembly_table;
+static GHashTable *lowpan_context_table = NULL;
+
+/* Link-Local prefix used by 6LoWPAN (FF80::/10) */
+static const guint8 lowpan_llprefix[8] = {
+ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* Context hash table map key. */
+typedef struct {
+ guint16 pan; /* PAN Identifier */
+ guint8 cid; /* Context Identifier */
+} lowpan_context_key;
+
+/* Context hash table map data. */
+typedef struct {
+ guint frame; /* Frame where the context was discovered. */
+ guint8 plen; /* Prefix length. */
+ ws_in6_addr prefix; /* Compression context. */
+} lowpan_context_data;
+
+/* 6LoWPAN contexts. */
+#define LOWPAN_CONTEXT_MAX 16
+#define LOWPAN_CONTEXT_DEFAULT 0
+#define LOWPAN_CONTEXT_LINK_LOCAL LOWPAN_CONTEXT_MAX
+#define LOWPAN_CONTEXT_LINK_LOCAL_BITS 10
+static lowpan_context_data lowpan_context_local;
+static lowpan_context_data lowpan_context_default;
+static const gchar * lowpan_context_prefs[LOWPAN_CONTEXT_MAX];
+
+/* Preferences */
+static gboolean rfc4944_short_address_format = FALSE;
+static gboolean iid_has_universal_local_bit = FALSE;
+static gboolean ipv6_summary_in_tree = TRUE;
+
+/* Helper macro to convert a bit offset/length into a byte count. */
+#define BITS_TO_BYTE_LEN(bitoff, bitlen) ((bitlen)?(((bitlen) + ((bitoff)&0x07) + 7) >> 3):(0))
+
+/* Structure for rebuilding UDP datagrams. */
+struct udp_hdr {
+ guint16 src_port;
+ guint16 dst_port;
+ guint16 length;
+ guint16 checksum;
+};
+
+/* Structure used to store decompressed header chains until reassembly. */
+struct lowpan_nhdr {
+ /* List Linking */
+ struct lowpan_nhdr *next;
+ /* Next Header */
+ guint8 proto;
+ guint length;
+ guint reported;
+};
+#define LOWPAN_NHDR_DATA(nhdr) ((guint8 *)(nhdr) + sizeof (struct lowpan_nhdr))
+
+/* Dissector prototypes */
+static void proto_init_6lowpan (void);
+static void prefs_6lowpan_apply (void);
+static int dissect_6lowpan (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
+static tvbuff_t * dissect_6lowpan_ipv6 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static tvbuff_t * dissect_6lowpan_hc1 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint dgram_size, const guint8 *siid, const guint8 *diid);
+static tvbuff_t * dissect_6lowpan_bc0 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static tvbuff_t * dissect_6lowpan_iphc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint dgram_size, const guint8 *siid, const guint8 *diid);
+static struct lowpan_nhdr *
+ dissect_6lowpan_iphc_nhc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, gint dgram_size, const guint8 *siid, const guint8 *diid);
+static tvbuff_t * dissect_6lowpan_mesh (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 *siid, guint8 *diid);
+static tvbuff_t * dissect_6lowpan_rfrag (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const guint8 *siid, const guint8 *diid);
+static tvbuff_t * dissect_6lowpan_rfrag_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static tvbuff_t * dissect_6lowpan_frag_first (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const guint8 *siid, const guint8 *diid);
+static tvbuff_t * dissect_6lowpan_frag_middle (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static void dissect_6lowpan_unknown (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static tvbuff_t * dissect_6lowpan_6loRH (tvbuff_t *tvb, guint offset, proto_tree *tree);
+
+
+/* Helper functions. */
+static gboolean lowpan_dlsrc_to_ifcid (packet_info *pinfo, guint8 *ifcid);
+static gboolean lowpan_dldst_to_ifcid (packet_info *pinfo, guint8 *ifcid);
+static void lowpan_addr16_to_ifcid (guint16 addr, guint8 *ifcid);
+static void lowpan_addr16_with_panid_to_ifcid(guint16 panid, guint16 addr, guint8 *ifcid);
+static void lowpan_addr48_to_ifcid (const guint8 *addr, guint8 *ifcid);
+static tvbuff_t * lowpan_reassemble_ipv6 (tvbuff_t *tvb, packet_info *pinfo, struct ws_ip6_hdr *ipv6, struct lowpan_nhdr *nhdr_list);
+static guint8 lowpan_parse_nhc_proto (tvbuff_t *tvb, gint offset);
+
+/* Context table helpers */
+static guint lowpan_context_hash (gconstpointer key);
+static gboolean lowpan_context_equal (gconstpointer a, gconstpointer b);
+static lowpan_context_data *lowpan_context_find(guint8 cid, guint16 pan);
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_pfxcpy
+ * DESCRIPTION
+ * A version of memcpy that takes a length in bits. If the
+ * length is not byte-aligned, the final byte will be
+ * manipulated so that only the desired number of bits are
+ * copied.
+ * PARAMETERS
+ * dst ; Destination.
+ * src ; Source.
+ * bits ; Number of bits to copy.
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+static void
+lowpan_pfxcpy(void *dst, const void *src, size_t bits)
+{
+ memcpy(dst, src, bits>>3);
+ if (bits & 0x7) {
+ guint8 mask = ((0xff00) >> (bits & 0x7));
+ guint8 last = ((const guint8 *)src)[bits>>3] & mask;
+ ((guint8 *)dst)[bits>>3] &= ~mask;
+ ((guint8 *)dst)[bits>>3] |= last;
+ }
+} /* lowpan_pfxcpy */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_context_hash
+ * DESCRIPTION
+ * Context table hash function.
+ * PARAMETERS
+ * key ; Pointer to a lowpan_context_key type.
+ * RETURNS
+ * guint ; The hashed key value.
+ *---------------------------------------------------------------
+ */
+static guint
+lowpan_context_hash(gconstpointer key)
+{
+ return (((const lowpan_context_key *)key)->cid) | (((const lowpan_context_key *)key)->pan << 8);
+} /* lowpan_context_hash */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_context_equal
+ * DESCRIPTION
+ * Context table equals function.
+ * PARAMETERS
+ * key ; Pointer to a lowpan_context_key type.
+ * RETURNS
+ * gboolean ;
+ *---------------------------------------------------------------
+ */
+static gboolean
+lowpan_context_equal(gconstpointer a, gconstpointer b)
+{
+ return (((const lowpan_context_key *)a)->pan == ((const lowpan_context_key *)b)->pan) &&
+ (((const lowpan_context_key *)a)->cid == ((const lowpan_context_key *)b)->cid);
+} /* lowpan_context_equal */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_context_find
+ * DESCRIPTION
+ * Context table lookup function.
+ * PARAMETERS
+ * cid ; Context identifier.
+ * pan ; PAN identifier.
+ * RETURNS
+ * lowpan_context_data *;
+ *---------------------------------------------------------------
+ */
+static lowpan_context_data *
+lowpan_context_find(guint8 cid, guint16 pan)
+{
+ lowpan_context_key key;
+ lowpan_context_data *data;
+
+ /* Check for the internal link-local context. */
+ if (cid == LOWPAN_CONTEXT_LINK_LOCAL) return &lowpan_context_local;
+
+ /* Lookup the context from the table. */
+ key.pan = pan;
+ key.cid = cid;
+ data = (lowpan_context_data *)g_hash_table_lookup(lowpan_context_table, &key);
+ if (data) return data;
+
+ /* If we didn't find a match, try again with the broadcast PAN. */
+ if (pan != IEEE802154_BCAST_PAN) {
+ key.pan = IEEE802154_BCAST_PAN;
+ data = (lowpan_context_data *)g_hash_table_lookup(lowpan_context_table, &key);
+ if (data) return data;
+ }
+
+ /* If the lookup failed, return the default context (::/0) */
+ return &lowpan_context_default;
+} /* lowpan_context_find */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_context_insert
+ * DESCRIPTION
+ * Context table insert function.
+ * PARAMETERS
+ * cid ; Context identifier.
+ * pan ; PAN identifier.
+ * plen ; Prefix length.
+ * prefix ; Compression prefix.
+ * frame ; Frame number.
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+void
+lowpan_context_insert(guint8 cid, guint16 pan, guint8 plen, ws_in6_addr *prefix, guint frame)
+{
+ lowpan_context_key key;
+ lowpan_context_data *data;
+ gpointer pkey;
+ gpointer pdata;
+
+ /* Sanity! */
+ if (plen > 128) return;
+ if (!prefix) return;
+ if (!lowpan_context_table) return;
+
+ /* Search the context table for an existing entry. */
+ key.pan = pan;
+ key.cid = cid;
+ if (g_hash_table_lookup_extended(lowpan_context_table, &key, NULL, &pdata)) {
+ /* Context already exists. */
+ data = (lowpan_context_data *)pdata;
+ if ( (data->plen == plen) && (memcmp(&data->prefix, prefix, (plen+7)/8) == 0) ) {
+ /* Context already exists with no change. */
+ return;
+ }
+ }
+ pkey = wmem_memdup(NULL, &key, sizeof(key));
+
+ /* Create a new context */
+ data = wmem_new(NULL, lowpan_context_data);
+ data->frame = frame;
+ data->plen = plen;
+ memset(&data->prefix, 0, sizeof(ws_in6_addr)); /* Ensure zero paddeding */
+ lowpan_pfxcpy(&data->prefix, prefix, plen);
+ g_hash_table_insert(lowpan_context_table, pkey, data);
+} /* lowpan_context_insert */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_context_free
+ * DESCRIPTION
+ * Frees the allocated memory for the context hash table
+ * PARAMETERS
+ * data ; Pointer to key or value
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+static void
+lowpan_context_free(gpointer data)
+{
+ wmem_free(NULL, data);
+} /* lowpan_context_free */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_addr16_to_ifcid
+ * DESCRIPTION
+ * Converts a short address to in interface identifier as
+ * per rfc 6282 section 3.2.2.
+ * PARAMETERS
+ * addr ; 16-bit short address.
+ * ifcid ; interface identifier (output).
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+static void
+lowpan_addr16_to_ifcid(guint16 addr, guint8 *ifcid)
+{
+ /* Note: The PANID is no longer used in building the IID. */
+ ifcid[0] = 0x00; /* the U/L bit must be cleared. */
+ ifcid[1] = 0x00;
+ ifcid[2] = 0x00;
+ ifcid[3] = 0xff;
+ ifcid[4] = 0xfe;
+ ifcid[5] = 0x00;
+ ifcid[6] = (addr >> 8) & 0xff;
+ ifcid[7] = (addr >> 0) & 0xff;
+} /* lowpan_addr16_to_ifcid */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_addr16_with_panid_to_ifcid
+ * DESCRIPTION
+ * Converts a short address to in interface identifier as
+ * per rfc 4944 section 6.
+ * PARAMETERS
+ * panid ; 16-bit PAN ID.
+ * addr ; 16-bit short address.
+ * ifcid ; interface identifier (output).
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+static void
+lowpan_addr16_with_panid_to_ifcid(guint16 panid, guint16 addr, guint8 *ifcid)
+{
+ /* Note: The PANID is used in building the IID following RFC 2464 section 4. */
+ ifcid[0] = (panid >> 8) & 0xfd; /* the U/L bit must be cleared. */
+ ifcid[1] = (panid >> 0) & 0xff;
+ ifcid[2] = 0x00;
+ ifcid[3] = 0xff;
+ ifcid[4] = 0xfe;
+ ifcid[5] = 0x00;
+ ifcid[6] = (addr >> 8) & 0xff;
+ ifcid[7] = (addr >> 0) & 0xff;
+} /* lowpan_addr16_with_panid_to_ifcid */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_addr48_to_ifcid
+ * DESCRIPTION
+ * Converts an IEEE 48-bit MAC identifier to an interface
+ * identifier as per RFC 4291 Appendix A.
+ * PARAMETERS
+ * addr ; 48-bit MAC identifier.
+ * ifcid ; interface identifier (output).
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+static void
+lowpan_addr48_to_ifcid(const guint8 *addr, guint8 *ifcid)
+{
+ static const guint8 unknown_addr[] = { 0, 0, 0, 0, 0, 0 };
+
+ /* Don't convert unknown addresses */
+ if (memcmp(addr, unknown_addr, sizeof(unknown_addr)) != 0) {
+ ifcid[0] = addr[0];
+ ifcid[1] = addr[1];
+ ifcid[2] = addr[2];
+ ifcid[3] = 0xff;
+ ifcid[4] = 0xfe;
+ ifcid[5] = addr[3];
+ ifcid[6] = addr[4];
+ ifcid[7] = addr[5];
+ if (iid_has_universal_local_bit) {
+ ifcid[0] ^= 0x02; /* Invert the U/L bit. */
+ }
+ } else {
+ memset(ifcid, 0, LOWPAN_IFC_ID_LEN);
+ }
+} /* lowpan_ether_to_ifcid */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_dlsrc_to_ifcid
+ * DESCRIPTION
+ * Finds an interface identifier from the data-link source
+ * addressing.
+ * PARAMETERS
+ * pinfo ; packet information.
+ * ifcid ; interface identifier (output).
+ * RETURNS
+ * gboolean ; TRUE if an interface identifier could
+ * be found.
+ *---------------------------------------------------------------
+ */
+static gboolean
+lowpan_dlsrc_to_ifcid(packet_info *pinfo, guint8 *ifcid)
+{
+ ieee802154_hints_t *hints;
+
+ /* Check the link-layer address field. */
+ if (pinfo->dl_src.type == AT_EUI64) {
+ memcpy(ifcid, pinfo->dl_src.data, LOWPAN_IFC_ID_LEN);
+ /* RFC2464: Invert the U/L bit when using an EUI64 address. */
+ ifcid[0] ^= 0x02;
+ return TRUE;
+ } else if (pinfo->dl_src.type == AT_ETHER) {
+ lowpan_addr48_to_ifcid((const guint8 *)pinfo->dl_src.data, ifcid);
+ return TRUE;
+ }
+
+ /* Lookup the IEEE 802.15.4 addressing hints. */
+ hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo,
+ proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN), 0);
+ if (hints) {
+
+ /* Convert the 16-bit short address to an IID using the PAN ID (RFC 4944) or not depending on the preference */
+ if (rfc4944_short_address_format) {
+ lowpan_addr16_with_panid_to_ifcid(hints->src_pan, hints->src16, ifcid);
+ } else {
+ lowpan_addr16_to_ifcid(hints->src16, ifcid);
+ }
+
+ return TRUE;
+ } else {
+ /* Failed to find a link-layer source address. */
+ memset(ifcid, 0, LOWPAN_IFC_ID_LEN);
+ return FALSE;
+ }
+} /* lowpan_dlsrc_to_ifcid */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_dldst_to_ifcid
+ * DESCRIPTION
+ * Finds an interface identifier from the data-link destination
+ * addressing.
+ * PARAMETERS
+ * pinfo ; packet information.
+ * ifcid ; interface identifier (output).
+ * RETURNS
+ * gboolean ; TRUE if an interface identifier could
+ * be found.
+ *---------------------------------------------------------------
+ */
+static gboolean
+lowpan_dldst_to_ifcid(packet_info *pinfo, guint8 *ifcid)
+{
+ ieee802154_hints_t *hints;
+
+ /* Check the link-layer address field. */
+ if (pinfo->dl_dst.type == AT_EUI64) {
+ memcpy(ifcid, pinfo->dl_dst.data, LOWPAN_IFC_ID_LEN);
+ /* RFC2464: Invert the U/L bit when using an EUI64 address. */
+ ifcid[0] ^= 0x02;
+ return TRUE;
+ } else if (pinfo->dl_dst.type == AT_ETHER) {
+ lowpan_addr48_to_ifcid((const guint8 *)pinfo->dl_dst.data, ifcid);
+ return TRUE;
+ }
+
+ /* Lookup the IEEE 802.15.4 addressing hints. */
+ hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo,
+ proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN), 0);
+ if (hints) {
+
+ /* Convert the 16-bit short address to an IID using the PAN ID (RFC 4944) or not depending on the preference */
+ if (rfc4944_short_address_format) {
+ lowpan_addr16_with_panid_to_ifcid(hints->src_pan, hints->dst16, ifcid);
+ } else {
+ lowpan_addr16_to_ifcid(hints->dst16, ifcid);
+ }
+
+ return TRUE;
+ } else {
+ /* Failed to find a link-layer destination address. */
+ memset(ifcid, 0, LOWPAN_IFC_ID_LEN);
+ return FALSE;
+ }
+} /* lowpan_dldst_to_ifcid */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_reassemble_ipv6
+ * DESCRIPTION
+ * Helper function to rebuild an IPv6 packet from the IPv6
+ * header structure, and a list of next header structures.
+ * PARAMETERS
+ * ipv6 ; IPv6 Header.
+ * nhdr_list ; Next header list.
+ * RETURNS
+ * tvbuff_t * ; Reassembled IPv6 packet.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+lowpan_reassemble_ipv6(tvbuff_t *tvb, packet_info *pinfo, struct ws_ip6_hdr *ipv6, struct lowpan_nhdr *nhdr_list)
+{
+ gint length = 0;
+ gint reported = 0;
+ guint8 * buffer;
+ guint8 * cursor;
+ struct lowpan_nhdr *nhdr;
+
+ /* Compute the real and reported lengths. */
+ for (nhdr = nhdr_list; nhdr; nhdr = nhdr->next) {
+ length += nhdr->length;
+ reported += nhdr->reported;
+ }
+ ipv6->ip6h_plen = g_ntohs(reported);
+
+ /* Allocate a buffer for the packet and copy in the IPv6 header. */
+ buffer = (guint8 *)wmem_alloc(pinfo->pool, length + IPv6_HDR_SIZE);
+ memcpy(buffer, ipv6, IPv6_HDR_SIZE);
+ cursor = buffer + IPv6_HDR_SIZE;
+
+ /* Add the next headers into the buffer. */
+ for (nhdr = nhdr_list; nhdr; nhdr = nhdr->next) {
+ memcpy(cursor, LOWPAN_NHDR_DATA(nhdr), nhdr->length);
+ cursor += nhdr->length;
+ };
+
+ /* Return the reassembled packet. */
+ return tvb_new_child_real_data(tvb, buffer, length + IPv6_HDR_SIZE, reported + IPv6_HDR_SIZE);
+} /* lowpan_reassemble_ipv6 */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_parse_nhc_proto
+ * DESCRIPTION
+ * Parses the start of an 6LoWPAN NHC header to determine the
+ * next header protocol identifier. Will return IP_PROTO_NONE
+ * if no valid protocol could be determined.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * offset ; offset of the NHC.
+ * RETURNS
+ * guint8 ; IP_PROTO_* of the next header's protocol.
+ *---------------------------------------------------------------
+ */
+static guint8
+lowpan_parse_nhc_proto(tvbuff_t *tvb, gint offset)
+{
+ /* Ensure that at least one byte exists. */
+ if (!tvb_bytes_exist(tvb, offset, 1)) return IP_PROTO_NONE;
+
+ /* Check for IPv6 extension headers. */
+ if (tvb_get_bits8(tvb, offset<<3, LOWPAN_NHC_PATTERN_EXT_BITS) == LOWPAN_NHC_PATTERN_EXT) {
+ guint8 eid = (tvb_get_guint8(tvb, offset) & LOWPAN_NHC_EXT_EID) >> LOWPAN_NHC_EXT_EID_OFFSET;
+ switch (eid) {
+ case LOWPAN_NHC_EID_HOP_BY_HOP:
+ return IP_PROTO_HOPOPTS;
+ case LOWPAN_NHC_EID_ROUTING:
+ return IP_PROTO_ROUTING;
+ case LOWPAN_NHC_EID_FRAGMENT:
+ return IP_PROTO_FRAGMENT;
+ case LOWPAN_NHC_EID_DEST_OPTIONS:
+ return IP_PROTO_DSTOPTS;
+ case LOWPAN_NHC_EID_MOBILITY:
+ return IP_PROTO_MIPV6;
+ case LOWPAN_NHC_EID_IPV6:
+ return IP_PROTO_IPV6;
+ default:
+ /* Unknown protocol type. */
+ return IP_PROTO_NONE;
+ };
+ }
+ /* Check for compressed UDP headers. */
+ if (tvb_get_bits8(tvb, offset<<3, LOWPAN_NHC_PATTERN_UDP_BITS) == LOWPAN_NHC_PATTERN_UDP) {
+ return IP_PROTO_UDP;
+ }
+ /* Unknown header type. */
+ return IP_PROTO_NONE;
+} /* lowpan_parse_nhc_proto */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * lowpan_reassembly_id
+ * DESCRIPTION
+ * Creates an identifier that groups fragments based on the given datagram
+ * tag and the link layer destination address (to differentiate packets
+ * forwarded over different links in a mesh network).
+ * PARAMETERS
+ * pinfo : packet info.
+ * dgram_tag ; datagram tag (from the Fragmentation Header).
+ * RETURNS
+ * guint32 ; identifier for this group of fragments.
+ *---------------------------------------------------------------
+ */
+static guint32
+lowpan_reassembly_id(packet_info *pinfo, guint16 dgram_tag)
+{
+ /* Start with the datagram tag for identification. If the packet is not
+ * being forwarded, then this should be sufficient to prevent collisions
+ * which could break reassembly. */
+ guint32 frag_id = dgram_tag;
+ ieee802154_hints_t *hints;
+
+ /* Forwarded packets in a mesh network have the same datagram tag, mix
+ * the IEEE 802.15.4 destination link layer address. */
+ if (pinfo->dl_dst.type == AT_EUI64) {
+ /* IEEE 64-bit extended address */
+ frag_id = add_address_to_hash(frag_id, &pinfo->dl_dst);
+ } else {
+ /* 16-bit short address */
+ hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo,
+ proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN), 0);
+ if (hints) {
+ frag_id |= hints->dst16 << 16;
+ }
+ }
+ return frag_id;
+} /* lowpan_reassembly_id */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_heur
+ * DESCRIPTION
+ * Heuristic dissector for 6LoWPAN. Checks if the pattern is
+ * a valid 6LoWPAN type, and not NALP.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; protocol display tree.
+ * data : ieee802154_packet,
+ * RETURNS
+ * boolean ; TRUE if the tvbuff was dissected as a
+ * 6LoWPAN packet. If this returns FALSE,
+ * then no dissection will be attempted.
+ *---------------------------------------------------------------
+ */
+static gboolean
+dissect_6lowpan_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ guint offset = 0;
+
+ /* Check for valid patterns. */
+ for (;;) {
+ /* Parse patterns until we find a match. */
+ if (!tvb_reported_length_remaining(tvb, offset)) return FALSE;
+ if (tvb_get_bits8(tvb, offset*8, LOWPAN_PATTERN_IPV6_BITS) == LOWPAN_PATTERN_IPV6) break;
+ if (tvb_get_bits8(tvb, offset*8, LOWPAN_PATTERN_HC1_BITS) == LOWPAN_PATTERN_HC1) break;
+ if (tvb_get_bits8(tvb, offset*8, LOWPAN_PATTERN_BC0_BITS) == LOWPAN_PATTERN_BC0) {
+ /* Broadcast headers must be followed by another valid header. */
+ offset += 2;
+ continue;
+ }
+ if (tvb_get_bits8(tvb, offset*8, LOWPAN_PATTERN_IPHC_BITS) == LOWPAN_PATTERN_IPHC) break;
+ if (tvb_get_bits8(tvb, offset*8, LOWPAN_PATTERN_MESH_BITS) == LOWPAN_PATTERN_MESH) {
+ /* Mesh headers must be followed by another valid header. */
+ guint8 mesh = tvb_get_guint8(tvb, offset++);
+ offset += (mesh & LOWPAN_MESH_HEADER_V) ? 2 : 8;
+ offset += (mesh & LOWPAN_MESH_HEADER_F) ? 2 : 8;
+ if ((mesh & LOWPAN_MESH_HEADER_HOPS) == LOWPAN_MESH_HEADER_HOPS) offset++;
+ continue;
+ }
+ if (tvb_get_bits8(tvb, offset*8, LOWPAN_PATTERN_RFRAG_BITS) == LOWPAN_PATTERN_RFRAG) break;
+ if (tvb_get_bits8(tvb, offset*8, LOWPAN_PATTERN_RFRAG_BITS) == LOWPAN_PATTERN_RFRAG_ACK) break;
+ if (tvb_get_bits8(tvb, offset*8, LOWPAN_PATTERN_FRAG_BITS) == LOWPAN_PATTERN_FRAG1) {
+ /* First fragment headers must be followed by another valid header. */
+ offset += 4;
+ continue;
+ }
+ if (tvb_get_bits8(tvb, offset*8, LOWPAN_PATTERN_FRAG_BITS) == LOWPAN_PATTERN_FRAGN) break;
+
+ /* If we get here, then we couldn't match to any pattern. */
+ return FALSE;
+ } /* for */
+
+ /* If we get here, then we found a matching pattern. */
+ dissect_6lowpan(tvb, pinfo, tree, data);
+ return TRUE;
+} /* dissect_6lowpan_heur */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan
+ * DESCRIPTION
+ * Dissector routine for 6LoWPAN packets.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; protocol display tree.
+ * data ; Packet data (ieee 802.15.4).
+ * RETURNS
+ * int ; Length of data processed, or 0 if not 6LoWPAN.
+ *---------------------------------------------------------------
+ */
+static int
+dissect_6lowpan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ proto_tree *lowpan_tree;
+ proto_item *lowpan_root;
+ tvbuff_t *next = tvb;
+ guint offset = 0;
+ /* Interface identifier of the encapsulating layer. */
+ guint8 src_iid[LOWPAN_IFC_ID_LEN];
+ guint8 dst_iid[LOWPAN_IFC_ID_LEN];
+
+ /* Get the interface identifiers from the encapsulating layer. */
+ lowpan_dlsrc_to_ifcid(pinfo, src_iid);
+ lowpan_dldst_to_ifcid(pinfo, dst_iid);
+
+ /* Create the protocol tree. */
+ lowpan_root = proto_tree_add_protocol_format(tree, proto_6lowpan, tvb, 0, -1, "6LoWPAN");
+ lowpan_tree = proto_item_add_subtree(lowpan_root, ett_6lowpan);
+
+ /* Add the protocol name. */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "6LoWPAN");
+
+ /* Mesh and Broadcast headers always come first in a 6LoWPAN frame. */
+ if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_MESH_BITS) == LOWPAN_PATTERN_MESH) {
+ next = dissect_6lowpan_mesh(next, pinfo, lowpan_tree, src_iid, dst_iid);
+ if (!next) return tvb_captured_length(tvb);
+ }
+ if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_BC0_BITS) == LOWPAN_PATTERN_BC0) {
+ next = dissect_6lowpan_bc0(next, pinfo, lowpan_tree);
+ if (!next) return tvb_captured_length(tvb);
+ }
+
+ /* After the mesh and broadcast headers, process dispatch codes recursively. */
+ /* Recoverable Fragmentation headers.*/
+ if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_RFRAG_BITS) == LOWPAN_PATTERN_RFRAG) {
+ next = dissect_6lowpan_rfrag(next, pinfo, lowpan_tree, src_iid, dst_iid);
+ if (!next) return tvb_captured_length(tvb);
+ }
+ else if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_RFRAG_BITS) == LOWPAN_PATTERN_RFRAG_ACK) {
+ next = dissect_6lowpan_rfrag_ack(next, pinfo, lowpan_tree);
+ if (!next) return tvb_captured_length(tvb);
+ }
+ /* Fragmentation headers.*/
+ if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_FRAG_BITS) == LOWPAN_PATTERN_FRAG1) {
+ next = dissect_6lowpan_frag_first(next, pinfo, lowpan_tree, src_iid, dst_iid);
+ }
+ else if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_FRAG_BITS) == LOWPAN_PATTERN_FRAGN) {
+ next = dissect_6lowpan_frag_middle(next, pinfo, lowpan_tree);
+ }
+ /* Uncompressed IPv6 packets. */
+ else if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_IPV6_BITS) == LOWPAN_PATTERN_IPV6) {
+ next = dissect_6lowpan_ipv6(next, pinfo, lowpan_tree);
+ }
+ else if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_PAGING_DISPATCH_BITS) == LOWPAN_PATTERN_PAGING_DISPATCH) {
+ proto_tree_add_bits_item(lowpan_tree, hf_6lowpan_pagenb, tvb, 4, 4, ENC_BIG_ENDIAN);
+ offset += 1;
+ next = dissect_6lowpan_6loRH(next, offset, lowpan_tree);
+ if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_IPHC_BITS) == LOWPAN_PATTERN_IPHC) {
+ next = dissect_6lowpan_iphc(next, pinfo, lowpan_tree, -1, src_iid, dst_iid);
+ if (!next) return tvb_captured_length(tvb);
+ }
+ if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_HC1_BITS) == LOWPAN_PATTERN_HC1) {
+ next = dissect_6lowpan_hc1(next, pinfo, lowpan_tree, -1, src_iid, dst_iid);
+ }
+ }
+ /* Compressed IPv6 packets. */
+ else if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_HC1_BITS) == LOWPAN_PATTERN_HC1) {
+ next = dissect_6lowpan_hc1(next, pinfo, lowpan_tree, -1, src_iid, dst_iid);
+ }
+ else if (tvb_get_bits8(next, 0, LOWPAN_PATTERN_IPHC_BITS) == LOWPAN_PATTERN_IPHC) {
+ next = dissect_6lowpan_iphc(next, pinfo, lowpan_tree, -1, src_iid, dst_iid);
+ }
+ /* Unknown 6LoWPAN dispatch type */
+ else {
+ dissect_6lowpan_unknown(next, pinfo, lowpan_tree);
+ return tvb_captured_length(tvb);
+ }
+
+ /* The last step should have returned an uncompressed IPv6 datagram. */
+ if (next) {
+ call_dissector(ipv6_handle, next, pinfo, tree);
+ }
+ return tvb_captured_length(tvb);
+} /* dissect_6lowpan */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_6loRH
+ * DESCRIPTION
+ * Dissector routine for 6loRH fields in 6LoWPAN packets.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * offset ; offset of the 6loRH fields
+ * tree ; protocol display tree.
+ * RETURNS
+ * tvbuff_t * ; The remaining payload to be parsed.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_6loRH(tvbuff_t *tvb, guint offset, proto_tree *tree)
+{
+
+ guint16 check;
+ gint IK;
+ guint16 loRH_flags;
+ proto_tree * loRH_tree;
+ guint16 loRHE_length;
+ guint8 loRHE_type;
+ guint16 loRHE_class;
+ guint8 rpl_instance;
+ gint condition = 1;
+ gint16 loRHE_unitnums;
+
+ struct ws_ip6_hdr ipv6;
+ static int * const bits_RHC[] = {
+ &hf_6lowpan_5_bit_o,
+ &hf_6lowpan_5_bit_r,
+ &hf_6lowpan_5_bit_f,
+ &hf_6lowpan_5_bit_i,
+ &hf_6lowpan_5_bit_k,
+ NULL
+ };
+
+ loRH_flags = tvb_get_ntohs(tvb, offset);
+ check = loRH_flags & 0xC000;
+
+ if (check == LOWPAN_6LORH_GENERAL_FORMAT) {
+
+ memset(&ipv6.ip6h_src, 0, sizeof(ipv6.ip6h_src));
+
+ while(condition > 0){
+ condition -= 1 ;
+ /*Create the tree*/
+ loRH_tree = proto_tree_add_subtree(tree, tvb, offset, 2, ett_lowpan_routing_header_dispatch, NULL, "6LoRH:");
+
+ /* Get and display the pattern. */
+ proto_tree_add_bits_item(loRH_tree, hf_6lowpan_routing_header, tvb, 8*offset, LOWPAN_PATTERN_IPHC_BITS, ENC_BIG_ENDIAN);
+ /*=====================================================
+ * Parse 6LoRH Header flags.
+ *=====================================================
+ */
+
+ loRHE_class = (loRH_flags & LOWPAN_PATTERN_6LORHE_CLASS) >> LOWPAN_PATTERN_6LORHE_CLASS_BITS;
+ loRHE_length = (loRH_flags & LOWPAN_PATTERN_6LORHE_LENGTH) >> LOWPAN_PATTERN_6LORHE_LENGTH_BITS;
+ loRHE_unitnums = loRHE_length + 1;
+ loRHE_type = (loRH_flags & LOWPAN_PATTERN_6LORHE_TYPE);
+ IK = (loRH_flags & LOWPAN_5_RPI_BITS_IK) >> 8;
+
+ proto_item_append_text(loRH_tree, " %s", val_to_str_const(loRHE_type, lowpan_patterns_rh_type, "Unknown"));
+
+ switch (loRHE_class){
+ case (LOWPAN_PATTERN_6LORHE):/*Elective Routing Header*/
+ condition = 1 ;
+ if (loRHE_type >= 15) { /* BIER implementation */
+ proto_tree_add_uint (loRH_tree, hf_6lowpan_6lorhe_size, tvb, offset, 2, loRH_flags & LOWPAN_PATTERN_6LORHE_LENGTH);
+ proto_tree_add_uint (loRH_tree, hf_6lowpan_6lorhe_type, tvb, offset, 2, loRHE_type);
+ offset += 2 ;
+ if (loRHE_type == 15) {
+ for (int i=0; i<loRHE_unitnums; i++) {
+ proto_tree_add_item(loRH_tree, hf_6lowpan_6lorhe_bitmap, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ }
+ }
+ }
+ else if (loRHE_type == LOWPAN_IP_IN_IP_6LORH) {
+ memset(&ipv6.ip6h_src, 0, sizeof(ipv6.ip6h_src));
+ proto_tree_add_item(loRH_tree, hf_6lowpan_6lorhe_length, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(loRH_tree, hf_6lowpan_6lorhe_type, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(loRH_tree, hf_6lowpan_6lorhe_hoplimit, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
+
+ if (loRHE_length > 1) {
+ for (int i = 0; i < 16; ++i) {
+ ipv6.ip6h_src.bytes[i] = tvb_get_guint8(tvb, offset + 3 + i);
+ }
+ proto_tree_add_ipv6(loRH_tree, hf_6lowpan_6lorhc_address_src, tvb, offset + 3, 16,
+ &ipv6.ip6h_src);
+ }
+ offset += 2 + loRHE_length;
+ }
+ else {
+ condition -= 1;
+ }
+ break; /* case LOWPAN_PATTERN_6LORHE */
+
+ case (LOWPAN_PATTERN_6LORHC): /*Critical Routing Header*/
+ condition = 1 ;
+ if (loRHE_type == 5){
+ proto_tree_add_bitmask_list (loRH_tree, tvb, offset, 2, bits_RHC, ENC_NA);
+ proto_tree_add_item (loRH_tree, hf_6lowpan_6lorhe_type, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ switch (IK){
+ case BITS_IK_0:
+ proto_tree_add_item (loRH_tree, hf_6lowpan_rpl_instance, tvb, offset, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item (loRH_tree, hf_6lowpan_sender_rank2, tvb, offset+1, 2, ENC_BIG_ENDIAN);
+ offset += 3;
+ break;
+ case BITS_IK_1:
+ proto_tree_add_item (loRH_tree, hf_6lowpan_rpl_instance, tvb, offset, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item (loRH_tree, hf_6lowpan_sender_rank1, tvb, offset+1, 1, ENC_BIG_ENDIAN);
+ offset += 2;
+ break;
+ case BITS_IK_2:
+ rpl_instance = 0x00;
+ proto_tree_add_uint (loRH_tree, hf_6lowpan_rpl_instance, tvb, offset, 0, rpl_instance);
+ proto_tree_add_item (loRH_tree, hf_6lowpan_sender_rank2, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ break;
+ case BITS_IK_3:
+ rpl_instance = 0x00;
+ proto_tree_add_uint (loRH_tree, hf_6lowpan_rpl_instance, tvb, offset, 0, rpl_instance);
+ proto_tree_add_item (loRH_tree, hf_6lowpan_sender_rank1, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset +=1;
+ break;
+ }
+ }
+ else if (loRHE_type <= 4){
+ memset(&ipv6.ip6h_src, 0, sizeof(ipv6.ip6h_src));
+ proto_tree_add_uint (loRH_tree, hf_6lowpan_6lorhc_size, tvb, offset, 2, loRH_flags & LOWPAN_PATTERN_6LORHE_LENGTH);
+ proto_tree_add_uint (loRH_tree, hf_6lowpan_6lorhe_type, tvb, offset, 2, loRHE_type);
+ offset += 2 ;
+ switch (loRHE_type){
+ case IPV6_ADDR_COMPRESSED_1_BYTE: /* IPv6 address compressed to 1 byte */
+ for (int i=0; i<loRHE_unitnums; i++) {
+ for (int j = 0; j < 1; j++){
+ ipv6.ip6h_src.bytes[15-j] = tvb_get_guint8(tvb, offset);
+ }
+ proto_tree_add_ipv6(tree, hf_6lowpan_6lorhc_address_hop0, tvb, offset, 1, &ipv6.ip6h_src);
+ offset +=1;
+ }
+ break;
+
+ case IPV6_ADDR_COMPRESSED_2_BYTE: /* IPv6 address compressed to 2 bytes */
+ for (int i=0; i<loRHE_unitnums; i++) {
+ for (int j = 0; j < 2; ++j){
+ ipv6.ip6h_src.bytes[15-1+j] = tvb_get_guint8(tvb, offset);
+ offset +=1;
+ }
+ proto_tree_add_ipv6(tree, hf_6lowpan_6lorhc_address_hop1, tvb, offset - 2, 2, &ipv6.ip6h_src);
+ }
+ break;
+
+ case IPV6_ADDR_COMPRESSED_4_BYTE: /* IPv6 address compressed to 4 bytes */
+ for (int i=0; i<loRHE_unitnums; i++) {
+ for (int j = 0; j < 4; j++){
+ ipv6.ip6h_src.bytes[15-3+j] = tvb_get_guint8(tvb, offset);
+ offset +=1;
+ }
+ proto_tree_add_ipv6(tree, hf_6lowpan_6lorhc_address_hop2, tvb, offset - 4, 4, &ipv6.ip6h_src);
+ }
+ break;
+
+ case IPV6_ADDR_COMPRESSED_8_BYTE: /* IPv6 address compressed to 8 bytes */
+ for (int i=0; i<loRHE_unitnums; i++) {
+ for (int j = 0; j < 8; j++){
+ ipv6.ip6h_src.bytes[15-7+j] = tvb_get_guint8(tvb, offset);
+ offset +=1;
+ }
+ proto_tree_add_ipv6(tree, hf_6lowpan_6lorhc_address_hop3, tvb, offset - 8, 8, &ipv6.ip6h_src);
+ }
+ break;
+ case IPV6_ADDR_COMPRESSED_16_BYTE: /* IPv6 address compressed to 16 bytes */
+ for (int i=0; i<loRHE_unitnums; i++) {
+ for (int j = 0; j < 16; j++){
+ ipv6.ip6h_src.bytes[j] = tvb_get_guint8(tvb, offset);
+ offset +=1;
+ }
+ proto_tree_add_ipv6(tree, hf_6lowpan_6lorhc_address_hop4, tvb, offset - 16, 16, &ipv6.ip6h_src);
+ }
+ break; /**/
+ } /* switch loRHE_type */
+ } /* else if (loRHE_type <= 4) */
+ else {
+ condition -= 1;
+ }
+ break; /* case LOWPAN_PATTERN_6LORHC */
+
+ default:
+ condition -= 1 ;
+ break;
+ } /* switch loRHE_class */
+ loRH_flags = tvb_get_ntohs(tvb, offset);
+ loRHE_class = (loRH_flags & LOWPAN_PATTERN_6LORHE_CLASS) >> 13;
+
+ if ((loRHE_class) != LOWPAN_PATTERN_6LORHE){
+ if ((loRHE_class) != LOWPAN_PATTERN_6LORHC){
+ condition -= 1;
+ }
+ }
+ } /* while (condition > 0)*/
+ }
+ return tvb_new_subset_remaining(tvb, offset);
+} /* dissect_6lowpan_6loRH */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_ipv6
+ * DESCRIPTION
+ * Dissector routine for an uncompressed IPv6 header type.
+ *
+ * This is one of the final encapsulation types, and will
+ * returned an uncompressed IPv6 datagram (or fragment
+ * thereof).
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * offset ; offset to the start of the header.
+ * RETURNS
+ * tvbuff_t * ; The remaining payload to be parsed.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_ipv6(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
+{
+ /* Get and display the pattern. */
+ proto_tree_add_bits_item(tree, hf_6lowpan_pattern,
+ tvb, 0, LOWPAN_PATTERN_IPV6_BITS, ENC_BIG_ENDIAN);
+
+ /* Create a tvbuff subset for the ipv6 datagram. */
+ return tvb_new_subset_remaining(tvb, 1);
+} /* dissect_6lowpan_ipv6 */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_hc1
+ * DESCRIPTION
+ * Dissector routine for a 6LoWPAN HC1 header.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * dgram_size ; Datagram size (or <0 if not fragmented).
+ * siid ; Source Interface ID.
+ * diid ; Destination Interface ID.
+ * RETURNS
+ * tvbuff_t * ; The remaining payload to be parsed.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_hc1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint dgram_size, const guint8 *siid, const guint8 *diid)
+{
+ gint offset = 0;
+ gint bit_offset;
+ int i;
+ guint8 hc1_encoding;
+ guint8 hc_udp_encoding = 0;
+ guint8 next_header;
+ proto_tree * hc_tree;
+ proto_item * hc_item;
+ tvbuff_t * ipv6_tvb;
+ /* IPv6 header. */
+ guint8 ipv6_class;
+ guint32 ipv6_flow;
+ struct ws_ip6_hdr ipv6;
+ struct lowpan_nhdr *nhdr_list;
+ static int * const hc1_encodings[] = {
+ &hf_6lowpan_hc1_source_prefix,
+ &hf_6lowpan_hc1_source_ifc,
+ &hf_6lowpan_hc1_dest_prefix,
+ &hf_6lowpan_hc1_dest_ifc,
+ &hf_6lowpan_hc1_class,
+ &hf_6lowpan_hc1_next,
+ &hf_6lowpan_hc1_more,
+ NULL
+ };
+ static int * const hc2_encodings[] = {
+ &hf_6lowpan_hc2_udp_src,
+ &hf_6lowpan_hc2_udp_dst,
+ &hf_6lowpan_hc2_udp_len,
+ NULL
+ };
+
+ /*=====================================================
+ * Parse HC Encoding Flags
+ *=====================================================
+ */
+ /* Create a tree for the HC1 Header. */
+ hc_tree = proto_tree_add_subtree(tree, tvb, 0, 2, ett_6lowpan_hc1, &hc_item, "HC1 Encoding");
+
+ /* Get and display the pattern. */
+ proto_tree_add_bits_item(hc_tree, hf_6lowpan_pattern, tvb, 0, LOWPAN_PATTERN_HC1_BITS, ENC_BIG_ENDIAN);
+ offset += 1;
+
+ /* Get and display the HC1 encoding bits. */
+ hc1_encoding = tvb_get_guint8(tvb, offset);
+ next_header = ((hc1_encoding & LOWPAN_HC1_NEXT) >> 1);
+ proto_tree_add_bitmask(hc_tree, tvb, offset, hf_6lowpan_hc1_encoding,
+ ett_6lowpan_hc1_encoding, hc1_encodings, ENC_NA);
+ offset += 1;
+
+ /* Get and display the HC2 encoding bits, if present. */
+ if (hc1_encoding & LOWPAN_HC1_MORE) {
+ if (next_header == LOWPAN_HC1_NEXT_UDP) {
+ hc_udp_encoding = tvb_get_guint8(tvb, offset);
+ proto_tree_add_bitmask(tree, tvb, offset, hf_6lowpan_hc2_udp_encoding,
+ ett_6lowpan_hc2_udp, hc2_encodings, ENC_NA);
+ offset += 1;
+ }
+ else {
+ /* HC1 states there are more bits, but an illegal next header was defined. */
+ expert_add_info(pinfo, hc_item, &ei_6lowpan_hc1_more_bits);
+ return NULL;
+ }
+ }
+
+ /*=====================================================
+ * Parse Uncompressed IPv6 Header Fields
+ *=====================================================
+ */
+ /*
+ * And now all hell breaks loose. After the header encoding fields, we are
+ * left with an assortment of optional fields from the IPv6 header,
+ * depending on which fields are present or not, the headers may not be
+ * aligned to an octet boundary.
+ *
+ * From now on we have to parse the uncompressed fields relative to a bit
+ * offset.
+ */
+ bit_offset = offset << 3;
+
+ /* Parse hop limit */
+ ipv6.ip6h_hlim = tvb_get_bits8(tvb, bit_offset, LOWPAN_IPV6_HOP_LIMIT_BITS);
+ proto_tree_add_uint(tree, hf_6lowpan_hop_limit, tvb, bit_offset>>3,
+ BITS_TO_BYTE_LEN(bit_offset, LOWPAN_IPV6_HOP_LIMIT_BITS), ipv6.ip6h_hlim);
+ bit_offset += LOWPAN_IPV6_HOP_LIMIT_BITS;
+
+ /*=====================================================
+ * Parse/Decompress IPv6 Source Address
+ *=====================================================
+ */
+ offset = bit_offset;
+ if (!(hc1_encoding & LOWPAN_HC1_SOURCE_PREFIX)) {
+ for (i=0; i<8; i++, bit_offset += 8) {
+ ipv6.ip6h_src.bytes[i] = tvb_get_bits8(tvb, bit_offset, 8);
+ }
+ }
+ else {
+ memcpy(ipv6.ip6h_src.bytes, lowpan_llprefix, sizeof(lowpan_llprefix));
+ }
+ if (!(hc1_encoding & LOWPAN_HC1_SOURCE_IFC)) {
+ for (i=8; i<16; i++, bit_offset += 8) {
+ ipv6.ip6h_src.bytes[i] = tvb_get_bits8(tvb, bit_offset, 8);
+ }
+ }
+ else {
+ memcpy(&ipv6.ip6h_src.bytes[sizeof(ipv6.ip6h_src) - LOWPAN_IFC_ID_LEN], siid, LOWPAN_IFC_ID_LEN);
+ }
+ /* Display the source address. */
+ proto_tree_add_ipv6(tree, hf_6lowpan_source, tvb, offset>>3,
+ BITS_TO_BYTE_LEN(offset, (bit_offset-offset)), &ipv6.ip6h_src);
+
+ /*
+ * Do not set the address columns until after defragmentation, since we have
+ * to do decompression before reassembly, and changing the address will cause
+ * wireshark to think that the middle fragments came from another device.
+ */
+
+ /*=====================================================
+ * Parse/Decompress IPv6 Destination Address
+ *=====================================================
+ */
+ offset = bit_offset;
+ if (!(hc1_encoding & LOWPAN_HC1_DEST_PREFIX)) {
+ for (i=0; i<8; i++, bit_offset += 8) {
+ ipv6.ip6h_dst.bytes[i] = tvb_get_bits8(tvb, bit_offset, 8);
+ }
+ }
+ else {
+ memcpy(ipv6.ip6h_dst.bytes, lowpan_llprefix, sizeof(lowpan_llprefix));
+ }
+ if (!(hc1_encoding & LOWPAN_HC1_DEST_IFC)) {
+ for (i=8; i<16; i++, bit_offset += 8) {
+ ipv6.ip6h_dst.bytes[i] = tvb_get_bits8(tvb, bit_offset, 8);
+ }
+ }
+ else {
+ memcpy(&ipv6.ip6h_dst.bytes[sizeof(ipv6.ip6h_dst) - LOWPAN_IFC_ID_LEN], diid, LOWPAN_IFC_ID_LEN);
+ }
+ /* Display the destination address. */
+ proto_tree_add_ipv6(tree, hf_6lowpan_dest, tvb, offset>>3,
+ BITS_TO_BYTE_LEN(offset, (bit_offset-offset)), &ipv6.ip6h_dst);
+
+ /*
+ * Do not set the address columns until after defragmentation, since we have
+ * to do decompression before reassembly, and changing the address will cause
+ * wireshark to think that the middle fragments came from another device.
+ */
+
+ /* Parse the traffic class and flow label. */
+ ipv6_class = 0;
+ ipv6_flow = 0;
+ if (!(hc1_encoding & LOWPAN_HC1_TRAFFIC_CLASS)) {
+ /* Parse the traffic class. */
+ ipv6_class = tvb_get_bits8(tvb, bit_offset, LOWPAN_IPV6_TRAFFIC_CLASS_BITS);
+ proto_tree_add_uint(tree, hf_6lowpan_traffic_class, tvb, bit_offset>>3,
+ BITS_TO_BYTE_LEN(bit_offset, LOWPAN_IPV6_TRAFFIC_CLASS_BITS), ipv6_class);
+ bit_offset += LOWPAN_IPV6_TRAFFIC_CLASS_BITS;
+
+ /* Parse the flow label. */
+ ipv6_flow = tvb_get_bits32(tvb, bit_offset, LOWPAN_IPV6_FLOW_LABEL_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_uint(tree, hf_6lowpan_flow_label, tvb, bit_offset>>3,
+ BITS_TO_BYTE_LEN(bit_offset, LOWPAN_IPV6_FLOW_LABEL_BITS), ipv6_flow);
+ bit_offset += LOWPAN_IPV6_FLOW_LABEL_BITS;
+ }
+
+ /* Rebuild the IPv6 flow label, traffic class and version fields. */
+ ipv6.ip6h_vc_flow = ipv6_flow;
+ ipv6.ip6h_vc_flow |= ((guint32)ipv6_class << LOWPAN_IPV6_FLOW_LABEL_BITS);
+ ipv6.ip6h_vc_flow |= ((guint32)0x6 << (LOWPAN_IPV6_TRAFFIC_CLASS_BITS + LOWPAN_IPV6_FLOW_LABEL_BITS));
+ ipv6.ip6h_vc_flow = g_ntohl(ipv6.ip6h_vc_flow);
+
+ /* Parse the IPv6 next header field. */
+ if (next_header == LOWPAN_HC1_NEXT_UDP) {
+ ipv6.ip6h_nxt = IP_PROTO_UDP;
+ }
+ else if (next_header == LOWPAN_HC1_NEXT_ICMP) {
+ ipv6.ip6h_nxt = IP_PROTO_ICMPV6;
+ }
+ else if (next_header == LOWPAN_HC1_NEXT_TCP) {
+ ipv6.ip6h_nxt = IP_PROTO_TCP;
+ }
+ else {
+ /* Parse the next header field. */
+ ipv6.ip6h_nxt = tvb_get_bits8(tvb, bit_offset, LOWPAN_IPV6_NEXT_HEADER_BITS);
+ proto_tree_add_uint_format_value(tree, hf_6lowpan_next_header, tvb, bit_offset>>3,
+ BITS_TO_BYTE_LEN(bit_offset, LOWPAN_IPV6_NEXT_HEADER_BITS), ipv6.ip6h_nxt,
+ "%s (0x%02x)", ipprotostr(ipv6.ip6h_nxt), ipv6.ip6h_nxt);
+ bit_offset += LOWPAN_IPV6_NEXT_HEADER_BITS;
+ }
+
+ /*=====================================================
+ * Parse and Reconstruct the UDP Header
+ *=====================================================
+ */
+ if ((hc1_encoding & LOWPAN_HC1_MORE) && (next_header == LOWPAN_HC1_NEXT_UDP)) {
+ struct udp_hdr udp;
+ gint length;
+
+ /* Parse the source port. */
+ offset = bit_offset;
+ if (hc_udp_encoding & LOWPAN_HC2_UDP_SRCPORT) {
+ udp.src_port = tvb_get_bits8(tvb, bit_offset, LOWPAN_UDP_PORT_COMPRESSED_BITS) + LOWPAN_PORT_12BIT_OFFSET;
+ bit_offset += LOWPAN_UDP_PORT_COMPRESSED_BITS;
+ }
+ else {
+ udp.src_port = tvb_get_bits16(tvb, bit_offset, LOWPAN_UDP_PORT_BITS, ENC_BIG_ENDIAN);
+ bit_offset += LOWPAN_UDP_PORT_BITS;
+ }
+ proto_tree_add_uint(tree, hf_6lowpan_udp_src, tvb, offset>>3,
+ BITS_TO_BYTE_LEN(offset, (bit_offset-offset)), udp.src_port);
+ udp.src_port = g_ntohs(udp.src_port);
+
+ /* Parse the destination port. */
+ offset = bit_offset;
+ if (hc_udp_encoding & LOWPAN_HC2_UDP_DSTPORT) {
+ udp.dst_port = tvb_get_bits8(tvb, bit_offset, LOWPAN_UDP_PORT_COMPRESSED_BITS) + LOWPAN_PORT_12BIT_OFFSET;
+ bit_offset += LOWPAN_UDP_PORT_COMPRESSED_BITS;
+ }
+ else {
+ udp.dst_port = tvb_get_bits16(tvb, bit_offset, LOWPAN_UDP_PORT_BITS, ENC_BIG_ENDIAN);
+ bit_offset += LOWPAN_UDP_PORT_BITS;
+ }
+ proto_tree_add_uint(tree, hf_6lowpan_udp_dst, tvb, offset>>3,
+ BITS_TO_BYTE_LEN(offset, (bit_offset-offset)), udp.dst_port);
+ udp.dst_port = g_ntohs(udp.dst_port);
+
+ /* Parse the length, if present. */
+ if (!(hc_udp_encoding & LOWPAN_HC2_UDP_LENGTH)) {
+ udp.length = tvb_get_bits16(tvb, bit_offset, LOWPAN_UDP_LENGTH_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_uint(tree, hf_6lowpan_udp_len, tvb, bit_offset>>3,
+ BITS_TO_BYTE_LEN(bit_offset, LOWPAN_UDP_LENGTH_BITS), udp.length);
+
+ bit_offset += LOWPAN_UDP_LENGTH_BITS;
+ }
+ /* Compute the length from the fragmentation headers. */
+ else if (dgram_size >= 0) {
+ if (dgram_size < IPv6_HDR_SIZE) {
+ /* Datagram size is too small */
+ return NULL;
+ }
+ udp.length = dgram_size - IPv6_HDR_SIZE;
+ }
+ /* Compute the length from the tvbuff size. */
+ else {
+ udp.length = tvb_reported_length(tvb);
+ udp.length -= BITS_TO_BYTE_LEN(0, bit_offset + LOWPAN_UDP_CHECKSUM_BITS);
+ udp.length += (int)sizeof(struct udp_hdr);
+ }
+ udp.length = g_ntohs(udp.length);
+
+ /* Parse the checksum. */
+ udp.checksum = tvb_get_bits16(tvb, bit_offset, LOWPAN_UDP_CHECKSUM_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_uint(tree, hf_6lowpan_udp_checksum, tvb, bit_offset>>3,
+ BITS_TO_BYTE_LEN(bit_offset, LOWPAN_UDP_CHECKSUM_BITS), udp.checksum);
+ bit_offset += LOWPAN_UDP_CHECKSUM_BITS;
+ udp.checksum = g_ntohs(udp.checksum);
+
+ /* Construct the next header for the UDP datagram. */
+ offset = BITS_TO_BYTE_LEN(0, bit_offset);
+ length = tvb_captured_length_remaining(tvb, offset);
+ nhdr_list = (struct lowpan_nhdr *)wmem_alloc(pinfo->pool, sizeof(struct lowpan_nhdr) + sizeof(struct udp_hdr) + length);
+ nhdr_list->next = NULL;
+ nhdr_list->proto = IP_PROTO_UDP;
+ nhdr_list->length = length + (int)sizeof(struct udp_hdr);
+ nhdr_list->reported = g_ntohs(udp.length);
+
+ /* Copy the UDP header into the buffer. */
+ memcpy(LOWPAN_NHDR_DATA(nhdr_list), &udp, sizeof(struct udp_hdr));
+ tvb_memcpy(tvb, LOWPAN_NHDR_DATA(nhdr_list) + sizeof(struct udp_hdr), offset, length);
+ }
+ /*=====================================================
+ * Reconstruct the IPv6 Packet
+ *=====================================================
+ */
+ else {
+ gint length;
+ offset = BITS_TO_BYTE_LEN(0, bit_offset);
+ length = tvb_captured_length_remaining(tvb, offset);
+ nhdr_list = (struct lowpan_nhdr *)wmem_alloc(pinfo->pool, sizeof(struct lowpan_nhdr) + length);
+ nhdr_list->next = NULL;
+ nhdr_list->proto = ipv6.ip6h_nxt;
+ nhdr_list->length = length;
+ if (dgram_size < 0) {
+ nhdr_list->reported = tvb_reported_length_remaining(tvb, offset);
+ }
+ else {
+ nhdr_list->reported = dgram_size - IPv6_HDR_SIZE;
+ }
+ tvb_memcpy(tvb, LOWPAN_NHDR_DATA(nhdr_list), offset, nhdr_list->length);
+ }
+
+ /* Link the reassembled tvbuff together. */
+ ipv6_tvb = lowpan_reassemble_ipv6(tvb, pinfo, &ipv6, nhdr_list);
+
+ /* Add a new data source for it. */
+ add_new_data_source(pinfo, ipv6_tvb, "Decompressed 6LoWPAN HC1");
+
+ return ipv6_tvb;
+} /* dissect_6lowpan_hc1 */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_iphc
+ * DESCRIPTION
+ * Dissector routine for a 6LoWPAN IPHC header.
+ *
+ * This header is still in the draft phase, but is expected
+ * to replace HC1.
+ *
+ * See draft-ietf-6lowpan-hc-15.txt
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * dgram_size ; Datagram size (or <0 if not fragmented).
+ * siid ; Source Interface ID.
+ * diid ; Destination Interface ID.
+ * RETURNS
+ * tvbuff_t * ; The remaining payload to be parsed or NULL on error.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_iphc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint dgram_size, const guint8 *siid, const guint8 *diid)
+{
+ ieee802154_hints_t *hints;
+ guint16 hint_panid;
+ gint offset = 0;
+ gint length = 0;
+ proto_tree * iphc_tree;
+ proto_item * ti_dam = NULL;
+ proto_item * ti;
+ /* IPHC header fields. */
+ guint16 iphc_flags;
+ guint8 iphc_traffic;
+ guint8 iphc_hop_limit;
+ guint8 iphc_src_mode;
+ guint8 iphc_dst_mode;
+ guint8 iphc_ctx = 0;
+ /* Contexts to use for address decompression. */
+ gint iphc_sci = LOWPAN_CONTEXT_DEFAULT;
+ gint iphc_dci = LOWPAN_CONTEXT_DEFAULT;
+ lowpan_context_data *sctx;
+ lowpan_context_data *dctx;
+ /* IPv6 header */
+ guint8 ipv6_dscp = 0;
+ guint8 ipv6_ecn = 0;
+ guint32 ipv6_flowlabel = 0;
+ struct ws_ip6_hdr ipv6;
+ tvbuff_t * ipv6_tvb;
+ /* Next header chain */
+ struct lowpan_nhdr *nhdr_list;
+
+ /* Lookup the IEEE 802.15.4 addressing hints. */
+ hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo,
+ proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN), 0);
+ hint_panid = (hints) ? (hints->src_pan) : (IEEE802154_BCAST_PAN);
+
+ /* Create a tree for the IPHC header. */
+ iphc_tree = proto_tree_add_subtree(tree, tvb, 0, 2, ett_6lowpan_iphc, NULL, "IPHC Header");
+
+ /* Display the pattern. */
+ proto_tree_add_bits_item(iphc_tree, hf_6lowpan_pattern, tvb, 0, LOWPAN_PATTERN_IPHC_BITS, ENC_BIG_ENDIAN);
+
+ /*=====================================================
+ * Parse IPHC Header flags.
+ *=====================================================
+ */
+ iphc_flags = tvb_get_ntohs(tvb, offset);
+ iphc_traffic = (iphc_flags & LOWPAN_IPHC_FLAG_FLOW) >> LOWPAN_IPHC_FLAG_OFFSET_FLOW;
+ iphc_hop_limit = (iphc_flags & LOWPAN_IPHC_FLAG_HLIM) >> LOWPAN_IPHC_FLAG_OFFSET_HLIM;
+ iphc_src_mode = (iphc_flags & LOWPAN_IPHC_FLAG_SRC_MODE) >> LOWPAN_IPHC_FLAG_OFFSET_SRC_MODE;
+ iphc_dst_mode = (iphc_flags & LOWPAN_IPHC_FLAG_DST_MODE) >> LOWPAN_IPHC_FLAG_OFFSET_DST_MODE;
+ if (tree) {
+ const value_string *am_vs;
+ proto_tree_add_uint (iphc_tree, hf_6lowpan_iphc_flag_tf, tvb, offset, 2, iphc_flags & LOWPAN_IPHC_FLAG_FLOW);
+ proto_tree_add_boolean (iphc_tree, hf_6lowpan_iphc_flag_nhdr, tvb, offset, 2, iphc_flags & LOWPAN_IPHC_FLAG_NHDR);
+ proto_tree_add_uint (iphc_tree, hf_6lowpan_iphc_flag_hlim, tvb, offset, 2, iphc_flags & LOWPAN_IPHC_FLAG_HLIM);
+ proto_tree_add_boolean (iphc_tree, hf_6lowpan_iphc_flag_cid, tvb, offset, 2, iphc_flags & LOWPAN_IPHC_FLAG_CONTEXT_ID);
+ proto_tree_add_boolean (iphc_tree, hf_6lowpan_iphc_flag_sac, tvb, offset, 2, iphc_flags & LOWPAN_IPHC_FLAG_SRC_COMP);
+ am_vs = iphc_flags & LOWPAN_IPHC_FLAG_SRC_COMP ? lowpan_iphc_saddr_stateful_modes : lowpan_iphc_addr_modes;
+ proto_tree_add_uint_format_value(iphc_tree, hf_6lowpan_iphc_flag_sam, tvb, offset, 2, iphc_flags & LOWPAN_IPHC_FLAG_SRC_MODE,
+ "%s (0x%04x)", val_to_str_const(iphc_src_mode, am_vs, "Reserved"), iphc_src_mode);
+ proto_tree_add_boolean (iphc_tree, hf_6lowpan_iphc_flag_mcast, tvb, offset, 2, iphc_flags & LOWPAN_IPHC_FLAG_MCAST_COMP);
+ proto_tree_add_boolean (iphc_tree, hf_6lowpan_iphc_flag_dac, tvb, offset, 2, iphc_flags & LOWPAN_IPHC_FLAG_DST_COMP);
+ /* Destination address mode changes meanings depending on multicast compression. */
+ if (iphc_flags & LOWPAN_IPHC_FLAG_MCAST_COMP) {
+ if (iphc_flags & LOWPAN_IPHC_FLAG_DST_COMP) {
+ am_vs = lowpan_iphc_mcast_stateful_modes;
+ } else {
+ am_vs = lowpan_iphc_mcast_modes;
+ }
+ } else {
+ if (iphc_flags & LOWPAN_IPHC_FLAG_DST_COMP) {
+ am_vs = lowpan_iphc_daddr_stateful_modes;
+ } else {
+ am_vs = lowpan_iphc_addr_modes;
+ }
+ }
+ ti_dam = proto_tree_add_uint_format_value(iphc_tree, hf_6lowpan_iphc_flag_dam, tvb, offset, 2,
+ iphc_flags & LOWPAN_IPHC_FLAG_DST_MODE, "%s (0x%04x)", val_to_str_const(iphc_dst_mode, am_vs, "Reserved"), iphc_dst_mode);
+ }
+ offset += 2;
+
+ /* Display the context identifier extension, if present. */
+ if (iphc_flags & LOWPAN_IPHC_FLAG_CONTEXT_ID) {
+ iphc_ctx = tvb_get_guint8(tvb, offset);
+ iphc_sci = (iphc_ctx & LOWPAN_IPHC_FLAG_SCI) >> LOWPAN_IPHC_FLAG_OFFSET_SCI;
+ iphc_dci = (iphc_ctx & LOWPAN_IPHC_FLAG_DCI) >> LOWPAN_IPHC_FLAG_OFFSET_DCI;
+ proto_tree_add_uint(iphc_tree, hf_6lowpan_iphc_sci, tvb, offset, 1, iphc_ctx & LOWPAN_IPHC_FLAG_SCI);
+ proto_tree_add_uint(iphc_tree, hf_6lowpan_iphc_dci, tvb, offset, 1, iphc_ctx & LOWPAN_IPHC_FLAG_DCI);
+ offset += 1;
+ }
+ /* Use link-local contexts if stateless. */
+ if (!(iphc_flags & LOWPAN_IPHC_FLAG_SRC_COMP)) {
+ iphc_sci = LOWPAN_CONTEXT_LINK_LOCAL;
+ }
+ if (!(iphc_flags & LOWPAN_IPHC_FLAG_DST_COMP)) {
+ iphc_dci = LOWPAN_CONTEXT_LINK_LOCAL;
+ }
+ /* Lookup the contexts. */
+ /*
+ * Don't display their origin until after we decompress the address in case
+ * the address modes indicate that we should use a different context.
+ */
+ sctx = lowpan_context_find(iphc_sci, hint_panid);
+ dctx = lowpan_context_find(iphc_dci, hint_panid);
+
+ /*=====================================================
+ * Parse Traffic Class and Flow Label
+ *=====================================================
+ */
+ offset <<= 3;
+ /* Parse the ECN field. */
+ if (iphc_traffic != LOWPAN_IPHC_FLOW_COMPRESSED) {
+ ipv6_ecn = tvb_get_bits8(tvb, offset, LOWPAN_IPHC_ECN_BITS);
+ proto_tree_add_bits_item(tree, hf_6lowpan_ecn, tvb, offset, LOWPAN_IPHC_ECN_BITS, ENC_BIG_ENDIAN);
+ offset += LOWPAN_IPHC_ECN_BITS;
+ }
+ /* Parse the DSCP field. */
+ if ((iphc_traffic == LOWPAN_IPHC_FLOW_CLASS_LABEL) || (iphc_traffic == LOWPAN_IPHC_FLOW_CLASS)) {
+ ipv6_dscp = tvb_get_bits8(tvb, offset, LOWPAN_IPHC_DSCP_BITS);
+ proto_tree_add_bits_item(tree, hf_6lowpan_dscp, tvb, offset, LOWPAN_IPHC_DSCP_BITS, LOWPAN_IPHC_DSCP_BITS);
+ offset += LOWPAN_IPHC_DSCP_BITS;
+ }
+ /* Add a generated entry to show the IPv6 traffic class byte. */
+ if (ipv6_dscp || ipv6_ecn) {
+ proto_item *tclass_item;
+ tclass_item = proto_tree_add_uint(tree, hf_6lowpan_traffic_class, tvb, 0, 0,
+ (ipv6_dscp << LOWPAN_IPHC_ECN_BITS) | ipv6_ecn);
+ proto_item_set_generated(tclass_item);
+ }
+
+ /* Parse the flow label. */
+ if ((iphc_traffic == LOWPAN_IPHC_FLOW_CLASS_LABEL) || (iphc_traffic == LOWPAN_IPHC_FLOW_ECN_LABEL)) {
+ /* Pad to 4-bits past the start of the byte. */
+ guint pad_bits = ((4 - offset) & 0x7);
+ if (pad_bits) {
+ proto_tree_add_bits_item(tree, hf_6lowpan_padding, tvb, offset, pad_bits, ENC_BIG_ENDIAN);
+ }
+ offset += pad_bits;
+ ipv6_flowlabel = tvb_get_bits32(tvb, offset, LOWPAN_IPHC_LABEL_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_bits_item(tree, hf_6lowpan_flow_label, tvb, offset, LOWPAN_IPHC_LABEL_BITS, ENC_BIG_ENDIAN);
+ offset += LOWPAN_IPHC_LABEL_BITS;
+ }
+
+ /* Rebuild the IPv6 flow label, traffic class and version fields. */
+ ipv6.ip6h_vc_flow = ipv6_flowlabel;
+ ipv6.ip6h_vc_flow |= ((guint32)ipv6_ecn << LOWPAN_IPV6_FLOW_LABEL_BITS);
+ ipv6.ip6h_vc_flow |= ((guint32)ipv6_dscp << (LOWPAN_IPHC_ECN_BITS + LOWPAN_IPV6_FLOW_LABEL_BITS));
+ ipv6.ip6h_vc_flow |= ((guint32)0x6 << (LOWPAN_IPV6_TRAFFIC_CLASS_BITS + LOWPAN_IPV6_FLOW_LABEL_BITS));
+ ipv6.ip6h_vc_flow = g_ntohl(ipv6.ip6h_vc_flow);
+
+ /* Convert back to byte offsets. */
+ offset >>= 3;
+
+ /*=====================================================
+ * Parse Next Header and Hop Limit
+ *=====================================================
+ */
+ /* Get the next header field, if present. */
+ if (!(iphc_flags & LOWPAN_IPHC_FLAG_NHDR)) {
+ ipv6.ip6h_nxt = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint_format_value(tree, hf_6lowpan_next_header, tvb, offset, 1, ipv6.ip6h_nxt,
+ "%s (0x%02x)", ipprotostr(ipv6.ip6h_nxt), ipv6.ip6h_nxt);
+ offset += 1;
+ }
+
+ /* Get the hop limit field, if present. */
+ if (iphc_hop_limit == LOWPAN_IPHC_HLIM_1) {
+ ipv6.ip6h_hlim = 1;
+ }
+ else if (iphc_hop_limit == LOWPAN_IPHC_HLIM_64) {
+ ipv6.ip6h_hlim = 64;
+ }
+ else if (iphc_hop_limit == LOWPAN_IPHC_HLIM_255) {
+ ipv6.ip6h_hlim = 255;
+ }
+ else {
+ ipv6.ip6h_hlim = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(tree, hf_6lowpan_hop_limit, tvb, offset, 1, ipv6.ip6h_hlim);
+ offset += 1;
+ }
+
+ /*=====================================================
+ * Parse and decompress the source address.
+ *=====================================================
+ */
+ length = 0;
+ memset(&ipv6.ip6h_src, 0, sizeof(ipv6.ip6h_src));
+ /* (SAC=1 && SAM=00) -> the unspecified address (::). */
+ if ((iphc_flags & LOWPAN_IPHC_FLAG_SRC_COMP) && (iphc_src_mode == LOWPAN_IPHC_ADDR_SRC_UNSPEC)) {
+ sctx = &lowpan_context_default;
+ }
+ /* The IID is derived from the encapsulating layer. */
+ else if (iphc_src_mode == LOWPAN_IPHC_ADDR_COMPRESSED) {
+ memcpy(&ipv6.ip6h_src.bytes[sizeof(ipv6.ip6h_src) - LOWPAN_IFC_ID_LEN], siid, LOWPAN_IFC_ID_LEN);
+ }
+ /* Full Address inline. */
+ else if (iphc_src_mode == LOWPAN_IPHC_ADDR_FULL_INLINE) {
+ if (!(iphc_flags & LOWPAN_IPHC_FLAG_SRC_COMP)) sctx = &lowpan_context_default;
+ length = (int)sizeof(ipv6.ip6h_src);
+ tvb_memcpy(tvb, &ipv6.ip6h_src, offset, length);
+ }
+ /* 64-bits inline. */
+ else if (iphc_src_mode == LOWPAN_IPHC_ADDR_64BIT_INLINE) {
+ length = 8;
+ tvb_memcpy(tvb, &ipv6.ip6h_src.bytes[sizeof(ipv6.ip6h_src) - length], offset, length);
+ }
+ /* 16-bits inline. */
+ else if (iphc_src_mode == LOWPAN_IPHC_ADDR_16BIT_INLINE) {
+ length = 2;
+ /* Format becomes ff:fe00:xxxx */
+ ipv6.ip6h_src.bytes[11] = 0xff;
+ ipv6.ip6h_src.bytes[12] = 0xfe;
+ tvb_memcpy(tvb, &ipv6.ip6h_src.bytes[sizeof(ipv6.ip6h_src) - length], offset, length);
+
+ }
+ /* Copy the context bits. */
+ lowpan_pfxcpy(&ipv6.ip6h_src, &sctx->prefix, sctx->plen);
+ /* Update the IID of the encapsulating layer. */
+ siid = &ipv6.ip6h_src.bytes[sizeof(ipv6.ip6h_src) - LOWPAN_IFC_ID_LEN];
+
+ /* Display the source IPv6 address. */
+ ti = proto_tree_add_ipv6(tree, hf_6lowpan_source, tvb, offset, length, &ipv6.ip6h_src);
+ if (length == 0) {
+ proto_item_set_generated(ti);
+ }
+ if (ipv6_summary_in_tree) {
+ address src_addr = ADDRESS_INIT(AT_IPv6, sizeof(ipv6.ip6h_src), &ipv6.ip6h_src);
+ proto_item_append_text(tree, ", Src: %s", address_with_resolution_to_str(pinfo->pool, &src_addr));
+ }
+
+ /* Add information about where the context came from. */
+ /* TODO: We should display the prefix length too. */
+ if (sctx->plen) {
+ ti = proto_tree_add_ipv6(iphc_tree, hf_6lowpan_iphc_sctx_prefix, tvb, 0, 0, &sctx->prefix);
+ proto_item_set_generated(ti);
+ if ( sctx->frame ) {
+ ti = proto_tree_add_uint(iphc_tree, hf_6lowpan_iphc_sctx_origin, tvb, 0, 0, sctx->frame);
+ proto_item_set_generated(ti);
+ }
+ }
+ offset += length;
+ /*
+ * Do not set the address columns until after defragmentation, since we have
+ * to do decompression before reassembly, and changing the address will cause
+ * wireshark to think that the middle fragments came from another device.
+ */
+
+ /*=====================================================
+ * Parse and decompress a multicast address.
+ *=====================================================
+ */
+ length = 0;
+ memset(&ipv6.ip6h_dst, 0, sizeof(ipv6.ip6h_dst));
+ /* Stateless multicast compression. */
+ if ((iphc_flags & LOWPAN_IPHC_FLAG_MCAST_COMP) && !(iphc_flags & LOWPAN_IPHC_FLAG_DST_COMP)) {
+ if (iphc_dst_mode == LOWPAN_IPHC_ADDR_FULL_INLINE) {
+ length = (int)sizeof(ipv6.ip6h_dst);
+ tvb_memcpy(tvb, &ipv6.ip6h_dst.bytes[sizeof(ipv6.ip6h_dst) - length], offset, length);
+ }
+ else if (iphc_dst_mode == LOWPAN_IPHC_MCAST_48BIT) {
+ ipv6.ip6h_dst.bytes[0] = 0xff;
+ ipv6.ip6h_dst.bytes[1] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[11] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[12] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[13] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[14] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[15] = tvb_get_guint8(tvb, offset + (length++));
+ }
+ else if (iphc_dst_mode == LOWPAN_IPHC_MCAST_32BIT) {
+ ipv6.ip6h_dst.bytes[0] = 0xff;
+ ipv6.ip6h_dst.bytes[1] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[13] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[14] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[15] = tvb_get_guint8(tvb, offset + (length++));
+ }
+ else if (iphc_dst_mode == LOWPAN_IPHC_MCAST_8BIT) {
+ ipv6.ip6h_dst.bytes[0] = 0xff;
+ ipv6.ip6h_dst.bytes[1] = 0x02;
+ ipv6.ip6h_dst.bytes[15] = tvb_get_guint8(tvb, offset + (length++));
+ }
+ else {
+ /* Illegal destination address compression mode. */
+ expert_add_info(pinfo, ti_dam, &ei_6lowpan_illegal_dest_addr_mode);
+ return NULL;
+ }
+ }
+ /* Stateful multicast compression. */
+ else if ((iphc_flags & LOWPAN_IPHC_FLAG_MCAST_COMP) && (iphc_flags & LOWPAN_IPHC_FLAG_DST_COMP)) {
+ if (iphc_dst_mode == LOWPAN_IPHC_MCAST_STATEFUL_48BIT) {
+ /* RFC 3306 unicast-prefix based multicast address of the form:
+ * ffXX:XXLL:PPPP:PPPP:PPPP:PPPP:XXXX:XXXX
+ * XX = inline byte.
+ * LL = prefix/context length (up to 64-bits).
+ * PP = prefix/context byte.
+ */
+ ipv6.ip6h_dst.bytes[0] = 0xff;
+ ipv6.ip6h_dst.bytes[1] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[2] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[3] = (dctx->plen > 64) ? (64) : (dctx->plen);
+ memcpy(&ipv6.ip6h_dst.bytes[4], &dctx->prefix, 8);
+ ipv6.ip6h_dst.bytes[12] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[13] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[14] = tvb_get_guint8(tvb, offset + (length++));
+ ipv6.ip6h_dst.bytes[15] = tvb_get_guint8(tvb, offset + (length++));
+ }
+ else {
+ /* Illegal destination address compression mode. */
+ expert_add_info(pinfo, ti_dam, &ei_6lowpan_illegal_dest_addr_mode);
+ return NULL;
+ }
+ }
+
+ /*=====================================================
+ * Parse and decompress a unicast destination address.
+ *=====================================================
+ */
+ else {
+ /* (DAC=1 && DAM=00) -> reserved value. */
+ if ((iphc_flags & LOWPAN_IPHC_FLAG_DST_COMP) && (iphc_dst_mode == LOWPAN_IPHC_ADDR_FULL_INLINE)) {
+ /* Illegal destination address compression mode. */
+ expert_add_info(pinfo, ti_dam, &ei_6lowpan_illegal_dest_addr_mode);
+ return NULL;
+ }
+ /* The IID is derived from the link-layer source. */
+ else if (iphc_dst_mode == LOWPAN_IPHC_ADDR_COMPRESSED) {
+ memcpy(&ipv6.ip6h_dst.bytes[sizeof(ipv6.ip6h_dst) - LOWPAN_IFC_ID_LEN], diid, LOWPAN_IFC_ID_LEN);
+ }
+ /* Full Address inline. */
+ else if (iphc_dst_mode == LOWPAN_IPHC_ADDR_FULL_INLINE) {
+ dctx = &lowpan_context_default;
+ length = (int)sizeof(ipv6.ip6h_dst);
+ tvb_memcpy(tvb, &ipv6.ip6h_dst, offset, length);
+ }
+ /* 64-bits inline. */
+ else if (iphc_dst_mode == LOWPAN_IPHC_ADDR_64BIT_INLINE) {
+ length = 8;
+ tvb_memcpy(tvb, &ipv6.ip6h_dst.bytes[sizeof(ipv6.ip6h_dst) - length], offset, length);
+ }
+ /* 16-bits inline. */
+ else if (iphc_dst_mode == LOWPAN_IPHC_ADDR_16BIT_INLINE) {
+ length = 2;
+ /* Format becomes ff:fe00:xxxx */
+ ipv6.ip6h_dst.bytes[11] = 0xff;
+ ipv6.ip6h_dst.bytes[12] = 0xfe;
+ tvb_memcpy(tvb, &ipv6.ip6h_dst.bytes[sizeof(ipv6.ip6h_dst) - length], offset, length);
+ }
+ /* Copy the context bits. */
+ lowpan_pfxcpy(&ipv6.ip6h_dst, &dctx->prefix, dctx->plen);
+ /* Update the interface id of the encapsulating layer. */
+ diid = &ipv6.ip6h_dst.bytes[sizeof(ipv6.ip6h_dst) - LOWPAN_IFC_ID_LEN];
+ }
+
+ /* Display the destination IPv6 address. */
+ ti = proto_tree_add_ipv6(tree, hf_6lowpan_dest, tvb, offset, length, &ipv6.ip6h_dst);
+ if (length == 0) {
+ proto_item_set_generated(ti);
+ }
+ if (ipv6_summary_in_tree) {
+ address dst_addr = ADDRESS_INIT(AT_IPv6, sizeof(ipv6.ip6h_dst), &ipv6.ip6h_dst);
+ proto_item_append_text(tree, ", Dest: %s", address_with_resolution_to_str(pinfo->pool, &dst_addr));
+ }
+
+ /* Add information about where the context came from. */
+ /* TODO: We should display the prefix length too. */
+ if (dctx->plen) {
+ ti = proto_tree_add_ipv6(iphc_tree, hf_6lowpan_iphc_dctx_prefix, tvb, 0, 0, &dctx->prefix);
+ proto_item_set_generated(ti);
+ if ( dctx->frame ) {
+ ti = proto_tree_add_uint(iphc_tree, hf_6lowpan_iphc_dctx_origin, tvb, 0, 0, dctx->frame);
+ proto_item_set_generated(ti);
+ }
+ }
+ offset += length;
+ /*
+ * Do not set the address columns until after defragmentation, since we have
+ * to do decompression before reassembly, and changing the address will cause
+ * wireshark to think that the middle fragments came from another device.
+ */
+
+ /*=====================================================
+ * Decompress extension headers.
+ *=====================================================
+ */
+ /* Parse the list of extension headers. */
+ if (iphc_flags & LOWPAN_IPHC_FLAG_NHDR) {
+ /* Parse the next header protocol identifier. */
+ ipv6.ip6h_nxt = lowpan_parse_nhc_proto(tvb, offset);
+
+ /* Parse the 6LoWPAN NHC fields. */
+ nhdr_list = dissect_6lowpan_iphc_nhc(tvb, pinfo, tree, offset, dgram_size - IPv6_HDR_SIZE, siid, diid);
+ }
+ /* Create an extension header for the remaining payload. */
+ else {
+ length = tvb_captured_length_remaining(tvb, offset);
+ nhdr_list = (struct lowpan_nhdr *)wmem_alloc(pinfo->pool, sizeof(struct lowpan_nhdr) + length);
+ nhdr_list->next = NULL;
+ nhdr_list->proto = ipv6.ip6h_nxt;
+ nhdr_list->length = length;
+ if (dgram_size < 0) {
+ nhdr_list->reported = tvb_reported_length_remaining(tvb, offset);
+ }
+ else {
+ nhdr_list->reported = dgram_size - IPv6_HDR_SIZE;
+ }
+ tvb_memcpy(tvb, LOWPAN_NHDR_DATA(nhdr_list), offset, nhdr_list->length);
+ }
+
+ /*=====================================================
+ * Rebuild the IPv6 packet.
+ *=====================================================
+ */
+ /* Reassemble the IPv6 packet. */
+ ipv6_tvb = lowpan_reassemble_ipv6(tvb, pinfo, &ipv6, nhdr_list);
+
+ /* Add a new data source for it. */
+ add_new_data_source(pinfo, ipv6_tvb, "Decompressed 6LoWPAN IPHC");
+
+ return ipv6_tvb;
+} /* dissect_6lowpan_iphc */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_iphc_nhc
+ * DESCRIPTION
+ * Dissector routine for a 6LoWPAN IPHC next header structure(s).
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * offset ; packet buffer offset.
+ * dgram_size ; Remaining datagram size (or <0 if unknown).
+ * siid ; Source Interface ID.
+ * diid ; Destination Interface ID.
+ * RETURNS
+ * lowpan_nhdr * ; List of wmem_alloc'd next header structures.
+ *---------------------------------------------------------------
+ */
+static struct lowpan_nhdr *
+dissect_6lowpan_iphc_nhc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, gint dgram_size, const guint8 *siid, const guint8 *diid)
+{
+ gint length;
+ proto_item * ti = NULL;
+ proto_tree * nhc_tree = NULL;
+ struct lowpan_nhdr *nhdr;
+
+ /*=====================================================
+ * IP-in-IP Tunneling
+ *=====================================================
+ */
+ if (tvb_get_bits8(tvb, offset<<3, LOWPAN_NHC_PATTERN_EXT_IPV6_BITS) == LOWPAN_NHC_PATTERN_EXT_IPV6) {
+ guint8 ext_flags;
+ tvbuff_t *iphc_tvb;
+
+ /* Create a tree for the IPv6 extension header. */
+ nhc_tree = proto_tree_add_subtree(tree, tvb, offset, 2, ett_6lowpan_nhc_ext, &ti, "IPv6 extension header");
+ /* Display the IPv6 Extension Header NHC ID pattern. */
+ proto_tree_add_bits_item(nhc_tree, hf_6lowpan_nhc_pattern, tvb, offset<<3, LOWPAN_NHC_PATTERN_EXT_BITS, ENC_BIG_ENDIAN);
+
+ /* Get and display the extension header compression flags. */
+ ext_flags = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(nhc_tree, hf_6lowpan_nhc_ext_eid, tvb, offset, 1, ext_flags & LOWPAN_NHC_EXT_EID);
+ proto_tree_add_boolean(nhc_tree, hf_6lowpan_nhc_ext_nh, tvb, offset, 1, ext_flags & LOWPAN_NHC_EXT_NHDR);
+ if (ext_flags & LOWPAN_NHC_EXT_NHDR) {
+ /* TODO: Flag a warning, the NH bit MUST be 0 when EID==0x7 (IP-in-IP). */
+ }
+ offset += 1;
+
+ /* Decode the remainder of the packet using IPHC encoding. */
+ iphc_tvb = dissect_6lowpan_iphc(tvb_new_subset_remaining(tvb, offset), pinfo, tree, dgram_size, siid, diid);
+ if (!iphc_tvb) return NULL;
+
+ /* Create the next header structure for the tunneled IPv6 header. */
+ nhdr = (struct lowpan_nhdr *)wmem_alloc0(pinfo->pool, sizeof(struct lowpan_nhdr) + tvb_captured_length(iphc_tvb));
+ nhdr->next = NULL;
+ nhdr->proto = IP_PROTO_IPV6;
+ nhdr->length = tvb_captured_length(iphc_tvb);
+ nhdr->reported = tvb_reported_length(iphc_tvb);
+ tvb_memcpy(iphc_tvb, LOWPAN_NHDR_DATA(nhdr), 0, nhdr->length);
+ return nhdr;
+ }
+ /*=====================================================
+ * IPv6 Extension Header
+ *=====================================================
+ */
+ if (tvb_get_bits8(tvb, offset<<3, LOWPAN_NHC_PATTERN_EXT_BITS) == LOWPAN_NHC_PATTERN_EXT) {
+ struct ip6_ext ipv6_ext = {0, 0};
+ guint8 ext_flags;
+ guint8 ext_hlen;
+ guint8 ext_len;
+ guint8 ext_proto;
+ proto_item *ti_ext_len = NULL;
+
+ /* Parse the IPv6 extension header protocol. */
+ ext_proto = lowpan_parse_nhc_proto(tvb, offset);
+
+ /* Create a tree for the IPv6 extension header. */
+ nhc_tree = proto_tree_add_subtree(tree, tvb, offset, 2, ett_6lowpan_nhc_ext, NULL, "IPv6 extension header");
+ /* Display the IPv6 Extension Header NHC ID pattern. */
+ proto_tree_add_bits_item(nhc_tree, hf_6lowpan_nhc_pattern, tvb, offset<<3, LOWPAN_NHC_PATTERN_EXT_BITS, ENC_BIG_ENDIAN);
+
+ /* Get and display the extension header compression flags. */
+ ext_flags = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(nhc_tree, hf_6lowpan_nhc_ext_eid, tvb, offset, 1, ext_flags & LOWPAN_NHC_EXT_EID);
+ proto_tree_add_boolean(nhc_tree, hf_6lowpan_nhc_ext_nh, tvb, offset, 1, ext_flags & LOWPAN_NHC_EXT_NHDR);
+ offset += 1;
+
+ /* Get and display the next header field, if present. */
+ if (!(ext_flags & LOWPAN_NHC_EXT_NHDR)) {
+ ipv6_ext.ip6e_nxt = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint_format_value(nhc_tree, hf_6lowpan_nhc_ext_next, tvb, offset, 1, ipv6_ext.ip6e_nxt,
+ "%s (0x%02x)", ipprotostr(ipv6_ext.ip6e_nxt), ipv6_ext.ip6e_nxt);
+ proto_item_set_end(ti, tvb, offset+1);
+ offset += 1;
+ }
+
+ if (ext_proto == IP_PROTO_FRAGMENT) {
+ /* Fragment header has a reserved byte in place of the Length field. */
+ ext_hlen = 1;
+ length = (guint8)sizeof(struct ip6_frag);
+ ext_len = length - ext_hlen;
+
+ proto_tree_add_item(nhc_tree, hf_6lowpan_nhc_ext_reserved, tvb, offset, 1, ENC_NA);
+
+ } else {
+ /* Get and display the extension header length. */
+ ext_hlen = (guint8)sizeof(struct ip6_ext);
+ ext_len = tvb_get_guint8(tvb, offset);
+ ti_ext_len = proto_tree_add_uint(nhc_tree, hf_6lowpan_nhc_ext_length, tvb, offset, 1, ext_len);
+ offset += 1;
+
+ /* Compute the length of the extension header padded to an 8-byte alignment. */
+ length = ext_hlen + ext_len;
+ length = (length + 7) & ~0x7;
+ ipv6_ext.ip6e_len = length>>3; /* Convert to units of 8 bytes. */
+ ipv6_ext.ip6e_len -= 1; /* Don't include the first 8 bytes. */
+ }
+
+ /* Create the next header structure for the IPv6 extension header. */
+ nhdr = (struct lowpan_nhdr *)wmem_alloc0(pinfo->pool, sizeof(struct lowpan_nhdr) + length);
+ nhdr->next = NULL;
+ nhdr->proto = ext_proto;
+ nhdr->length = length;
+ nhdr->reported = length;
+
+ /* Add the IPv6 extension header to the buffer. */
+ if (ext_flags & LOWPAN_NHC_EXT_NHDR) {
+ ipv6_ext.ip6e_nxt = lowpan_parse_nhc_proto(tvb, offset+ext_len);
+ }
+ memcpy(LOWPAN_NHDR_DATA(nhdr), &ipv6_ext, ext_hlen);
+
+ /*
+ * If the extension header was truncated, display the remainder using
+ * the data dissector, and end NHC dissection here.
+ */
+ if (!tvb_bytes_exist(tvb, offset, ext_len)) {
+ /* Call the data dissector for the remainder. */
+ call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, nhc_tree);
+
+ /* Copy the remainder, and truncate the real buffer length. */
+ nhdr->length = tvb_captured_length_remaining(tvb, offset) + ext_hlen;
+ tvb_memcpy(tvb, LOWPAN_NHDR_DATA(nhdr) + ext_hlen, offset, tvb_captured_length_remaining(tvb, offset));
+
+ /* There is nothing more we can do. */
+ return nhdr;
+ }
+
+ if (ext_proto == IP_PROTO_FRAGMENT) {
+ /* Display the extension header using the data dissector. */
+ call_data_dissector(tvb_new_subset_length(tvb, offset+1, ext_len-1), pinfo, nhc_tree);
+ } else {
+ /* Display the extension header using the data dissector. */
+ call_data_dissector(tvb_new_subset_length(tvb, offset, ext_len), pinfo, nhc_tree);
+ }
+
+ /* Copy the extension header into the struct. */
+ tvb_memcpy(tvb, LOWPAN_NHDR_DATA(nhdr) + ext_hlen, offset, ext_len);
+ offset += ext_len;
+
+ /* Add padding option */
+ if (length > ext_hlen + ext_len) {
+ guint8 padding = length - (ext_hlen + ext_len);
+ guint8 *pad_ptr = LOWPAN_NHDR_DATA(nhdr) + ext_hlen + ext_len;
+ if (ext_proto != IP_PROTO_HOPOPTS && ext_proto != IP_PROTO_DSTOPTS) {
+ expert_add_info(pinfo, ti_ext_len, &ei_6lowpan_bad_ext_header_length);
+ }
+ if (padding == 1) {
+ pad_ptr[0] = IP6OPT_PAD1;
+ } else {
+ pad_ptr[0] = IP6OPT_PADN;
+ pad_ptr[1] = padding - 2;
+ /* No need to write pad data, as buffer is zero-initialised */
+ }
+ }
+
+ if (ext_flags & LOWPAN_NHC_EXT_NHDR) {
+ /*
+ * There are more LOWPAN_NHC structures to parse. Call ourself again
+ * recursively to parse them and build the linked list.
+ */
+ nhdr->next = dissect_6lowpan_iphc_nhc(tvb, pinfo, tree, offset, dgram_size - nhdr->reported, siid, diid);
+ }
+ else if (ipv6_ext.ip6e_nxt != IP_PROTO_NONE) {
+ /* Create another next header structure for the remaining payload. */
+ length = tvb_captured_length_remaining(tvb, offset);
+ nhdr->next = (struct lowpan_nhdr *)wmem_alloc(pinfo->pool, sizeof(struct lowpan_nhdr) + length);
+ nhdr->next->next = NULL;
+ nhdr->next->proto = ipv6_ext.ip6e_nxt;
+ nhdr->next->length = length;
+ if (dgram_size < 0) {
+ nhdr->next->reported = tvb_reported_length_remaining(tvb, offset);
+ }
+ else {
+ nhdr->next->reported = dgram_size - nhdr->reported;
+ }
+ tvb_memcpy(tvb, LOWPAN_NHDR_DATA(nhdr->next), offset, nhdr->next->length);
+ }
+
+ /* Done. */
+ return nhdr;
+ }
+ /*=====================================================
+ * UDP Header
+ *=====================================================
+ */
+ if (tvb_get_bits8(tvb, offset<<3, LOWPAN_NHC_PATTERN_UDP_BITS) == LOWPAN_NHC_PATTERN_UDP) {
+ struct udp_hdr udp;
+ gint src_bitlen;
+ gint dst_bitlen;
+ guint8 udp_flags;
+ guint16 udp_src_port, udp_dst_port;
+
+ /* Create a tree for the UDP header. */
+ nhc_tree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_6lowpan_nhc_udp, NULL, "UDP header compression");
+ /* Display the UDP NHC ID pattern. */
+ proto_tree_add_bits_item(nhc_tree, hf_6lowpan_nhc_pattern, tvb, offset<<3, LOWPAN_NHC_PATTERN_UDP_BITS, ENC_BIG_ENDIAN);
+
+ /* Get and display the UDP header compression options */
+ proto_tree_add_item(nhc_tree, hf_6lowpan_nhc_udp_checksum, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(nhc_tree, hf_6lowpan_nhc_udp_ports, tvb, offset, 1, ENC_NA);
+ udp_flags = tvb_get_guint8(tvb, offset);
+ offset += 1;
+
+ /* Get and display the ports. */
+ switch (udp_flags & LOWPAN_NHC_UDP_PORTS) {
+ case LOWPAN_NHC_UDP_PORT_INLINE:
+ udp_src_port = tvb_get_ntohs(tvb, offset);
+ udp_dst_port = tvb_get_ntohs(tvb, offset+2);
+ src_bitlen = 16;
+ dst_bitlen = 16;
+ break;
+
+ case LOWPAN_NHC_UDP_PORT_8BIT_DST:
+ udp_src_port = tvb_get_ntohs(tvb, offset);
+ udp_dst_port = LOWPAN_PORT_8BIT_OFFSET + tvb_get_guint8(tvb, offset + 2);
+ src_bitlen = 16;
+ dst_bitlen = 8;
+ break;
+
+ case LOWPAN_NHC_UDP_PORT_8BIT_SRC:
+ udp_src_port = LOWPAN_PORT_8BIT_OFFSET + tvb_get_guint8(tvb, offset);
+ udp_dst_port = tvb_get_ntohs(tvb, offset + 1);
+ src_bitlen = 8;
+ dst_bitlen = 16;
+ break;
+
+ case LOWPAN_NHC_UDP_PORT_12BIT:
+ udp_src_port = LOWPAN_PORT_12BIT_OFFSET + (tvb_get_guint8(tvb, offset) >> 4);
+ udp_dst_port = LOWPAN_PORT_12BIT_OFFSET + (tvb_get_guint8(tvb, offset) & 0x0f);
+ src_bitlen = 4;
+ dst_bitlen = 4;
+ break;
+
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ break;
+ } /* switch */
+
+ proto_tree_add_uint(tree, hf_6lowpan_udp_src, tvb, offset, BITS_TO_BYTE_LEN(offset<<3, src_bitlen), udp_src_port);
+ proto_tree_add_uint(tree, hf_6lowpan_udp_dst, tvb, offset+(src_bitlen>>3), BITS_TO_BYTE_LEN((offset<<3)+src_bitlen, dst_bitlen), udp_dst_port);
+ offset += ((src_bitlen + dst_bitlen)>>3);
+ udp.src_port = g_htons(udp_src_port);
+ udp.dst_port = g_htons(udp_dst_port);
+
+ /* Get and display the checksum. */
+ if (!(udp_flags & LOWPAN_NHC_UDP_CHECKSUM)) {
+ /* Parse the checksum. */
+ tvb_memcpy(tvb, &udp.checksum, offset, sizeof(udp.checksum));
+ proto_tree_add_checksum(tree, tvb, offset, hf_6lowpan_udp_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
+ offset += 2;
+ }
+ else {
+ /* Checksum must be != 0 or the UDP dissector will flag the packet with a PI_ERROR */
+ udp.checksum = 0xffff;
+ }
+
+ /* Compute the datagram length. */
+ if (dgram_size < 0) {
+ length = tvb_reported_length_remaining(tvb, offset);
+ udp.length = g_htons(length + (int)sizeof(struct udp_hdr));
+ }
+ else {
+ udp.length = g_htons(dgram_size);
+ }
+
+ /*
+ * Although rfc768 (udp) allows a packet to be sent with a checksum of
+ * 0 to mean that no checksum was computed, apparently IPv6 specifically
+ * disallows sending UDP datagrams without checksums. Likewise, 6LoWPAN
+ * requires that we recompute the checksum.
+ *
+ * If the datagram is incomplete, then leave the checksum at 0xffff.
+ */
+#if 0
+ /*
+ * This has been disabled, since we might only be dissecting a fragment
+ * of the packet, and thus we might not have the entire UDP payload at
+ * this time.
+ *
+ * If we want to display the checksums, they will have to be recomputed
+ * after packet reassembly. Lots of work for not much gain, since we can
+ * just set the UDP checksum to 0xffff (anything != 0) and Wireshark
+ * doesn't care.
+ */
+ if ((udp_flags & LOWPAN_NHC_UDP_CHECKSUM) && tvb_bytes_exist(tvb, offset, length)) {
+ vec_t cksum_vec[3];
+ struct {
+ ws_in6_addr src;
+ ws_in6_addr dst;
+ guint32 length;
+ guint8 zero[3];
+ guint8 proto;
+ } cksum_phdr;
+
+ /* Fill in the pseudo-header. */
+ memcpy(&cksum_phdr.src, pinfo->src.data, sizeof(ws_in6_addr));
+ memcpy(&cksum_phdr.dst, pinfo->dst.data, sizeof(ws_in6_addr));
+ cksum_phdr.length = g_htonl(length + (int)sizeof(struct udp_hdr));
+ memset(cksum_phdr.zero, 0, sizeof(cksum_phdr.zero));
+ cksum_phdr.proto = IP_PROTO_UDP;
+
+ /* Compute the checksum. */
+ SET_CKSUM_VEC_PTR(cksum_vec[0], (const guint8 *)&cksum_phdr, sizeof(cksum_phdr));
+ SET_CKSUM_VEC_PTR(cksum_vec[1], (const guint8 *)&udp, sizeof(struct udp_hdr));
+ SET_CKSUM_VEC_TVB(cksum_vec[2], tvb, offset, length);
+ udp.checksum = in_cksum(cksum_vec, 3);
+ if (udp.checksum == 0) udp.checksum = 0xffff;
+ }
+#endif
+
+ /* Create the next header structure for the UDP datagram. */
+ length = tvb_captured_length_remaining(tvb, offset);
+ nhdr = (struct lowpan_nhdr *)wmem_alloc(pinfo->pool, sizeof(struct lowpan_nhdr) + sizeof(struct udp_hdr) + length);
+ nhdr->next = NULL;
+ nhdr->proto = IP_PROTO_UDP;
+ nhdr->length = length + (int)sizeof(struct udp_hdr);
+ nhdr->reported = g_ntohs(udp.length);
+
+ /* Copy the UDP header and payload into the buffer. */
+ memcpy(LOWPAN_NHDR_DATA(nhdr), &udp, sizeof(struct udp_hdr));
+ tvb_memcpy(tvb, LOWPAN_NHDR_DATA(nhdr) + sizeof(struct udp_hdr), offset, tvb_captured_length_remaining(tvb, offset));
+ return nhdr;
+ }
+ /*=====================================================
+ * Unknown Next Header Type
+ *=====================================================
+ */
+ return NULL;
+} /* dissect_6lowpan_iphc_nhc */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_bc0
+ * DESCRIPTION
+ * Dissector routine for a 6LoWPAN broadcast header.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * RETURNS
+ * tvbuff_t * ; The remaining payload to be parsed.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_bc0(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
+{
+ guint8 seqnum;
+ proto_tree * bcast_tree;
+
+ /* Create a tree for the broadcast header. */
+ bcast_tree = proto_tree_add_subtree(tree, tvb, 0, 2, ett_6lowpan_bcast, NULL, "Broadcast Header");
+
+ /* Get and display the pattern. */
+ proto_tree_add_bits_item(bcast_tree, hf_6lowpan_pattern, tvb, 0, LOWPAN_PATTERN_BC0_BITS, ENC_BIG_ENDIAN);
+
+ /* Get and display the sequence number. */
+ seqnum = tvb_get_guint8(tvb, 1);
+ proto_tree_add_uint(bcast_tree, hf_6lowpan_bcast_seqnum, tvb, 1, 1, seqnum);
+
+ /* Return the remaining buffer. */
+ return tvb_new_subset_remaining(tvb, 2);
+} /* dissect_6lowpan_bc0 */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_mesh
+ * DESCRIPTION
+ * Dissector routine for a 6LoWPAN mesh header.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * offset ; offset to the start of the header.
+ * siid ; Source Interface ID.
+ * diid ; Destination Interface ID.
+ * RETURNS
+ * tvbuff_t * ; The remaining payload to be parsed.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_mesh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 *siid, guint8 *diid)
+{
+ gint offset = 0;
+ guint8 mesh_header;
+ proto_tree * mesh_tree;
+ proto_tree * flag_tree;
+ proto_item * ti;
+
+ ieee802154_hints_t *hints;
+
+ /* Create a tree for the mesh header. */
+ mesh_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_6lowpan_mesh, &ti, "Mesh Header");
+
+ /* Get and display the mesh flags. */
+ mesh_header = tvb_get_guint8(tvb, offset);
+
+ /* Create the mesh header subtree. */
+ flag_tree = proto_tree_add_subtree(mesh_tree, tvb, offset, 1, ett_6lowpan_mesh, NULL, "Flags");
+
+ /* Add the mesh header fields. */
+ proto_tree_add_bits_item(flag_tree, hf_6lowpan_pattern, tvb, offset * 8, LOWPAN_PATTERN_MESH_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_boolean(flag_tree, hf_6lowpan_mesh_v, tvb, offset, 1, mesh_header & LOWPAN_MESH_HEADER_V);
+ proto_tree_add_boolean(flag_tree, hf_6lowpan_mesh_f, tvb, offset, 1, mesh_header & LOWPAN_MESH_HEADER_F);
+ proto_tree_add_uint(flag_tree, hf_6lowpan_mesh_hops, tvb, offset, 1, mesh_header & LOWPAN_MESH_HEADER_HOPS);
+ offset += 1;
+
+ if ((mesh_header & LOWPAN_MESH_HEADER_HOPS) == LOWPAN_MESH_HEADER_HOPS) {
+ proto_tree_add_item(mesh_tree, hf_6lowpan_mesh_hops8, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ }
+
+ /* Get and display the originator address. */
+ if (!(mesh_header & LOWPAN_MESH_HEADER_V)) {
+ proto_tree_add_item(mesh_tree, hf_6lowpan_mesh_orig64,
+ tvb, offset, 8, ENC_BIG_ENDIAN);
+
+ set_address_tvb(&pinfo->src, AT_EUI64, 8, tvb, offset);
+ copy_address_shallow(&pinfo->net_src, &pinfo->src);
+
+ /* Update source IID */
+ tvb_memcpy(tvb, siid, offset, LOWPAN_IFC_ID_LEN);
+ /* RFC2464: Invert the U/L bit when using an EUI64 address. */
+ siid[0] ^= 0x02;
+ offset += 8;
+ }
+ else {
+ guint16 addr16 = tvb_get_ntohs(tvb, offset);
+ guint8 * ifcid;
+
+ proto_tree_add_uint(mesh_tree, hf_6lowpan_mesh_orig16, tvb, offset, 2, addr16);
+ ifcid = (guint8 *)wmem_alloc(pinfo->pool, 8);
+
+ /* Lookup the IEEE 802.15.4 addressing hints wanting RFC 2464 compatibility. */
+ hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo,
+ proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN), 0);
+
+ /* Convert the 16-bit short address to an IID using the PAN ID (RFC 4944) or not depending on the preference and the presence of hints from lower layers */
+ if (hints && rfc4944_short_address_format) {
+ lowpan_addr16_with_panid_to_ifcid(hints->src_pan, addr16, ifcid);
+ } else {
+ lowpan_addr16_to_ifcid(addr16, ifcid);
+ }
+
+ set_address(&pinfo->src, AT_EUI64, 8, ifcid);
+ copy_address_shallow(&pinfo->net_src, &pinfo->src);
+
+ /* Update source IID */
+ memcpy(siid, ifcid, LOWPAN_IFC_ID_LEN);
+ offset += 2;
+ }
+
+ /* Get and display the destination address. */
+ if (!(mesh_header & LOWPAN_MESH_HEADER_F)) {
+ proto_tree_add_item(mesh_tree, hf_6lowpan_mesh_dest64,
+ tvb, offset, 8, ENC_BIG_ENDIAN);
+
+ set_address_tvb(&pinfo->dst, AT_EUI64, 8, tvb, offset);
+ copy_address_shallow(&pinfo->net_dst, &pinfo->dst);
+
+ /* Update destination IID */
+ tvb_memcpy(tvb, diid, offset, LOWPAN_IFC_ID_LEN);
+ /* RFC2464: Invert the U/L bit when using an EUI64 address. */
+ diid[0] ^= 0x02;
+ offset += 8;
+ }
+ else {
+ guint16 addr16 = tvb_get_ntohs(tvb, offset);
+ guint8 * ifcid;
+
+ proto_tree_add_uint(mesh_tree, hf_6lowpan_mesh_dest16, tvb, offset, 2, addr16);
+
+ ifcid = (guint8 *)wmem_alloc(pinfo->pool, 8);
+
+ /* Lookup the IEEE 802.15.4 addressing hints wanting RFC 2464 compatibility. */
+ hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo,
+ proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN), 0);
+
+ /* Convert the 16-bit short address to an IID using the PAN ID (RFC 4944) or not depending on the preference and the presence of hints from lower layers */
+ if (hints && rfc4944_short_address_format) {
+ lowpan_addr16_with_panid_to_ifcid(hints->src_pan, addr16, ifcid);
+ } else {
+ lowpan_addr16_to_ifcid(addr16, ifcid);
+ }
+
+ set_address(&pinfo->dst, AT_EUI64, 8, ifcid);
+ copy_address_shallow(&pinfo->net_dst, &pinfo->dst);
+
+ /* Update destination IID */
+ memcpy(diid, ifcid, LOWPAN_IFC_ID_LEN);
+ offset += 2;
+ }
+
+ /* Adjust the mesh header length. */
+ proto_item_set_end(ti, tvb, offset);
+
+ /* Return the remaining buffer. */
+ return tvb_new_subset_remaining(tvb, offset);
+} /* dissect_6lowpan_mesh */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_frag_headers
+ * DESCRIPTION
+ * Dissector routine for headers in the first fragment.
+ * The first fragment can contain an uncompressed IPv6, HC1 or IPHC fragment.
+ * PARAMETERS
+ * tvb ; fragment buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * siid ; Source Interface ID.
+ * diid ; Destination Interface ID.
+ * RETURNS
+ * tvbuff_t * ; buffer containing the uncompressed IPv6 headers
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_frag_headers(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item *length_item, const guint8 *siid, const guint8 *diid)
+{
+ tvbuff_t *frag_tvb = NULL;
+
+ /* The first fragment can contain an uncompressed IPv6, HC1 or IPHC fragment. */
+ if (tvb_get_bits8(tvb, 0, LOWPAN_PATTERN_IPV6_BITS) == LOWPAN_PATTERN_IPV6) {
+ frag_tvb = dissect_6lowpan_ipv6(tvb, pinfo, tree);
+ }
+ else if (tvb_get_bits8(tvb, 0, LOWPAN_PATTERN_HC1_BITS) == LOWPAN_PATTERN_HC1) {
+ /* Check if the datagram size is sane. */
+ if (tvb_reported_length(tvb) < IPv6_HDR_SIZE) {
+ expert_add_info_format(pinfo, length_item, &ei_6lowpan_bad_ipv6_header_length,
+ "Length is less than IPv6 header length %u", IPv6_HDR_SIZE);
+ }
+ frag_tvb = dissect_6lowpan_hc1(tvb, pinfo, tree, tvb_reported_length(tvb), siid, diid);
+ }
+ else if (tvb_get_bits8(tvb, 0, LOWPAN_PATTERN_IPHC_BITS) == LOWPAN_PATTERN_IPHC) {
+ /* Check if the datagram size is sane. */
+ if (tvb_reported_length(tvb) < IPv6_HDR_SIZE) {
+ expert_add_info_format(pinfo, length_item, &ei_6lowpan_bad_ipv6_header_length,
+ "Length is less than IPv6 header length %u", IPv6_HDR_SIZE);
+ }
+ frag_tvb = dissect_6lowpan_iphc(tvb, pinfo, tree, tvb_reported_length(tvb), siid, diid);
+ }
+ /* Unknown 6LoWPAN dispatch type */
+ else {
+ dissect_6lowpan_unknown(tvb, pinfo, tree);
+ }
+ return frag_tvb;
+} /* dissect_6lowpan_frag_headers */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_rfrag
+ * DESCRIPTION
+ * Dissector routine for a 6LoWPAN Recoverable Fragment headers.
+ *
+ * If reassembly could be completed, this should return an
+ * uncompressed IPv6 packet. If reassembly had to be delayed
+ * for more packets, this will return NULL.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * siid ; Source Interface ID.
+ * diid ; Destination Interface ID.
+ * RETURNS
+ * tvbuff_t * ; reassembled IPv6 packet.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_rfrag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const guint8 *siid, const guint8 *diid)
+{
+ gint offset = 0;
+ guint32 frag_size;
+ guint32 dgram_tag;
+ proto_tree * frag_tree;
+ proto_item * ti;
+ proto_item * length_item;
+ /* Reassembly parameters. */
+ tvbuff_t * new_tvb;
+ tvbuff_t * frag_tvb;
+ fragment_head * frag_data;
+ gboolean save_fragmented;
+ guint16 sequence;
+ guint32 frag_offset;
+
+ /* Create a tree for the fragmentation header. */
+ frag_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_6lowpan_frag, &ti, "RFRAG Header");
+
+ /* Get and display the pattern and explicit congestion bit. */
+ proto_tree_add_bits_item(frag_tree, hf_6lowpan_pattern, tvb, offset * 8, LOWPAN_PATTERN_RFRAG_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_item(frag_tree, hf_6lowpan_rfrag_congestion, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+
+ /* Get and display the datagram tag. */
+ proto_tree_add_item_ret_uint(frag_tree, hf_6lowpan_rfrag_dgram_tag, tvb, offset, 1, ENC_BIG_ENDIAN, &dgram_tag);
+ offset += 1;
+
+ proto_tree_add_item(frag_tree, hf_6lowpan_rfrag_ack_requested, tvb, offset, 2, ENC_BIG_ENDIAN);
+ sequence = tvb_get_bits16(tvb, (offset * 8) + 1, LOWPAN_RFRAG_SEQUENCE_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_item(frag_tree, hf_6lowpan_rfrag_sequence, tvb, offset, 2, ENC_BIG_ENDIAN);
+
+ frag_size = tvb_get_bits16(tvb, (offset * 8) + 1 + LOWPAN_RFRAG_SEQUENCE_BITS, LOWPAN_RFRAG_FRAG_SZ_BITS, ENC_BIG_ENDIAN);
+ length_item = proto_tree_add_uint(frag_tree, hf_6lowpan_rfrag_size, tvb, offset * 8, 2, frag_size);
+ offset += 2;
+
+ if (sequence) {
+ proto_tree_add_item_ret_uint(frag_tree, hf_6lowpan_rfrag_offset, tvb, offset, 2, ENC_BIG_ENDIAN, &frag_offset);
+ }
+ else {
+ proto_tree_add_item_ret_uint(frag_tree, hf_6lowpan_rfrag_dgram_size, tvb, offset, 2, ENC_BIG_ENDIAN, &frag_offset);
+ }
+ offset += 2;
+
+ /* Adjust the fragmentation header length. */
+ proto_item_set_end(ti, tvb, offset);
+
+ frag_tvb = tvb_new_subset_length(tvb, offset, frag_size);
+ if (sequence == 0) {
+ dissect_6lowpan_frag_headers(frag_tvb, pinfo, tree, length_item, siid, diid);
+ }
+
+ /* Add this datagram to the fragment table. */
+ save_fragmented = pinfo->fragmented;
+ pinfo->fragmented = TRUE;
+ guint32 frag_id = lowpan_reassembly_id(pinfo, dgram_tag);
+ if (sequence == 0) {
+ frag_data = fragment_add_check(&lowpan_reassembly_table,
+ frag_tvb, 0, pinfo, frag_id, NULL,
+ 0, frag_size, TRUE);
+ fragment_set_tot_len(&lowpan_reassembly_table, pinfo, frag_id, NULL, frag_offset);
+ }
+ else {
+ guint32 dgram_size = fragment_get_tot_len(&lowpan_reassembly_table, pinfo, frag_id, NULL);
+ frag_data = fragment_add_check(&lowpan_reassembly_table,
+ frag_tvb, 0, pinfo, frag_id, NULL,
+ frag_offset, frag_size, (frag_offset+frag_size) < dgram_size);
+ }
+
+ /* Attempt reassembly. */
+ new_tvb = process_reassembled_data(frag_tvb, 0, pinfo,
+ "Reassembled 6LoWPAN", frag_data, &lowpan_frag_items,
+ NULL, tree);
+
+ pinfo->fragmented = save_fragmented;
+
+ if (new_tvb) {
+ /* Reassembly was successful; return the completed datagram. */
+ return new_tvb;
+ } else {
+ /* Reassembly was unsuccessful; show this fragment. This may
+ just mean that we don't yet have all the fragments, so
+ we should not just continue dissecting. */
+ call_data_dissector(frag_tvb, pinfo, proto_tree_get_root(tree));
+ return NULL;
+ }
+} /* dissect_6lowpan_rfrag */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_rfrag_ack
+ * DESCRIPTION
+ * Dissector routine for a 6LoWPAN ACK Dispatch type and header
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * RETURNS
+ * tvbuff_t * ; reassembled IPv6 packet.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_rfrag_ack(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ gint offset = 0;
+ proto_tree * frag_tree;
+ proto_item * ti;
+ (void)pinfo;
+
+ /* Create a tree for the fragmentation header. */
+ frag_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_6lowpan_frag, &ti, "RFRAG ACK Header");
+
+ /* Get and display the pattern and explicit congestion bit. */
+ proto_tree_add_bits_item(frag_tree, hf_6lowpan_pattern, tvb, offset * 8, LOWPAN_PATTERN_RFRAG_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_item(frag_tree, hf_6lowpan_rfrag_congestion, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+
+ /* Get and display the datagram tag. */
+ proto_tree_add_item(frag_tree, hf_6lowpan_rfrag_dgram_tag, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+
+ proto_tree_add_bits_item(frag_tree, hf_6lowpan_rfrag_ack_bitmap, tvb, offset * 8, 32, ENC_BIG_ENDIAN);
+ offset += 4;
+
+ /* TODO: Match ACK bits to original fragments? */
+
+ return tvb_new_subset_remaining(tvb, offset);
+} /* dissect_6lowpan_rfrag_ack */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_frag_first
+ * DESCRIPTION
+ * Dissector routine for a 6LoWPAN FRAG1 headers.
+ *
+ * If reassembly could be completed, this should return an
+ * uncompressed IPv6 packet. If reassembly had to be delayed
+ * for more packets, this will return NULL.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * siid ; Source Interface ID.
+ * diid ; Destination Interface ID.
+ * RETURNS
+ * tvbuff_t * ; reassembled IPv6 packet.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_frag_first(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const guint8 *siid, const guint8 *diid)
+{
+ gint offset = 0;
+ gint frag_size;
+ guint16 dgram_size;
+ guint16 dgram_tag;
+ proto_tree * frag_tree;
+ proto_item * ti;
+ proto_item * length_item;
+ /* Reassembly parameters. */
+ tvbuff_t * new_tvb;
+ tvbuff_t * frag_tvb;
+ fragment_head * frag_data;
+ gboolean save_fragmented;
+
+ /* Create a tree for the fragmentation header. */
+ frag_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_6lowpan_frag, &ti, "Fragmentation Header");
+
+ /* Get and display the pattern and datagram size. */
+ dgram_size = tvb_get_bits16(tvb, (offset * 8) + LOWPAN_PATTERN_FRAG_BITS, LOWPAN_FRAG_DGRAM_SIZE_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_bits_item(frag_tree, hf_6lowpan_pattern, tvb, offset * 8, LOWPAN_PATTERN_FRAG_BITS, ENC_BIG_ENDIAN);
+ length_item = proto_tree_add_uint(frag_tree, hf_6lowpan_frag_dgram_size, tvb, offset, 2, dgram_size);
+ offset += 2;
+
+ /* Get and display the datagram tag. */
+ dgram_tag = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_uint(frag_tree, hf_6lowpan_frag_dgram_tag, tvb, offset, 2, dgram_tag);
+ offset += 2;
+
+ /* Adjust the fragmentation header length. */
+ proto_item_set_end(ti, tvb, offset);
+
+
+ frag_tvb = tvb_new_subset_length(tvb, offset, dgram_size);
+ frag_tvb = dissect_6lowpan_frag_headers(frag_tvb, pinfo, tree, length_item, siid, diid);
+ /* Check call to dissect_6lowpan_xxx was successful */
+ if (frag_tvb == NULL) {
+ return NULL;
+ }
+
+ /* Add this datagram to the fragment table. */
+ frag_size = tvb_captured_length(frag_tvb);
+ tvb_set_reported_length(frag_tvb, frag_size);
+ save_fragmented = pinfo->fragmented;
+ pinfo->fragmented = TRUE;
+ guint32 frag_id = lowpan_reassembly_id(pinfo, dgram_tag);
+ frag_data = fragment_add_check(&lowpan_reassembly_table,
+ frag_tvb, 0, pinfo, frag_id, NULL,
+ 0, frag_size, (frag_size < dgram_size));
+
+ /* Attempt reassembly. */
+ new_tvb = process_reassembled_data(frag_tvb, 0, pinfo,
+ "Reassembled 6LoWPAN", frag_data, &lowpan_frag_items,
+ NULL, tree);
+
+ pinfo->fragmented = save_fragmented;
+
+ if (new_tvb) {
+ /* Reassembly was successful; return the completed datagram. */
+ return new_tvb;
+ } else {
+ /* Reassembly was unsuccessful; show this fragment. This may
+ just mean that we don't yet have all the fragments, so
+ we should not just continue dissecting. */
+ call_data_dissector(frag_tvb, pinfo, proto_tree_get_root(tree));
+ return NULL;
+ }
+} /* dissect_6lowpan_frag_first */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_frag_middle
+ * DESCRIPTION
+ * Dissector routine for a 6LoWPAN FRAGN headers.
+ *
+ * If reassembly could be completed, this should return an
+ * uncompressed IPv6 packet. If reassembly had to be delayed
+ * for more packets, this will return NULL.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * RETURNS
+ * tvbuff_t * ; reassembled IPv6 packet.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_6lowpan_frag_middle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ gint offset = 0;
+ gint frag_size;
+ guint16 dgram_size;
+ guint16 dgram_tag;
+ guint16 dgram_offset = 0;
+ proto_tree * frag_tree;
+ proto_item * ti;
+ /* Reassembly parameters. */
+ tvbuff_t * new_tvb;
+ fragment_head * frag_data;
+ gboolean save_fragmented;
+
+ /* Create a tree for the fragmentation header. */
+ frag_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_6lowpan_frag, &ti, "Fragmentation Header");
+
+ /* Get and display the pattern and datagram size. */
+ dgram_size = tvb_get_bits16(tvb, (offset * 8) + LOWPAN_PATTERN_FRAG_BITS, LOWPAN_FRAG_DGRAM_SIZE_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_bits_item(frag_tree, hf_6lowpan_pattern, tvb, offset * 8, LOWPAN_PATTERN_FRAG_BITS, ENC_BIG_ENDIAN);
+ proto_tree_add_uint(frag_tree, hf_6lowpan_frag_dgram_size, tvb, offset, 2, dgram_size);
+ offset += 2;
+
+ /* Get and display the datagram tag. */
+ dgram_tag = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_uint(frag_tree, hf_6lowpan_frag_dgram_tag, tvb, offset, 2, dgram_tag);
+ offset += 2;
+
+ /* Get and display the datagram offset. */
+ dgram_offset = tvb_get_guint8(tvb, offset) * 8;
+ proto_tree_add_uint(frag_tree, hf_6lowpan_frag_dgram_offset, tvb, offset, 1, dgram_offset);
+ offset += 1;
+
+ /* Adjust the fragmentation header length. */
+ frag_size = tvb_reported_length_remaining(tvb, offset);
+ proto_item_set_end(ti, tvb, offset);
+
+ /* Add this datagram to the fragment table. */
+ save_fragmented = pinfo->fragmented;
+ pinfo->fragmented = TRUE;
+ guint32 frag_id = lowpan_reassembly_id(pinfo, dgram_tag);
+ frag_data = fragment_add_check(&lowpan_reassembly_table,
+ tvb, offset, pinfo, frag_id, NULL,
+ dgram_offset, frag_size, ((dgram_offset + frag_size) < dgram_size));
+
+ /* Attempt reassembly. */
+ new_tvb = process_reassembled_data(tvb, offset, pinfo,
+ "Reassembled 6LoWPAN", frag_data, &lowpan_frag_items,
+ NULL, tree);
+
+ pinfo->fragmented = save_fragmented;
+
+ /* If reassembly was successful, then return the completed datagram. */
+ if (new_tvb) {
+ return new_tvb;
+ }
+ /* If reassembly failed, display the payload fragment using the data dissector. */
+ else {
+ new_tvb = tvb_new_subset_remaining(tvb, offset);
+ call_data_dissector(new_tvb, pinfo, proto_tree_get_root(tree));
+ return NULL;
+ }
+} /* dissect_6lowpan_frag_middle */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * dissect_6lowpan_unknown
+ * DESCRIPTION
+ * Dissector routine for 6LoWPAN packets after encountering
+ * an unknown header.
+ * PARAMETERS
+ * tvb ; packet buffer.
+ * pinfo ; packet info.
+ * tree ; 6LoWPAN display tree.
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+void
+dissect_6lowpan_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ tvbuff_t * data_tvb;
+
+ /* Get and display the pattern. */
+
+ /* Give a special case for NALP. */
+ if (tvb_get_bits8(tvb, 0, LOWPAN_PATTERN_IPHC_BITS) == LOWPAN_PATTERN_IPHC) {
+ proto_tree_add_bits_item(tree, hf_6lowpan_pattern, tvb, 0, LOWPAN_PATTERN_IPHC_BITS, ENC_BIG_ENDIAN);
+ }
+ else {
+ guint8 pattern = tvb_get_guint8(tvb, 0);
+ proto_tree_add_uint_bits_format_value(tree, hf_6lowpan_pattern, tvb, 0, 8, pattern, ENC_BIG_ENDIAN, "Unknown (0x%02x)", pattern);
+ }
+
+ /* Create a tvbuff subset for the remaining data. */
+ data_tvb = tvb_new_subset_remaining(tvb, 1);
+ call_data_dissector(data_tvb, pinfo, proto_tree_get_root(tree));
+} /* dissect_6lowpan_unknown */
+
+static void
+proto_shutdown_6lowpan(void)
+{
+ g_hash_table_destroy(lowpan_context_table);
+}
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * proto_register_6lowpan
+ * DESCRIPTION
+ * Protocol registration routine for 6LoWPAN. Called during
+ * Wireshark initialization.
+ * PARAMETERS
+ * none ;
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+void
+proto_register_6lowpan(void)
+{
+ static hf_register_info hf[] = {
+ /* Common 6LoWPAN fields. */
+ { &hf_6lowpan_pattern,
+ { "Pattern", "6lowpan.pattern",
+ FT_UINT8, BASE_HEX, VALS(lowpan_patterns), 0x0, NULL, HFILL }},
+ { &hf_6lowpan_nhc_pattern,
+ { "Pattern", "6lowpan.nhc.pattern",
+ FT_UINT8, BASE_HEX, VALS(lowpan_nhc_patterns), 0x0, NULL, HFILL }},
+ { &hf_6lowpan_padding,
+ { "Padding", "6lowpan.padding",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+
+ /* HC1 header fields. */
+ { &hf_6lowpan_hc1_encoding,
+ { "HC1 Encoding", "6lowpan.hc1.encoding",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_hc1_source_prefix,
+ { "Source prefix", "6lowpan.hc1.src_prefix",
+ FT_BOOLEAN, 8, TFS(&lowpan_compression), LOWPAN_HC1_SOURCE_PREFIX, NULL, HFILL }},
+ { &hf_6lowpan_hc1_source_ifc,
+ { "Source interface", "6lowpan.hc1.src_ifc",
+ FT_BOOLEAN, 8, TFS(&lowpan_compression), LOWPAN_HC1_SOURCE_IFC, NULL, HFILL }},
+ { &hf_6lowpan_hc1_dest_prefix,
+ { "Destination prefix", "6lowpan.hc1.dst_prefix",
+ FT_BOOLEAN, 8, TFS(&lowpan_compression), LOWPAN_HC1_DEST_PREFIX, NULL, HFILL }},
+ { &hf_6lowpan_hc1_dest_ifc,
+ { "Destination interface", "6lowpan.hc1.dst_ifc",
+ FT_BOOLEAN, 8, TFS(&lowpan_compression), LOWPAN_HC1_DEST_IFC, NULL, HFILL }},
+ { &hf_6lowpan_hc1_class,
+ { "Traffic class and flow label", "6lowpan.hc1.class",
+ FT_BOOLEAN, 8, TFS(&lowpan_compression), LOWPAN_HC1_TRAFFIC_CLASS, NULL, HFILL }},
+ { &hf_6lowpan_hc1_next,
+ { "Next header", "6lowpan.hc1.next",
+ FT_UINT8, BASE_HEX, VALS(lowpan_hc1_next), LOWPAN_HC1_NEXT, NULL, HFILL }},
+ { &hf_6lowpan_hc1_more,
+ { "More HC bits", "6lowpan.hc1.more",
+ FT_BOOLEAN, 8, NULL, LOWPAN_HC1_MORE, NULL, HFILL }},
+
+ /* HC_UDP header fields. */
+ { &hf_6lowpan_hc2_udp_encoding,
+ { "HC_UDP Encoding", "6lowpan.hc2.udp.encoding",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_hc2_udp_src,
+ { "Source port", "6lowpan.hc2.udp.src",
+ FT_BOOLEAN, 8, TFS(&lowpan_compression), LOWPAN_HC2_UDP_SRCPORT, NULL, HFILL }},
+ { &hf_6lowpan_hc2_udp_dst,
+ { "Destination port", "6lowpan.hc2.udp.dst",
+ FT_BOOLEAN, 8, TFS(&lowpan_compression), LOWPAN_HC2_UDP_DSTPORT, NULL, HFILL }},
+ { &hf_6lowpan_hc2_udp_len,
+ { "Length", "6lowpan.hc2.udp.length",
+ FT_BOOLEAN, 8, TFS(&lowpan_compression), LOWPAN_HC2_UDP_LENGTH, NULL, HFILL }},
+
+ /* IPHC header fields. */
+ { &hf_6lowpan_iphc_flag_tf,
+ { "Traffic class and flow label", "6lowpan.iphc.tf",
+ FT_UINT16, BASE_HEX, VALS(lowpan_iphc_traffic), LOWPAN_IPHC_FLAG_FLOW, "traffic class and flow control encoding", HFILL }},
+ { &hf_6lowpan_iphc_flag_nhdr,
+ { "Next header", "6lowpan.iphc.nh",
+ FT_BOOLEAN, 16, TFS(&lowpan_compression), LOWPAN_IPHC_FLAG_NHDR, NULL, HFILL }},
+ { &hf_6lowpan_iphc_flag_hlim,
+ { "Hop limit", "6lowpan.iphc.hlim",
+ FT_UINT16, BASE_HEX, VALS(lowpan_iphc_hop_limit), LOWPAN_IPHC_FLAG_HLIM, NULL, HFILL }},
+ { &hf_6lowpan_iphc_flag_cid,
+ { "Context identifier extension", "6lowpan.iphc.cid",
+ FT_BOOLEAN, 16, NULL, LOWPAN_IPHC_FLAG_CONTEXT_ID, NULL, HFILL }},
+ { &hf_6lowpan_iphc_flag_sac,
+ { "Source address compression", "6lowpan.iphc.sac",
+ FT_BOOLEAN, 16, TFS(&lowpan_iphc_addr_compression), LOWPAN_IPHC_FLAG_SRC_COMP, NULL, HFILL }},
+ { &hf_6lowpan_iphc_flag_sam,
+ { "Source address mode", "6lowpan.iphc.sam",
+ FT_UINT16, BASE_HEX, VALS(lowpan_iphc_addr_modes), LOWPAN_IPHC_FLAG_SRC_MODE, NULL, HFILL }},
+ { &hf_6lowpan_iphc_flag_mcast,
+ { "Multicast address compression", "6lowpan.iphc.m",
+ FT_BOOLEAN, 16, NULL, LOWPAN_IPHC_FLAG_MCAST_COMP, NULL, HFILL }},
+ { &hf_6lowpan_iphc_flag_dac,
+ { "Destination address compression","6lowpan.iphc.dac",
+ FT_BOOLEAN, 16, TFS(&lowpan_iphc_addr_compression), LOWPAN_IPHC_FLAG_DST_COMP, NULL, HFILL }},
+ { &hf_6lowpan_iphc_flag_dam,
+ { "Destination address mode", "6lowpan.iphc.dam",
+ FT_UINT16, BASE_HEX, VALS(lowpan_iphc_addr_modes), LOWPAN_IPHC_FLAG_DST_MODE, NULL, HFILL }},
+ { &hf_6lowpan_iphc_sci,
+ { "Source context identifier", "6lowpan.iphc.sci",
+ FT_UINT8, BASE_HEX, NULL, LOWPAN_IPHC_FLAG_SCI, NULL, HFILL }},
+ { &hf_6lowpan_iphc_dci,
+ { "Destination context identifier", "6lowpan.iphc.dci",
+ FT_UINT8, BASE_HEX, NULL, LOWPAN_IPHC_FLAG_DCI, NULL, HFILL }},
+
+ /* Context information fields. */
+ { &hf_6lowpan_iphc_sctx_prefix,
+ { "Source context", "6lowpan.iphc.sctx.prefix", FT_IPv6, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+ { &hf_6lowpan_iphc_sctx_origin,
+ { "Origin", "6lowpan.iphc.sctx.origin", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+ { &hf_6lowpan_iphc_dctx_prefix,
+ { "Destination context", "6lowpan.iphc.dctx.prefix", FT_IPv6, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+ { &hf_6lowpan_iphc_dctx_origin,
+ { "Origin", "6lowpan.iphc.dctx.origin", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
+ /* NHC IPv6 extension header fields. */
+ { &hf_6lowpan_nhc_ext_eid,
+ { "Header ID", "6lowpan.nhc.ext.eid",
+ FT_UINT8, BASE_HEX, VALS(lowpan_nhc_eid), LOWPAN_NHC_EXT_EID, NULL, HFILL }},
+ { &hf_6lowpan_nhc_ext_nh,
+ { "Next header", "6lowpan.nhc.ext.nh",
+ FT_BOOLEAN, 8, TFS(&lowpan_compression), LOWPAN_NHC_EXT_NHDR, NULL, HFILL }},
+ { &hf_6lowpan_nhc_ext_next,
+ { "Next header", "6lowpan.nhc.ext.next",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_nhc_ext_length,
+ { "Header length", "6lowpan.nhc.ext.length",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_nhc_ext_reserved,
+ { "Reserved octet", "6lowpan.nhc.ext.reserved",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+
+ /* NHC UDP header fields. */
+ { &hf_6lowpan_nhc_udp_checksum,
+ { "Checksum", "6lowpan.nhc.udp.checksum",
+ FT_BOOLEAN, 8, TFS(&lowpan_compression), LOWPAN_NHC_UDP_CHECKSUM, NULL, HFILL }},
+ { &hf_6lowpan_nhc_udp_ports,
+ { "Ports", "6lowpan.nhc.udp.ports",
+ FT_UINT8, BASE_DEC, VALS(lowpan_udp_ports), LOWPAN_NHC_UDP_PORTS, NULL, HFILL }},
+
+ /* Uncompressed IPv6 fields. */
+ { &hf_6lowpan_traffic_class,
+ { "Traffic class", "6lowpan.class",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_flow_label,
+ { "Flow label", "6lowpan.flow",
+ FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_ecn,
+ { "ECN", "6lowpan.ecn",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_dscp,
+ { "DSCP", "6lowpan.dscp",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_next_header,
+ { "Next header", "6lowpan.next",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_hop_limit,
+ { "Hop limit", "6lowpan.hops",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_source,
+ { "Source", "6lowpan.src",
+ FT_IPv6, BASE_NONE, NULL, 0x0, "Source IPv6 address", HFILL }},
+ { &hf_6lowpan_dest,
+ { "Destination", "6lowpan.dst",
+ FT_IPv6, BASE_NONE, NULL, 0x0, "Destination IPv6 address", HFILL }},
+
+ /* Uncompressed UDP fields. */
+ { &hf_6lowpan_udp_src,
+ { "Source port", "6lowpan.udp.src",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_udp_dst,
+ { "Destination port", "6lowpan.udp.dst",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_udp_len,
+ { "UDP length", "6lowpan.udp.length",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_udp_checksum,
+ { "UDP checksum", "6lowpan.udp.checksum",
+ FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+
+ /* Broadcast header fields. */
+ { &hf_6lowpan_bcast_seqnum,
+ { "Sequence number", "6lowpan.bcast.seqnum",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+
+ /* Mesh header fields. */
+ { &hf_6lowpan_mesh_v,
+ { "V", "6lowpan.mesh.v",
+ FT_BOOLEAN, 8, NULL, LOWPAN_MESH_HEADER_V, "short originator address present", HFILL }},
+ { &hf_6lowpan_mesh_f,
+ { "D", "6lowpan.mesh.f",
+ FT_BOOLEAN, 8, NULL, LOWPAN_MESH_HEADER_F, "short destination address present", HFILL }},
+ { &hf_6lowpan_mesh_hops,
+ { "Hops left", "6lowpan.mesh.hops",
+ FT_UINT8, BASE_DEC, NULL, LOWPAN_MESH_HEADER_HOPS, NULL, HFILL }},
+ { &hf_6lowpan_mesh_hops8,
+ { "Deep Hops left (Flags.Hops left == 15)", "6lowpan.mesh.hops8",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_mesh_orig16,
+ { "Originator", "6lowpan.mesh.orig16",
+ FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_mesh_orig64,
+ { "Originator", "6lowpan.mesh.orig64",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_mesh_dest16,
+ { "Destination", "6lowpan.mesh.dest16",
+ FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_mesh_dest64,
+ { "Destination", "6lowpan.mesh.dest64",
+ FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+
+ /* Fragmentation header fields. */
+ { &hf_6lowpan_frag_dgram_size,
+ { "Datagram size", "6lowpan.frag.size",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_frag_dgram_tag,
+ { "Datagram tag", "6lowpan.frag.tag",
+ FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_frag_dgram_offset,
+ { "Datagram offset", "6lowpan.frag.offset",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+
+ /* Recoverable Fragmentation header fields. */
+ { &hf_6lowpan_rfrag_congestion,
+ { "Congestion", "6lowpan.rfrag.congestion",
+ FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, NULL, HFILL }},
+ { &hf_6lowpan_rfrag_ack_requested,
+ { "Ack requested", "6lowpan.rfrag.ack_requested",
+ FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x8000, NULL, HFILL }},
+ { &hf_6lowpan_rfrag_dgram_tag,
+ { "Datagram tag", "6lowpan.rfrag.tag",
+ FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_rfrag_sequence,
+ { "Fragment sequence", "6lowpan.rfrag.sequence",
+ FT_UINT16, BASE_DEC, NULL, 0x7C00, NULL, HFILL }},
+ { &hf_6lowpan_rfrag_size,
+ { "Fragment size", "6lowpan.rfrag.size",
+ FT_UINT16, BASE_DEC, NULL, 0x03FF, NULL, HFILL }},
+ { &hf_6lowpan_rfrag_dgram_size,
+ { "Datagram size", "6lowpan.rfrag.datagram_size",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_rfrag_offset,
+ { "Fragment offset", "6lowpan.rfrag.offset",
+ FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_rfrag_ack_bitmap,
+ { "Fragment ACK bitmask", "6lowpan.rfrag.ack_bitmask",
+ FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+
+ /* Reassembly fields. */
+ { &hf_6lowpan_fragments,
+ { "Message fragments", "6lowpan.fragments",
+ FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }},
+ { &hf_6lowpan_fragment,
+ { "Message fragment", "6lowpan.fragment",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }},
+ { &hf_6lowpan_fragment_overlap,
+ { "Message fragment overlap", "6lowpan.fragment.overlap",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }},
+ { &hf_6lowpan_fragment_overlap_conflicts,
+ { "Message fragment overlapping with conflicting data", "6lowpan.fragment.overlap.conflicts",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }},
+ { &hf_6lowpan_fragment_multiple_tails,
+ { "Message has multiple tail fragments", "6lowpan.fragment.multiple_tails",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }},
+ { &hf_6lowpan_fragment_too_long_fragment,
+ { "Message fragment too long", "6lowpan.fragment.too_long_fragment",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }},
+ { &hf_6lowpan_fragment_error,
+ { "Message defragmentation error", "6lowpan.fragment.error",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }},
+ { &hf_6lowpan_fragment_count,
+ { "Message fragment count", "6lowpan.fragment.count",
+ FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }},
+ { &hf_6lowpan_reassembled_in,
+ { "Reassembled in", "6lowpan.reassembled.in",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }},
+ { &hf_6lowpan_reassembled_length,
+ { "Reassembled 6LoWPAN length", "6lowpan.reassembled.length",
+ FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }},
+
+ /* 6loRH fields */
+ { &hf_6lowpan_6lorhc_address_src,
+ { "Encapsulator Address", "6lowpan.src",
+ FT_IPv6, BASE_NONE, NULL, 0x0, "Source IPv6 address", HFILL }},
+ { &hf_6lowpan_6lorhc_address_hop0,
+ { "Source/15, Delta", "6lowpan.src",
+ FT_IPv6, BASE_NONE, NULL, 0x0, "Source IPv6 address", HFILL }},
+ { &hf_6lowpan_6lorhc_address_hop1,
+ { "Source/14, Delta", "6lowpan.src",
+ FT_IPv6, BASE_NONE, NULL, 0x0, "Source IPv6 address", HFILL }},
+ { &hf_6lowpan_6lorhc_address_hop2,
+ { "Source/12, Delta", "6lowpan.src",
+ FT_IPv6, BASE_NONE, NULL, 0x0, "Source IPv6 address", HFILL }},
+ { &hf_6lowpan_6lorhc_address_hop3,
+ { "Source/8, Delta", "6lowpan.src",
+ FT_IPv6, BASE_NONE, NULL, 0x0, "Source IPv6 address", HFILL }},
+ { &hf_6lowpan_6lorhc_address_hop4,
+ { "Source/0 Delta", "6lowpan.src",
+ FT_IPv6, BASE_NONE, NULL, 0x0, "Source IPv6 address", HFILL }},
+ { &hf_6lowpan_sender_rank1,
+ { "Sender Rank", "6lowpan.sender.rank",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_sender_rank2,
+ { "Sender Rank", "6lowpan.sender.rank",
+ FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_rpl_instance,
+ { "RPL Instance", "6lowpan.rpl.instance",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_5_bit_o,
+ { "Packet direction (bit O)", "6lowpan.6loRH.bitO",
+ FT_BOOLEAN, 16, TFS(&tfs_down_up), LOWPAN_5_RPI_BIT_O, NULL, HFILL }},
+ { &hf_6lowpan_5_bit_r,
+ { "Rank-Error (bit R)", "6lowpan.6loRH.bitR",
+ FT_BOOLEAN, 16, TFS(&tfs_yes_no), LOWPAN_5_RPI_BIT_R, NULL, HFILL }},
+ { &hf_6lowpan_5_bit_f,
+ { "Forwarding-Error (bit F)", "6lowpan.6loRH.bitF",
+ FT_BOOLEAN, 16, TFS(&tfs_yes_no), LOWPAN_5_RPI_BIT_F, NULL, HFILL }},
+ { &hf_6lowpan_5_bit_i,
+ { "RPL Instance (bit I)", "6lowpan.6loRH.bitI",
+ FT_BOOLEAN, 16, TFS(&bit_I_RPL), LOWPAN_5_RPI_BIT_I, NULL, HFILL }},
+ { &hf_6lowpan_5_bit_k,
+ { "Sender Rank Compression size (bit K)", "6lowpan.6loRH.bitK",
+ FT_BOOLEAN, 16, TFS(&bit_K_RPL), LOWPAN_5_RPI_BIT_K, NULL, HFILL }},
+ { &hf_6lowpan_6lorhe_hoplimit,
+ { "6loRH Hop Limit", "6lowpan.rhhop.limit",
+ FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_6lorhe_bitmap,
+ { "6loRH BIER Bitmap", "6lowpan.bitmap",
+ FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_6lowpan_6lorhe_type,
+ { "6loRH Type", "6lowpan.rhtype",
+ FT_UINT16, BASE_HEX, VALS(lowpan_patterns_rh_type), LOWPAN_PATTERN_6LORHE_TYPE, NULL, HFILL }},
+ { &hf_6lowpan_6lorhc_size,
+ { "6loRH Hop Number-1", "6lowpan.HopNuevo",
+ FT_UINT16, BASE_HEX, NULL, LOWPAN_PATTERN_6LORHE_LENGTH, NULL, HFILL }},
+ { &hf_6lowpan_6lorhe_size,
+ { "6loRH Bitmap Word Number-1", "6lowpan.WordNuevo",
+ FT_UINT16, BASE_HEX, NULL, LOWPAN_PATTERN_6LORHE_LENGTH, NULL, HFILL }},
+ { &hf_6lowpan_6lorhe_length,
+ { "6loRH Elective Length", "6lowpan.rhElength",
+ FT_UINT16, BASE_DEC, NULL, LOWPAN_PATTERN_6LORHE_LENGTH, NULL, HFILL }},
+ { &hf_6lowpan_routing_header,
+ { "Routing Header 6lo", "6lowpan.routingheader",
+ FT_UINT8, BASE_HEX, VALS(lowpan_patterns_rh), 0x0, NULL, HFILL }},
+ { &hf_6lowpan_pagenb,
+ { "Page Number", "6lowpan.pagenb",
+ FT_UINT16, 16, NULL, 0x0, NULL, HFILL }}
+ };
+
+ static gint *ett[] = {
+ &ett_6lowpan,
+ &ett_6lowpan_hc1,
+ &ett_6lowpan_hc1_encoding,
+ &ett_6lowpan_hc2_udp,
+ &ett_6lowpan_iphc,
+ &ett_lowpan_routing_header_dispatch,
+ &ett_6lowpan_nhc_ext,
+ &ett_6lowpan_nhc_udp,
+ &ett_6lowpan_bcast,
+ &ett_6lowpan_mesh,
+ &ett_6lowpan_mesh_flags,
+ &ett_6lowpan_frag,
+ /* Reassembly subtrees. */
+ &ett_6lowpan_fragment,
+ &ett_6lowpan_fragments
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_6lowpan_hc1_more_bits, { "6lowpan.hc1_more_bits", PI_MALFORMED, PI_ERROR, "HC1 more bits expected for illegal next header type.", EXPFILL }},
+ { &ei_6lowpan_illegal_dest_addr_mode, { "6lowpan.illegal_dest_addr_mode", PI_MALFORMED, PI_ERROR, "Illegal destination address mode", EXPFILL }},
+ { &ei_6lowpan_bad_ipv6_header_length, { "6lowpan.bad_ipv6_header_length", PI_MALFORMED, PI_ERROR, "Length is less than IPv6 header length", EXPFILL }},
+ { &ei_6lowpan_bad_ext_header_length, { "6lowpan.bad_ext_header_length", PI_MALFORMED, PI_ERROR, "Extension header not 8-octet aligned", EXPFILL }},
+ };
+
+ int i;
+ module_t *prefs_module;
+ expert_module_t* expert_6lowpan;
+
+ lowpan_context_table = g_hash_table_new_full(lowpan_context_hash, lowpan_context_equal, lowpan_context_free, lowpan_context_free);
+
+ proto_6lowpan = proto_register_protocol("IPv6 over Low power Wireless Personal Area Networks", "6LoWPAN", "6lowpan");
+ proto_register_field_array(proto_6lowpan, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_6lowpan = expert_register_protocol(proto_6lowpan);
+ expert_register_field_array(expert_6lowpan, ei, array_length(ei));
+
+ /* Register the dissector with wireshark. */
+ handle_6lowpan = register_dissector("6lowpan", dissect_6lowpan, proto_6lowpan);
+
+ /* Initialize the fragment reassembly table. */
+ reassembly_table_register(&lowpan_reassembly_table, &addresses_reassembly_table_functions);
+
+ /* Register the dissector init function */
+ register_init_routine(proto_init_6lowpan);
+ register_shutdown_routine(proto_shutdown_6lowpan);
+
+ /* Initialize the context preferences. */
+ memset((gchar*)lowpan_context_prefs, 0, sizeof(lowpan_context_prefs));
+
+ /* Register preferences. */
+ prefs_module = prefs_register_protocol(proto_6lowpan, prefs_6lowpan_apply);
+
+ prefs_register_bool_preference(prefs_module, "rfc4944_short_address_format",
+ "Derive IID according to RFC 4944",
+ "Derive IID from a short 16-bit address according to RFC 4944 (using the PAN ID).",
+ &rfc4944_short_address_format);
+ prefs_register_bool_preference(prefs_module, "iid_has_universal_local_bit",
+ "IID has Universal/Local bit",
+ "Linux kernels before version 4.12 does toggle the Universal/Local bit.",
+ &iid_has_universal_local_bit);
+ prefs_register_bool_preference(prefs_module, "summary_in_tree",
+ "Show IPv6 summary in protocol tree",
+ "Whether the IPv6 summary line should be shown in the protocol tree",
+ &ipv6_summary_in_tree);
+
+ for (i = 0; i < LOWPAN_CONTEXT_MAX; i++) {
+ char *pref_name, *pref_title;
+
+ /*
+ * Inspired by the IEEE 802.11 dissector - the preferences are expecting
+ * that each pref has a unique string passed in, and will crash if we
+ * try to reuse any for multiple preferences.
+ */
+ pref_name = wmem_strdup_printf(wmem_epan_scope(), "context%d", i);
+ pref_title = wmem_strdup_printf(wmem_epan_scope(), "Context %d", i);
+ prefs_register_string_preference(prefs_module, pref_name, pref_title,
+ "IPv6 prefix to use for stateful address decompression.",
+ &lowpan_context_prefs[i]);
+ }
+} /* proto_register_6lowpan */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * proto_init_6lowpan
+ * DESCRIPTION
+ * 6LoWPAN initialization function.
+ * PARAMETERS
+ * none ;
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+static void
+proto_init_6lowpan(void)
+{
+ /* Initialize the link-local context. */
+ lowpan_context_local.frame = 0;
+ lowpan_context_local.plen = LOWPAN_CONTEXT_LINK_LOCAL_BITS;
+ memcpy(&lowpan_context_local.prefix, lowpan_llprefix, sizeof(lowpan_llprefix));
+
+ /* Reload static contexts from our preferences. */
+ prefs_6lowpan_apply();
+} /* proto_init_6lowpan */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * prefs_6lowpan_apply
+ * DESCRIPTION
+ * Prefs "apply" callback. Parses the context table for
+ * IPv6 addresses/prefixes.
+ * PARAMETERS
+ * none ;
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+void
+prefs_6lowpan_apply(void)
+{
+ int i;
+ ws_in6_addr prefix;
+ gchar *prefix_str;
+ gchar *prefix_len_str;
+ guint32 prefix_len;
+ gchar prefix_buf[48]; /* max length of IPv6 str. plus a bit */
+
+ for (i = 0; i < LOWPAN_CONTEXT_MAX; i++) {
+ if (!lowpan_context_prefs[i]) continue;
+ (void) g_strlcpy(prefix_buf, lowpan_context_prefs[i], 48);
+ if ((prefix_str = strtok(prefix_buf, "/")) == NULL) continue;
+ if ((prefix_len_str = strtok(NULL, "/")) == NULL) continue;
+ if (sscanf(prefix_len_str, "%u", &prefix_len) != 1) continue;
+ if (!str_to_ip6(prefix_str, &prefix)) continue;
+ /* Set the prefix */
+ lowpan_context_insert(i, IEEE802154_BCAST_PAN, prefix_len, &prefix, 0);
+ } /* for */
+} /* prefs_6lowpan_apply */
+
+/*FUNCTION:------------------------------------------------------
+ * NAME
+ * proto_reg_handoff_6lowpan
+ * DESCRIPTION
+ * Protocol handoff routine for 6LoWPAN. Called after all
+ * protocols have been loaded.
+ * PARAMETERS
+ * none ;
+ * RETURNS
+ * void ;
+ *---------------------------------------------------------------
+ */
+void
+proto_reg_handoff_6lowpan(void)
+{
+ ipv6_handle = find_dissector_add_dependency("ipv6", proto_6lowpan);
+
+ /* Register the 6LoWPAN dissector with IEEE 802.15.4 */
+ dissector_add_for_decode_as(IEEE802154_PROTOABBREV_WPAN_PANID, handle_6lowpan);
+ heur_dissector_add(IEEE802154_PROTOABBREV_WPAN, dissect_6lowpan_heur, "6LoWPAN over IEEE 802.15.4", "6lowpan_wlan", proto_6lowpan, HEURISTIC_ENABLE);
+
+ /* Register Ethertype (RFC 7973) */
+ dissector_add_uint("ethertype", ETHERTYPE_6LOWPAN, handle_6lowpan);
+
+ dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_LE_IPSP, handle_6lowpan);
+ dissector_add_for_decode_as("btl2cap.cid", handle_6lowpan);
+} /* proto_reg_handoff_6lowpan */
+
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */