wireshark/epan/dissectors/packet-6lowpan.c

3739 lines
159 KiB
C
Raw Normal View History

/* 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 <stdio.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-ip.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];
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
/* Preferences */
static gboolean rfc4944_short_address_format = FALSE;
static gboolean iid_has_universal_local_bit = FALSE;
static gboolean ipv6_summary_in_tree = TRUE;
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
/* 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);
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
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
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
* 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 */
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
/*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) {
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
/* 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) {
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
/* 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(wmem_packet_scope(), 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(wmem_packet_scope(), 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(wmem_packet_scope(), &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(wmem_packet_scope(), &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(wmem_packet_scope(), 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(wmem_packet_scope(), 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(wmem_packet_scope(), 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(wmem_packet_scope(), 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(wmem_packet_scope(), 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;
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
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);
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
/* 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);
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
/* 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, "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);
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
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);
Support in 6lowpan for RFC4944 address generation For the conversion of a 16-bit short address in 6lowpan to an IID, there are several RFCs that produce different results. RFC 4944 section 6 specifies that the conversion uses the given PAN ID and the 16-bit short address. RFC 6282, on the other hand, specifies thta the conversion only uses the 16-bit short address and no longer uses the PAN ID. The current version of the 6lowpan dissector supports only the newer RFC 6282, but there are protocols out there that assume that the address conversion still abides to RFC 4944. In order to support these protocols and following the discussion from https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8970 this patch introduces a boolean preference in the 6lowpan dissector that indicates whether or not the older RFC 4944 should be used for address conversion. By default, it is set to FALSE, thus leaving the behavior of the dissector unchanged. Besides the boolean preference, another helper function lowpan_addr16_with_panid_to_ifcid has been written that implements the expected behavior from RFC 4944 using the same hint mechanism already in place in the dissector for the support of RFC 6282. Change-Id: I8d202c69a225d7b1212080a174e0111e5203553c Reviewed-on: https://code.wireshark.org/review/10902 Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com> Petri-Dish: Gerald Combs <gerald@wireshark.org> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-10-09 12:59:37 +00:00
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;
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:
*/