field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
		      MonoGenericContext *context)
{
	MonoClass *klass;
	MonoClassField *field;
	MonoTableInfo *tables = image->tables;
	MonoType *sig_type;
	guint32 cols[6];
	guint32 nindex, class, class_table;
	const char *fname;
	const char *ptr;
	guint32 idx = mono_metadata_token_index (token);

	mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
	nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
	class = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;

	fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);

	if (!mono_verifier_verify_memberref_signature (image, cols [MONO_MEMBERREF_SIGNATURE], NULL)) {
		mono_loader_set_error_bad_image (g_strdup_printf ("Bad field signature class token 0x%08x field name %s token 0x%08x on image %s", class, fname, token, image->name));
		return NULL;
	}

	switch (class) {
	case MONO_MEMBERREF_PARENT_TYPEDEF:
		class_table = MONO_TOKEN_TYPE_DEF;
		klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
		break;
	case MONO_MEMBERREF_PARENT_TYPEREF:
		class_table = MONO_TOKEN_TYPE_REF;
		klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
		break;
	case MONO_MEMBERREF_PARENT_TYPESPEC:
		class_table = MONO_TOKEN_TYPE_SPEC;
		klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, context);
		break;
	default:
		/*FIXME this must set a loader error!*/
		g_warning ("field load from %x", class);
		return NULL;
	}

	if (!klass) {
		char *name = mono_class_name_from_token (image, class_table | nindex);
		g_warning ("Missing field %s in class %s (type token %d)", fname, name, class_table | nindex);
		mono_loader_set_error_type_load (name, image->assembly_name);
		g_free (name);
		return NULL;
	}

	ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
	mono_metadata_decode_blob_size (ptr, &ptr);
	/* we may want to check the signature here... */

	if (*ptr++ != 0x6) {
		g_warning ("Bad field signature class token %08x field name %s token %08x", class, fname, token);
		mono_loader_set_error_field_load (klass, fname);
		return NULL;
	}
	/* FIXME: This needs a cache, especially for generic instances, since
	 * mono_metadata_parse_type () allocates everything from a mempool.
	 */
	sig_type = find_cached_memberref_sig (image, cols [MONO_MEMBERREF_SIGNATURE]);
	if (!sig_type) {
		sig_type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
		if (sig_type == NULL) {
			mono_loader_set_error_field_load (klass, fname);
			return NULL;
		}
		sig_type = cache_memberref_sig (image, cols [MONO_MEMBERREF_SIGNATURE], sig_type);
	}

	mono_class_init (klass); /*FIXME is this really necessary?*/
	if (retklass)
		*retklass = klass;
	field = mono_class_get_field_from_name_full (klass, fname, sig_type);

	if (!field)
		mono_loader_set_error_field_load (klass, fname);

	return field;
}


mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
{
	return mono_get_method_full (image, token, klass, NULL);
}

Search for dllimported shared libs in the base directory, not cwd.

* loader.c: we don't search the current directory anymore for shared
libraries referenced in DllImport attributes, as it has a slight
security risk. We search in the same directory where the referencing
image was loaded from, instead. Fixes bug# 641915.


mono_loader_unlock_if_inited (void)
{
	if (loader_lock_inited)
		mono_loader_unlock ();
}


mono_loader_cleanup (void)
{
	dllmap_cleanup ();

	TlsFree (loader_error_thread_id);
	TlsFree (loader_lock_nest_id);

	DeleteCriticalSection (&loader_mutex);
	loader_lock_inited = FALSE;
}


mono_loader_set_error_assembly_load (const char *assembly_name, gboolean ref_only)
{
	MonoLoaderError *error;

	if (mono_loader_get_last_error ())
		return;

	error = g_new0 (MonoLoaderError, 1);
	error->exception_type = MONO_EXCEPTION_FILE_NOT_FOUND;
	error->assembly_name = g_strdup (assembly_name);
	error->ref_only = ref_only;

	/*
	 * This is not strictly needed, but some (most) of the loader code still
	 * can't deal with load errors, and this message is more helpful than an
	 * assert.
	 */
	if (ref_only)
		g_warning ("Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.", assembly_name);
	else
		g_warning ("Could not load file or assembly '%s' or one of its dependencies.", assembly_name);

	set_loader_error (error);
}


mono_loader_error_prepare_exception (MonoLoaderError *error)
{
	MonoException *ex = NULL;

	switch (error->exception_type) {
	case MONO_EXCEPTION_TYPE_LOAD: {
		char *cname = g_strdup (error->class_name);
		char *aname = g_strdup (error->assembly_name);
		MonoString *class_name;

		mono_loader_clear_error ();

		class_name = mono_string_new (mono_domain_get (), cname);

		ex = mono_get_exception_type_load (class_name, aname);
		g_free (cname);
		g_free (aname);
		break;
        }
	case MONO_EXCEPTION_MISSING_METHOD: {
		char *cname = g_strdup (error->class_name);
		char *aname = g_strdup (error->member_name);

		mono_loader_clear_error ();
		ex = mono_get_exception_missing_method (cname, aname);
		g_free (cname);
		g_free (aname);
		break;
	}

	case MONO_EXCEPTION_MISSING_FIELD: {
		char *cnspace = g_strdup ((error->klass && *error->klass->name_space) ? error->klass->name_space : "");
		char *cname = g_strdup (error->klass ? error->klass->name : "");
		char *cmembername = g_strdup (error->member_name);
                char *class_name;

		mono_loader_clear_error ();
		class_name = g_strdup_printf ("%s%s%s", cnspace, cnspace ? "." : "", cname);

		ex = mono_get_exception_missing_field (class_name, cmembername);
		g_free (class_name);
		g_free (cname);
		g_free (cmembername);
		g_free (cnspace);
		break;
        }

	case MONO_EXCEPTION_FILE_NOT_FOUND: {
		char *msg;
		char *filename;

		if (error->ref_only)
			msg = g_strdup_printf ("Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.", error->assembly_name);
		else
			msg = g_strdup_printf ("Could not load file or assembly '%s' or one of its dependencies.", error->assembly_name);
		filename = g_strdup (error->assembly_name);
		/* Has to call this before calling anything which might call mono_class_init () */
		mono_loader_clear_error ();
		ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), filename));
		g_free (msg);
		g_free (filename);
		break;
	}

	case MONO_EXCEPTION_BAD_IMAGE: {
		char *msg = g_strdup (error->msg);
		mono_loader_clear_error ();
		ex = mono_get_exception_bad_image_format (msg);
		g_free (msg);
		break;
	}

	default:
		g_assert_not_reached ();
	}

	return ex;
}


mono_metadata_signature_vararg_match (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
{
	int i;

	if (sig1->hasthis != sig2->hasthis ||
	    sig1->sentinelpos != sig2->sentinelpos)
		return FALSE;

	for (i = 0; i < sig1->sentinelpos; i++) {
		MonoType *p1 = sig1->params[i];
		MonoType *p2 = sig2->params[i];

		/*if (p1->attrs != p2->attrs)
			return FALSE;
		*/
		if (!mono_metadata_type_equal (p1, p2))
			return FALSE;
	}

	if (!mono_metadata_type_equal (sig1->ret, sig2->ret))
		return FALSE;
	return TRUE;
}


struct timerqueue_node *timerqueue_getnext(struct timerqueue_head *head)
{
	struct rb_node *leftmost = rb_first_cached(&head->rb_root);

	return rb_entry(leftmost, struct timerqueue_node, node);
}

lib/timerqueue: Rely on rbtree semantics for next timer

Simplify the timerqueue code by using cached rbtrees and rely on the tree
leftmost node semantics to get the timer with earliest expiration time.
This is a drop in conversion, and therefore semantics remain untouched.

The runtime overhead of cached rbtrees is be pretty much the same as the
current head->next method, noting that when removing the leftmost node,
a common operation for the timerqueue, the rb_next(leftmost) is O(1) as
well, so the next timer will either be the right node or its parent.
Therefore no extra pointer chasing. Finally, the size of the struct
timerqueue_head remains the same.

Passes several hours of rcutorture.

Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lkml.kernel.org/r/20190724152323.bojciei3muvfxalm@linux-r8p5


bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node)
{
	struct rb_node **p = &head->rb_root.rb_root.rb_node;
	struct rb_node *parent = NULL;
	struct timerqueue_node *ptr;
	bool leftmost = true;

	/* Make sure we don't add nodes that are already added */
	WARN_ON_ONCE(!RB_EMPTY_NODE(&node->node));

	while (*p) {
		parent = *p;
		ptr = rb_entry(parent, struct timerqueue_node, node);
		if (node->expires < ptr->expires) {
			p = &(*p)->rb_left;
		} else {
			p = &(*p)->rb_right;
			leftmost = false;
		}
	}
	rb_link_node(&node->node, parent, p);
	rb_insert_color_cached(&node->node, &head->rb_root, leftmost);

	return leftmost;
}


bool timerqueue_del(struct timerqueue_head *head, struct timerqueue_node *node)
{
	WARN_ON_ONCE(RB_EMPTY_NODE(&node->node));

	rb_erase_cached(&node->node, &head->rb_root);
	RB_CLEAR_NODE(&node->node);

	return !RB_EMPTY_ROOT(&head->rb_root.rb_root);
}


static inline void timerqueue_init_head(struct timerqueue_head *head)
{
	head->rb_root = RB_ROOT_CACHED;
}


static inline void timerqueue_init(struct timerqueue_node *node)
{
	RB_CLEAR_NODE(&node->node);
}


struct timerqueue_node *timerqueue_iterate_next(struct timerqueue_node *node)
{
	struct rb_node *next;

	if (!node)
		return NULL;
	next = rb_next(&node->node);
	if (!next)
		return NULL;
	return container_of(next, struct timerqueue_node, node);
}


proto_reg_handoff_dnp3(void)
{
  /* register as heuristic dissector for both TCP and UDP */
  heur_dissector_add("tcp", dissect_dnp3_tcp_heur, "DNP 3.0 over TCP", "dnp3_tcp", proto_dnp3, HEURISTIC_DISABLE);
  heur_dissector_add("udp", dissect_dnp3_udp_heur, "DNP 3.0 over UDP", "dnp3_udp", proto_dnp3, HEURISTIC_DISABLE);

  dissector_add_uint_with_preference("tcp.port", TCP_PORT_DNP, dnp3_tcp_handle);
  dissector_add_uint_with_preference("udp.port", UDP_PORT_DNP, dnp3_udp_handle);
  dissector_add_for_decode_as("rtacser.data", dnp3_udp_handle);

  ssl_dissector_add(TCP_PORT_DNP_TLS, dnp3_tcp_handle);
}

dnp: plug a memory leak.

If we're throwing away the data, *throw away the data* - free it, as
we're not using it as the backing data for a tvbuff.


dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_tree *point_tree, proto_item *point_item, enum QUALITY_TYPE type)
{

  proto_tree *quality_tree;
  proto_item *quality_item;
  int         hf0 = 0, hf1 = 0, hf2 = 0, hf3 = 0, hf4 = 0, hf5 = 0, hf6 = 0, hf7 = 0;

  /* Common code */
  proto_item_append_text(point_item, " (Quality: ");
  quality_tree = proto_tree_add_subtree(point_tree, tvb, offset, 1, ett_dnp3_al_obj_quality, &quality_item, "Quality: ");

  if (al_ptflags & AL_OBJ_BI_FLAG0) {
    dnp3_append_2item_text(point_item, quality_item, "Online");
  }
  else {
    dnp3_append_2item_text(point_item, quality_item, "Offline");
  }
  if (al_ptflags & AL_OBJ_BI_FLAG1) dnp3_append_2item_text(point_item, quality_item, ", Restart");
  if (al_ptflags & AL_OBJ_BI_FLAG2) dnp3_append_2item_text(point_item, quality_item, ", Comm Fail");
  if (al_ptflags & AL_OBJ_BI_FLAG3) dnp3_append_2item_text(point_item, quality_item, ", Remote Force");
  if (al_ptflags & AL_OBJ_BI_FLAG4) dnp3_append_2item_text(point_item, quality_item, ", Local Force");

  switch (type) {
    case BIN_IN: /* Binary Input Quality flags */
      if (al_ptflags & AL_OBJ_BI_FLAG5) dnp3_append_2item_text(point_item, quality_item, ", Chatter Filter");

      hf0 = hf_dnp3_al_biq_b0;
      hf1 = hf_dnp3_al_biq_b1;
      hf2 = hf_dnp3_al_biq_b2;
      hf3 = hf_dnp3_al_biq_b3;
      hf4 = hf_dnp3_al_biq_b4;
      hf5 = hf_dnp3_al_biq_b5;
      hf6 = hf_dnp3_al_biq_b6;
      hf7 = hf_dnp3_al_biq_b7;
      break;

    case BIN_OUT: /* Binary Output Quality flags */
      hf0 = hf_dnp3_al_boq_b0;
      hf1 = hf_dnp3_al_boq_b1;
      hf2 = hf_dnp3_al_boq_b2;
      hf3 = hf_dnp3_al_boq_b3;
      hf4 = hf_dnp3_al_boq_b4;
      hf5 = hf_dnp3_al_boq_b5;
      hf6 = hf_dnp3_al_boq_b6;
      hf7 = hf_dnp3_al_boq_b7;
      break;

    case ANA_IN: /* Analog Input Quality flags */
      if (al_ptflags & AL_OBJ_AI_FLAG5) dnp3_append_2item_text(point_item, quality_item, ", Over-Range");
      if (al_ptflags & AL_OBJ_AI_FLAG6) dnp3_append_2item_text(point_item, quality_item, ", Reference Check");

      hf0 = hf_dnp3_al_aiq_b0;
      hf1 = hf_dnp3_al_aiq_b1;
      hf2 = hf_dnp3_al_aiq_b2;
      hf3 = hf_dnp3_al_aiq_b3;
      hf4 = hf_dnp3_al_aiq_b4;
      hf5 = hf_dnp3_al_aiq_b5;
      hf6 = hf_dnp3_al_aiq_b6;
      hf7 = hf_dnp3_al_aiq_b7;
      break;

    case ANA_OUT: /* Analog Output Quality flags */
      hf0 = hf_dnp3_al_aoq_b0;
      hf1 = hf_dnp3_al_aoq_b1;
      hf2 = hf_dnp3_al_aoq_b2;
      hf3 = hf_dnp3_al_aoq_b3;
      hf4 = hf_dnp3_al_aoq_b4;
      hf5 = hf_dnp3_al_aoq_b5;
      hf6 = hf_dnp3_al_aoq_b6;
      hf7 = hf_dnp3_al_aoq_b7;
      break;

    case COUNTER: /* Counter Quality flags */
      if (al_ptflags & AL_OBJ_CTR_FLAG5) dnp3_append_2item_text(point_item, quality_item, ", Roll-over");
      if (al_ptflags & AL_OBJ_CTR_FLAG6) dnp3_append_2item_text(point_item, quality_item, ", Discontinuity");

      hf0 = hf_dnp3_al_ctrq_b0;
      hf1 = hf_dnp3_al_ctrq_b1;
      hf2 = hf_dnp3_al_ctrq_b2;
      hf3 = hf_dnp3_al_ctrq_b3;
      hf4 = hf_dnp3_al_ctrq_b4;
      hf5 = hf_dnp3_al_ctrq_b5;
      hf6 = hf_dnp3_al_ctrq_b6;
      hf7 = hf_dnp3_al_ctrq_b7;
      break;
  }

  if (quality_tree != NULL) {
    proto_tree_add_item(quality_tree, hf7, tvb, offset, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(quality_tree, hf6, tvb, offset, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(quality_tree, hf5, tvb, offset, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(quality_tree, hf4, tvb, offset, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(quality_tree, hf3, tvb, offset, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(quality_tree, hf2, tvb, offset, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(quality_tree, hf1, tvb, offset, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(quality_tree, hf0, tvb, offset, 1, ENC_LITTLE_ENDIAN);
  }
  proto_item_append_text(point_item, ")");
}


dnp3_al_process_iin(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *al_tree)
{
  guint16     al_iin;
  proto_item *tiin;
  static int* const indications[] = {
      &hf_dnp3_al_iin_rst,
      &hf_dnp3_al_iin_dt,
      &hf_dnp3_al_iin_dol,
      &hf_dnp3_al_iin_tsr,
      &hf_dnp3_al_iin_cls3d,
      &hf_dnp3_al_iin_cls2d,
      &hf_dnp3_al_iin_cls1d,
      &hf_dnp3_al_iin_bmsg,
      &hf_dnp3_al_iin_cc,
      &hf_dnp3_al_iin_oae,
      &hf_dnp3_al_iin_ebo,
      &hf_dnp3_al_iin_pioor,
      &hf_dnp3_al_iin_obju,
      &hf_dnp3_al_iin_fcni,
      NULL
  };

  tiin = proto_tree_add_bitmask(al_tree, tvb, offset, hf_dnp3_al_iin, ett_dnp3_al_iin, indications, ENC_BIG_ENDIAN);
  al_iin = tvb_get_ntohs(tvb, offset);

  /* If IIN indicates an abnormal condition, add expert info */
  if ((al_iin & AL_IIN_DT) || (al_iin & AL_IIN_CC) || (al_iin & AL_IIN_OAE) || (al_iin & AL_IIN_EBO) ||
      (al_iin & AL_IIN_PIOOR) || (al_iin & AL_IIN_OBJU) || (al_iin & AL_IIN_FCNI)) {
      expert_add_info(pinfo, tiin, &ei_dnp_iin_abnormal);
  }
}


dissect_dnp3_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
  if (!check_dnp3_header(tvb, FALSE)) {
    return 0;
  }

  tcp_dissect_pdus(tvb, pinfo, tree, TRUE, DNP_HDR_LEN,
                   get_dnp3_message_len, dissect_dnp3_message, data);

  return tvb_captured_length(tvb);
}


proto_register_dnp3(void)
{

/* Setup list of header fields */
  static hf_register_info hf[] = {
    { &hf_dnp3_start,
      { "Start Bytes", "dnp3.start",
        FT_UINT16, BASE_HEX, NULL, 0x0,
        NULL, HFILL }
    },

    { &hf_dnp3_len,
      { "Length", "dnp3.len",
        FT_UINT8, BASE_DEC, NULL, 0x0,
        "Frame Data Length", HFILL }
    },

    { &hf_dnp3_ctl,
      { "Control", "dnp3.ctl",
        FT_UINT8, BASE_HEX, NULL, 0x0,
        "Frame Control Byte", HFILL }
    },

    { &hf_dnp3_ctl_prifunc,
      { "Control Function Code", "dnp3.ctl.prifunc",
        FT_UINT8, BASE_DEC, VALS(dnp3_ctl_func_pri_vals), DNP3_CTL_FUNC,
        "Frame Control Function Code", HFILL }
    },

    { &hf_dnp3_ctl_secfunc,
      { "Control Function Code", "dnp3.ctl.secfunc",
        FT_UINT8, BASE_DEC, VALS(dnp3_ctl_func_sec_vals), DNP3_CTL_FUNC,
        "Frame Control Function Code", HFILL }
    },

    { &hf_dnp3_ctlobj_code_c,
      { "Operation Type", "dnp3.ctl.op",
        FT_UINT8, BASE_DEC, VALS(dnp3_al_ctlc_code_vals), AL_OBJCTLC_CODE,
        "Control Code, Operation Type", HFILL }
    },

    { &hf_dnp3_ctlobj_code_m,
      { "Queue / Clear Field", "dnp3.ctl.clr",
        FT_UINT8, BASE_DEC, VALS(dnp3_al_ctlc_misc_vals), AL_OBJCTLC_MISC,
        "Control Code, Clear Field", HFILL }
    },

    { &hf_dnp3_ctlobj_code_tc,
      { "Trip Control Code", "dnp3.ctl.trip",
        FT_UINT8, BASE_DEC, VALS(dnp3_al_ctlc_tc_vals), AL_OBJCTLC_TC,
        "Control Code, Trip Close Control", HFILL }
    },

    { &hf_dnp3_ctl_dir,
      { "Direction", "dnp3.ctl.dir",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_DIR,
        NULL, HFILL }
    },

    { &hf_dnp3_ctl_prm,
      { "Primary", "dnp3.ctl.prm",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_PRM,
        NULL, HFILL }
    },

    { &hf_dnp3_ctl_fcb,
      { "Frame Count Bit", "dnp3.ctl.fcb",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_FCB,
        NULL, HFILL }
    },

    { &hf_dnp3_ctl_fcv,
      { "Frame Count Valid", "dnp3.ctl.fcv",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_FCV,
        NULL, HFILL }
    },

    { &hf_dnp3_ctl_dfc,
      { "Data Flow Control", "dnp3.ctl.dfc",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_CTL_DFC,
        NULL, HFILL }
    },

    { &hf_dnp3_dst,
      { "Destination", "dnp3.dst",
        FT_UINT16, BASE_DEC, NULL, 0x0,
        "Destination Address", HFILL }
    },

    { &hf_dnp3_src,
      { "Source", "dnp3.src",
        FT_UINT16, BASE_DEC, NULL, 0x0,
        "Source Address", HFILL }
    },

    { &hf_dnp3_addr,
      { "Address", "dnp3.addr",
        FT_UINT16, BASE_DEC, NULL, 0x0,
        "Source or Destination Address", HFILL }
    },

    { &hf_dnp3_data_hdr_crc,
      { "Data Link Header checksum", "dnp3.hdr.CRC",
        FT_UINT16, BASE_HEX, NULL, 0x0,
        NULL, HFILL }
    },

    { &hf_dnp3_data_hdr_crc_status,
        { "Data Link Header Checksum Status", "dnp.hdr.CRC.status",
        FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
        NULL, HFILL }
    },

    { &hf_dnp3_tr_ctl,
      { "Transport Control", "dnp3.tr.ctl",
        FT_UINT8, BASE_HEX, NULL, 0x0,
        "Transport Layer Control Byte", HFILL }
    },

    { &hf_dnp3_tr_fin,
      { "Final", "dnp3.tr.fin",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_TR_FIN,
        NULL, HFILL }
    },

    { &hf_dnp3_tr_fir,
      { "First", "dnp3.tr.fir",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_TR_FIR,
        NULL, HFILL }
    },

    { &hf_dnp3_tr_seq,
      { "Sequence", "dnp3.tr.seq",
        FT_UINT8, BASE_DEC, NULL, DNP3_TR_SEQ,
        "Frame Sequence Number", HFILL }
    },

    { &hf_dnp3_data_chunk,
      { "Data Chunk", "dnp.data_chunk",
        FT_BYTES, BASE_NONE, NULL, 0x0,
        NULL, HFILL }
    },

    { &hf_dnp3_data_chunk_len,
      { "Data Chunk length", "dnp.data_chunk_len",
        FT_UINT16, BASE_DEC, NULL, 0x0,
        NULL, HFILL }
    },

    { &hf_dnp3_data_chunk_crc,
      { "Data Chunk checksum", "dnp.data_chunk.CRC",
        FT_UINT16, BASE_HEX, NULL, 0x0,
        NULL, HFILL }
    },

    { &hf_dnp3_data_chunk_crc_status,
        { "Data Chunk Checksum Status", "dnp.data_chunk.CRC.status",
        FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
        NULL, HFILL }
    },

    { &hf_dnp3_al_ctl,
      { "Application Control", "dnp3.al.ctl",
        FT_UINT8, BASE_HEX, NULL, 0x0,
        "Application Layer Control Byte", HFILL }
    },

    { &hf_dnp3_al_fir,
      { "First", "dnp3.al.fir",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_FIR,
        NULL, HFILL }
    },

    { &hf_dnp3_al_fin,
      { "Final", "dnp3.al.fin",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_FIN,
        NULL, HFILL }
    },

    { &hf_dnp3_al_con,
      { "Confirm", "dnp3.al.con",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_CON,
        NULL, HFILL }
    },

    { &hf_dnp3_al_uns,
      { "Unsolicited", "dnp3.al.uns",
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), DNP3_AL_UNS,
        NULL, HFILL }
    },

    { &hf_dnp3_al_seq,
      { "Sequence", "dnp3.al.seq",
        FT_UINT8, BASE_DEC, NULL, DNP3_AL_SEQ,
        "Frame Sequence Number", HFILL }
    },

    { &hf_dnp3_al_func,
      { "Application Layer Function Code", "dnp3.al.func",
        FT_UINT8, BASE_DEC|BASE_EXT_STRING, &dnp3_al_func_vals_ext, DNP3_AL_FUNC,
        "Application Function Code", HFILL }
    },

    { &hf_dnp3_al_iin,
      { "Internal Indications", "dnp3.al.iin",
        FT_UINT16, BASE_HEX, NULL, 0x0,
        "Application Layer IIN", HFILL }
    },

    { &hf_dnp3_al_iin_bmsg,
      { "Broadcast Msg Rx", "dnp3.al.iin.bmsg",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_BMSG,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_cls1d,
      { "Class 1 Data Available", "dnp3.al.iin.cls1d",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CLS1D,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_cls2d,
      { "Class 2 Data Available", "dnp3.al.iin.cls2d",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CLS2D,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_cls3d,
      { "Class 3 Data Available", "dnp3.al.iin.cls3d",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CLS3D,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_tsr,
      { "Time Sync Required", "dnp3.al.iin.tsr",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_TSR,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_dol,
      { "Digital Outputs in Local", "dnp3.al.iin.dol",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_DOL,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_dt,
      { "Device Trouble", "dnp3.al.iin.dt",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_DT,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_rst,
      { "Device Restart", "dnp3.al.iin.rst",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_RST,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_fcni,
      { "Function Code not implemented", "dnp3.al.iin.fcni",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_FCNI,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_obju,
      { "Requested Objects Unknown", "dnp3.al.iin.obju",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_OBJU,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_pioor,
      { "Parameters Invalid or Out of Range", "dnp3.al.iin.pioor",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_PIOOR,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_ebo,
      { "Event Buffer Overflow", "dnp3.al.iin.ebo",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_EBO,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_oae,
      { "Operation Already Executing", "dnp3.al.iin.oae",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_OAE,
        NULL, HFILL }
    },

    { &hf_dnp3_al_iin_cc,
      { "Configuration Corrupt", "dnp3.al.iin.cc",
        FT_BOOLEAN, 16, TFS(&tfs_set_notset), AL_IIN_CC,
        NULL, HFILL }
    },

    { &hf_dnp3_al_obj,
      { "Object", "dnp3.al.obj",
        FT_UINT16, BASE_HEX|BASE_EXT_STRING, &dnp3_al_obj_vals_ext, 0x0,
        "Application Layer Object", HFILL }
    },

    { &hf_dnp3_al_objq_prefix,
      { "Prefix Code", "dnp3.al.objq.prefix",
        FT_UINT8, BASE_DEC|BASE_EXT_STRING, &dnp3_al_objq_prefix_vals_ext, AL_OBJQ_PREFIX,
        "Object Prefix Code", HFILL }
    },

    { &hf_dnp3_al_objq_range,
      { "Range Code", "dnp3.al.objq.range",
        FT_UINT8, BASE_DEC|BASE_EXT_STRING, &dnp3_al_objq_range_vals_ext, AL_OBJQ_RANGE,
        "Object Range Specifier Code", HFILL }
    },

    { &hf_dnp3_al_range_start8,
      { "Start (8 bit)", "dnp3.al.range.start",
        FT_UINT8, BASE_DEC, NULL, 0x0,
        "Object Start Index", HFILL }
    },

    { &hf_dnp3_al_range_stop8,
      { "Stop (8 bit)", "dnp3.al.range.stop",
        FT_UINT8, BASE_DEC, NULL, 0x0,
        "Object Stop Index", HFILL }
    },

    { &hf_dnp3_al_range_start16,
      { "Start (16 bit)", "dnp3.al.range.start",
        FT_UINT16, BASE_DEC, NULL, 0x0,
        "Object Start Index", HFILL }
    },

    { &hf_dnp3_al_range_stop16,
      { "Stop (16 bit)", "dnp3.al.range.stop",
        FT_UINT16, BASE_DEC, NULL, 0x0,
        "Object Stop Index", HFILL }
    },

    { &hf_dnp3_al_range_start32,
      { "Start (32 bit)", "dnp3.al.range.start",
        FT_UINT32, BASE_DEC, NULL, 0x0,
        "Object Start Index", HFILL }
    },

    { &hf_dnp3_al_range_stop32,
      { "Stop (32 bit)", "dnp3.al.range.stop",
        FT_UINT32, BASE_DEC, NULL, 0x0,
        "Object Stop Index", HFILL }
    },

    { &hf_dnp3_al_range_abs8,
      { "Address (8 bit)", "dnp3.al.range.abs",
        FT_UINT8, BASE_DEC, NULL, 0x0,
        "Object Absolute Address", HFILL }
    },

    { &hf_dnp3_al_range_abs16,
      { "Address (16 bit)", "dnp3.al.range.abs",
        FT_UINT16, BASE_DEC, NULL, 0x0,
        "Object Absolute Address", HFILL }
    },

    { &hf_dnp3_al_range_abs32,
      { "Address (32 bit)", "dnp3.al.range.abs",
        FT_UINT32, BASE_DEC, NULL, 0x0,
        "Object Absolute Address", HFILL }
    },

    { &hf_dnp3_al_range_quant8,
      { "Quantity (8 bit)", "dnp3.al.range.quantity",
        FT_UINT8, BASE_DEC, NULL, 0x0,
        "Object Quantity", HFILL }
    },

    { &hf_dnp3_al_range_quant16,
      { "Quantity (16 bit)", "dnp3.al.range.quantity",
        FT_UINT16, BASE_DEC, NULL, 0x0,
        "Object Quantity", HFILL }
    },

    { &hf_dnp3_al_range_quant32,
      { "Quantity (32 bit)", "dnp3.al.range.quantity",
        FT_UINT32, BASE_DEC, NULL, 0x0,
        "Object Quantity", HFILL }
    },

    { &hf_dnp3_al_index8,
      { "Index (8 bit)", "dnp3.al.index",
        FT_UINT8, BASE_DEC, NULL, 0x0,
        "Object Index", HFILL }
    },

    { &hf_dnp3_al_index16,
      { "Index (16 bit)", "dnp3.al.index",
        FT_UINT16, BASE_DEC, NULL, 0x0,
        "Object Index", HFILL }
    },

    { &hf_dnp3_al_index32,
      { "Index (32 bit)", "dnp3.al.index",
        FT_UINT32, BASE_DEC, NULL, 0x0,
        "Object Index", HFILL }
    },

#if 0
    { &hf_dnp3_al_ptnum,
      { "Object Point Number", "dnp3.al.ptnum",
        FT_UINT16, BASE_DEC, NULL, 0x0,
        NULL, HFILL }
    },
#endif

    { &hf_dnp3_al_size8,
      { "Size (8 bit)", "dnp3.al.size",
          FT_UINT8, BASE_DEC, NULL, 0x0,
          "Object Size", HFILL }
    },

    { &hf_dnp3_al_size16,
      { "Size (16 bit)", "dnp3.al.size",
          FT_UINT16, BASE_DEC, NULL, 0x0,
          "Object Size", HFILL }
    },

    { &hf_dnp3_al_size32,
      { "Size (32 bit)", "dnp3.al.size",
          FT_UINT32, BASE_DEC, NULL, 0x0,
          "Object Size", HFILL }
    },

    { &hf_dnp3_bocs_bit,
      { "Commanded State", "dnp3.al.bocs",
          FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x80,
          "Binary Output Commanded state", HFILL }
    },

    { &hf_dnp3_al_bit,
      { "Value (bit)", "dnp3.al.bit",
          FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x1,
          "Digital Value (1 bit)", HFILL }
    },

    { &hf_dnp3_al_2bit,
      { "Value (two bit)", "dnp3.al.2bit",
          FT_UINT8, BASE_DEC, NULL, 0x0,
          "Digital Value (2 bit)", HFILL }
    },

    { &hf_dnp3_al_ana16,
      { "Value (16 bit)", "dnp3.al.ana.int",
          FT_INT16, BASE_DEC, NULL, 0x0,
          "Analog Value (16 bit)", HFILL }
    },

    { &hf_dnp3_al_ana32,
      { "Value (32 bit)", "dnp3.al.ana.int",
          FT_INT32, BASE_DEC, NULL, 0x0,
          "Analog Value (32 bit)", HFILL }
    },

    { &hf_dnp3_al_anaflt,
      { "Value (float)", "dnp3.al.ana.float",
          FT_FLOAT, BASE_NONE, NULL, 0x0,
          "Analog Value (float)", HFILL }
    },

    { &hf_dnp3_al_anadbl,
      { "Value (double)", "dnp3.al.ana.double",
          FT_DOUBLE, BASE_NONE, NULL, 0x0,
          "Analog Value (double)", HFILL }
    },

    { &hf_dnp3_al_anaout16,
      { "Output Value (16 bit)", "dnp3.al.anaout.int",
          FT_INT16, BASE_DEC, NULL, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_anaout32,
      { "Output Value (32 bit)", "dnp3.al.anaout.int",
          FT_INT32, BASE_DEC, NULL, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_anaoutflt,
      { "Output Value (float)", "dnp3.al.anaout.float",
          FT_FLOAT, BASE_NONE, NULL, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_anaoutdbl,
      { "Output (double)", "dnp3.al.anaout.double",
          FT_DOUBLE, BASE_NONE, NULL, 0x0,
          "Output Value (double)", HFILL }
    },

    { &hf_dnp3_al_cnt16,
      { "Counter (16 bit)", "dnp3.al.cnt",
          FT_UINT16, BASE_DEC, NULL, 0x0,
          "Counter Value (16 bit)", HFILL }
    },

    { &hf_dnp3_al_cnt32,
      { "Counter (32 bit)", "dnp3.al.cnt",
          FT_UINT32, BASE_DEC, NULL, 0x0,
          "Counter Value (32 bit)", HFILL }
    },

    { &hf_dnp3_al_ctrlstatus,
      { "Control Status", "dnp3.al.ctrlstatus",
          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &dnp3_al_ctl_status_vals_ext, AL_OBJCTL_STATUS_MASK,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_mode,
      { "File Control Mode", "dnp3.al.file.mode",
          FT_UINT16, BASE_DEC, VALS(dnp3_al_file_mode_vals), 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_auth,
      { "File Authentication Key", "dnp3.al.file.auth",
          FT_UINT32, BASE_HEX, NULL, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_size,
      { "File Size", "dnp3.al.file.size",
          FT_UINT32, BASE_HEX, NULL, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_maxblk,
      { "File Max Block Size", "dnp3.al.file.maxblock",
          FT_UINT16, BASE_DEC, NULL, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_reqID,
      { "File Request Identifier", "dnp3.al.file.reqID",
          FT_UINT16, BASE_DEC, NULL, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_status,
      { "File Control Status", "dnp3.al.file.status",
          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &dnp3_al_file_status_vals_ext, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_handle,
      { "File Handle", "dnp3.al.file.handle",
          FT_UINT32, BASE_HEX, NULL, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_blocknum,
      { "File Block Number", "dnp3.al.file.blocknum",
          FT_UINT32, BASE_HEX, NULL, 0x7fffffff,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_lastblock,
      { "File Last Block", "dnp3.al.file.lastblock",
          FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x80000000,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_data,
      { "File Data", "dnp3.al.file.data",
          FT_BYTES, BASE_NONE, NULL, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_biq_b0,
      { "Online", "dnp3.al.biq.b0",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_biq_b1,
      { "Restart", "dnp3.al.biq.b1",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG1,
          NULL, HFILL }
    },

    { &hf_dnp3_al_biq_b2,
      { "Comm Fail", "dnp3.al.biq.b2",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG2,
          NULL, HFILL }
    },

    { &hf_dnp3_al_biq_b3,
      { "Remote Force", "dnp3.al.biq.b3",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG3,
          NULL, HFILL }
    },

    { &hf_dnp3_al_biq_b4,
      { "Local Force", "dnp3.al.biq.b4",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG4,
          NULL, HFILL }
    },

    { &hf_dnp3_al_biq_b5,
      { "Chatter Filter", "dnp3.al.biq.b5",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG5,
          NULL, HFILL }
    },

    { &hf_dnp3_al_biq_b6,
      { "Reserved", "dnp3.al.biq.b6",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG6,
          NULL, HFILL }
    },

    { &hf_dnp3_al_biq_b7,
      { "Point Value", "dnp3.al.biq.b7",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BI_FLAG7,
          NULL, HFILL }
    },

    { &hf_dnp3_al_boq_b0,
      { "Online", "dnp3.al.boq.b0",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_boq_b1,
      { "Restart", "dnp3.al.boq.b1",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG1,
          NULL, HFILL }
    },

    { &hf_dnp3_al_boq_b2,
      { "Comm Fail", "dnp3.al.boq.b2",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG2,
          NULL, HFILL }
    },

    { &hf_dnp3_al_boq_b3,
      { "Remote Force", "dnp3.al.boq.b3",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG3,
          NULL, HFILL }
    },

    { &hf_dnp3_al_boq_b4,
      { "Local Force", "dnp3.al.boq.b4",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG4,
          NULL, HFILL }
    },

    { &hf_dnp3_al_boq_b5,
      { "Reserved", "dnp3.al.boq.b5",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG5,
          NULL, HFILL }
    },

    { &hf_dnp3_al_boq_b6,
      { "Reserved", "dnp3.al.boq.b6",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG6,
          NULL, HFILL }
    },

    { &hf_dnp3_al_boq_b7,
      { "Point Value", "dnp3.al.boq.b7",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_BO_FLAG7,
          NULL, HFILL }
    },

    { &hf_dnp3_al_ctrq_b0,
      { "Online", "dnp3.al.ctrq.b0",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_ctrq_b1,
      { "Restart", "dnp3.al.ctrq.b1",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG1,
          NULL, HFILL }
    },

    { &hf_dnp3_al_ctrq_b2,
      { "Comm Fail", "dnp3.al.ctrq.b2",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG2,
          NULL, HFILL }
    },

    { &hf_dnp3_al_ctrq_b3,
      { "Remote Force", "dnp3.al.ctrq.b3",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG3,
          NULL, HFILL }
    },

    { &hf_dnp3_al_ctrq_b4,
      { "Local Force", "dnp3.al.ctrq.b4",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG4,
          NULL, HFILL }
    },

    { &hf_dnp3_al_ctrq_b5,
      { "Roll-Over", "dnp3.al.ctrq.b5",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG5,
          NULL, HFILL }
    },

    { &hf_dnp3_al_ctrq_b6,
      { "Discontinuity", "dnp3.al.ctrq.b6",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG6,
          NULL, HFILL }
    },

    { &hf_dnp3_al_ctrq_b7,
      { "Reserved", "dnp3.al.ctrq.b7",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_CTR_FLAG7,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aiq_b0,
      { "Online", "dnp3.al.aiq.b0",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aiq_b1,
      { "Restart", "dnp3.al.aiq.b1",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG1,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aiq_b2,
      { "Comm Fail", "dnp3.al.aiq.b2",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG2,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aiq_b3,
      { "Remote Force", "dnp3.al.aiq.b3",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG3,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aiq_b4,
      { "Local Force", "dnp3.al.aiq.b4",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG4,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aiq_b5,
      { "Over-Range", "dnp3.al.aiq.b5",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG5,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aiq_b6,
      { "Reference Check", "dnp3.al.aiq.b6",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG6,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aiq_b7,
      { "Reserved", "dnp3.al.aiq.b7",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AI_FLAG7,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aoq_b0,
      { "Online", "dnp3.al.aoq.b0",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aoq_b1,
      { "Restart", "dnp3.al.aoq.b1",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG1,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aoq_b2,
      { "Comm Fail", "dnp3.al.aoq.b2",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG2,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aoq_b3,
      { "Remote Force", "dnp3.al.aoq.b3",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG3,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aoq_b4,
      { "Local Force", "dnp3.al.aoq.b4",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG4,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aoq_b5,
      { "Reserved", "dnp3.al.aoq.b5",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG5,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aoq_b6,
      { "Reserved", "dnp3.al.aoq.b6",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG6,
          NULL, HFILL }
    },

    { &hf_dnp3_al_aoq_b7,
      { "Reserved", "dnp3.al.aoq.b7",
          FT_BOOLEAN, 8, TFS(&tfs_set_notset), AL_OBJ_AO_FLAG7,
          NULL, HFILL }
    },

    { &hf_dnp3_al_timestamp,
      { "Timestamp", "dnp3.al.timestamp",
          FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0,
          "Object Timestamp", HFILL }
    },

    { &hf_dnp3_al_file_perms,
      { "Permissions", "dnp3.al.file.perms",
          FT_UINT16, BASE_OCT, NULL, 0x0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_perms_read_owner,
      { "Read permission for owner", "dnp3.al.file.perms.read_owner",
          FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0400,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_perms_write_owner,
      { "Write permission for owner", "dnp3.al.file.perms.write_owner",
          FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0200,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_perms_exec_owner,
      { "Execute permission for owner", "dnp3.al.file.perms.exec_owner",
          FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0100,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_perms_read_group,
      { "Read permission for group", "dnp3.al.file.perms.read_group",
          FT_BOOLEAN, 16, TFS(&tfs_yes_no), 040,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_perms_write_group,
      { "Write permission for group", "dnp3.al.file.perms.write_group",
          FT_BOOLEAN, 16, TFS(&tfs_yes_no), 020,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_perms_exec_group,
      { "Execute permission for group", "dnp3.al.file.perms.exec_group",
          FT_BOOLEAN, 16, TFS(&tfs_yes_no), 010,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_perms_read_world,
      { "Read permission for world", "dnp3.al.file.perms.read_world",
          FT_BOOLEAN, 16, TFS(&tfs_yes_no), 04,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_perms_write_world,
      { "Write permission for world", "dnp3.al.file.perms.write_world",
          FT_BOOLEAN, 16, TFS(&tfs_yes_no), 02,
          NULL, HFILL }
    },

    { &hf_dnp3_al_file_perms_exec_world,
      { "Execute permission for world", "dnp3.al.file.perms.exec_world",
          FT_BOOLEAN, 16, TFS(&tfs_yes_no), 01,
          NULL, HFILL }
    },

    { &hf_dnp3_al_rel_timestamp,
      { "Relative Timestamp", "dnp3.al.reltimestamp",
          FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
          "Object Relative Timestamp", HFILL }
    },

    { &hf_dnp3_al_datatype,
      { "Data Type", "dnp3.al.datatype",
          FT_UINT8, BASE_HEX, VALS(dnp3_al_data_type_vals), 0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_da_length,
      { "Device Attribute Length", "dnp3.al.da.length",
          FT_UINT8, BASE_DEC, NULL, 0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_da_uint8,
      { "Device Attribute 8-Bit Unsigned Integer Value", "dnp3.al.da.uint8",
          FT_UINT8, BASE_DEC, NULL, 0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_da_uint16,
      { "Device Attribute 16-Bit Unsigned Integer Value", "dnp3.al.da.uint16",
          FT_UINT16, BASE_DEC, NULL, 0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_da_uint32,
      { "Device Attribute 32-Bit Unsigned Integer Value", "dnp3.al.da.uint32",
          FT_UINT32, BASE_DEC, NULL, 0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_da_int8,
      { "Device Attribute 8-Bit Integer Value", "dnp3.al.da.int8",
          FT_INT8, BASE_DEC, NULL, 0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_da_int16,
      { "Device Attribute 16-Bit Integer Value", "dnp3.al.da.int16",
          FT_INT16, BASE_DEC, NULL, 0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_da_int32,
      { "Device Attribute 32-Bit Integer Value", "dnp3.al.da.int32",
          FT_INT32, BASE_DEC, NULL, 0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_da_flt,
      { "Device Attribute Float Value", "dnp3.al.da.float",
          FT_FLOAT, BASE_NONE, NULL, 0,
          NULL, HFILL }
    },

    { &hf_dnp3_al_da_dbl,
      { "Device Attribute Double Value", "dnp3.al.da.double",
          FT_DOUBLE, BASE_NONE, NULL, 0,
          NULL, HFILL }
    },

    { &hf_al_frag_data,
      {"DNP3.0 AL Fragment Data", "dnp3.al.frag_data",
          FT_BYTES, BASE_NONE, NULL, 0x00,
          "DNP 3.0 Application Layer Fragment Data", HFILL }},

    { &hf_dnp3_fragment,
      { "DNP 3.0 AL Fragment", "dnp3.al.fragment",
          FT_FRAMENUM, BASE_NONE, NULL, 0x0,
          "DNP 3.0 Application Layer Fragment", HFILL }
    },

    { &hf_dnp3_fragments,
      { "DNP 3.0 AL Fragments", "dnp3.al.fragments",
          FT_NONE, BASE_NONE, NULL, 0x0,
          "DNP 3.0 Application Layer Fragments", HFILL }
    },

    { &hf_dnp3_fragment_overlap,
      { "Fragment overlap", "dnp3.al.fragment.overlap",
          FT_BOOLEAN, BASE_NONE, NULL, 0x0,
          "Fragment overlaps with other fragments", HFILL }
    },

    { &hf_dnp3_fragment_overlap_conflict,
      { "Conflicting data in fragment overlap", "dnp3.al.fragment.overlap.conflict",
          FT_BOOLEAN, BASE_NONE, NULL, 0x0,
          "Overlapping fragments contained conflicting data", HFILL }
    },

    { &hf_dnp3_fragment_multiple_tails,
      { "Multiple tail fragments found", "dnp3.al.fragment.multipletails",
          FT_BOOLEAN, BASE_NONE, NULL, 0x0,
          "Several tails were found when defragmenting the packet", HFILL }
    },

    { &hf_dnp3_fragment_too_long_fragment,
      { "Fragment too long", "dnp3.al.fragment.toolongfragment",
          FT_BOOLEAN, BASE_NONE, NULL, 0x0,
          "Fragment contained data past end of packet", HFILL }
    },

    { &hf_dnp3_fragment_error,
      { "Defragmentation error", "dnp3.al.fragment.error",
        FT_FRAMENUM, BASE_NONE, NULL, 0x0,
        "Defragmentation error due to illegal fragments", HFILL }
    },

    { &hf_dnp3_fragment_count,
      { "Fragment count", "dnp3.al.fragment.count",
        FT_UINT32, BASE_DEC, NULL, 0x0,
        NULL, HFILL }
    },

    { &hf_dnp3_fragment_reassembled_in,
      { "Reassembled PDU In Frame", "dnp3.al.fragment.reassembled_in",
        FT_FRAMENUM, BASE_NONE, NULL, 0x0,
        "This PDU is reassembled in this frame", HFILL }
    },

    { &hf_dnp3_fragment_reassembled_length,
      { "Reassembled DNP length", "dnp3.al.fragment.reassembled.length",
        FT_UINT32, BASE_DEC, NULL, 0x0,
        "The total length of the reassembled payload", HFILL }
    },
    /* Generated from convert_proto_tree_add_text.pl */
    { &hf_dnp3_al_point_index, { "Point Index", "dnp3.al.point_index", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
    { &hf_dnp3_al_da_value, { "Value", "dnp3.al.da.value", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
    { &hf_dnp3_al_count, { "Count", "dnp3.al.count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
    { &hf_dnp3_al_on_time, { "On Time", "dnp3.al.on_time", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
    { &hf_dnp3_al_off_time, { "Off Time", "dnp3.al.off_time", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
    { &hf_dnp3_al_time_delay, { "Time Delay", "dnp3.al.time_delay", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_milliseconds, 0x0, NULL, HFILL }},
    { &hf_dnp3_al_file_string_offset, { "File String Offset", "dnp3.al.file_string_offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
    { &hf_dnp3_al_file_string_length, { "File String Length", "dnp3.al.file_string_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
    { &hf_dnp3_al_file_name, { "File Name", "dnp3.al.file_name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
    { &hf_dnp3_al_octet_string, { "Octet String", "dnp3.al.octet_string", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
    { &hf_dnp3_unknown_data_chunk, { "Unknown Data Chunk", "dnp3.al.unknown_data_chunk", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},

  };

/* Setup protocol subtree array */
  static gint *ett[] = {
    &ett_dnp3,
    &ett_dnp3_dl,
    &ett_dnp3_dl_ctl,
    &ett_dnp3_tr_ctl,
    &ett_dnp3_dl_data,
    &ett_dnp3_dl_chunk,
    &ett_dnp3_al,
    &ett_dnp3_al_ctl,
    &ett_dnp3_al_obj_point_tcc,
    &ett_dnp3_al_iin,
    &ett_dnp3_al_obj,
    &ett_dnp3_al_obj_qualifier,
    &ett_dnp3_al_obj_range,
    &ett_dnp3_al_objdet,
    &ett_dnp3_al_obj_quality,
    &ett_dnp3_al_obj_point,
    &ett_dnp3_al_obj_point_perms,
    &ett_dnp3_fragment,
    &ett_dnp3_fragments
  };
  static ei_register_info ei[] = {
     { &ei_dnp_num_items_neg, { "dnp3.num_items_neg", PI_MALFORMED, PI_ERROR, "Negative number of items", EXPFILL }},
     { &ei_dnp_invalid_length, { "dnp3.invalid_length", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }},
     { &ei_dnp_iin_abnormal, { "dnp3.iin_abnormal", PI_PROTOCOL, PI_WARN, "IIN Abnormality", EXPFILL }},
     { &ei_dnp3_data_hdr_crc_incorrect, { "dnp3.hdr.CRC.incorrect", PI_CHECKSUM, PI_WARN, "Data Link Header Checksum incorrect", EXPFILL }},
     { &ei_dnp3_data_chunk_crc_incorrect, { "dnp3.data_chunk.CRC.incorrect", PI_CHECKSUM, PI_WARN, "Data Chunk Checksum incorrect", EXPFILL }},
     { &ei_dnp3_unknown_object, { "dnp3.unknown_object", PI_PROTOCOL, PI_WARN, "Unknown Object\\Variation", EXPFILL }},
     { &ei_dnp3_unknown_group0_variation, { "dnp3.unknown_group0_variation", PI_PROTOCOL, PI_WARN, "Unknown Group 0 Variation", EXPFILL }},
     { &ei_dnp3_num_items_invalid, { "dnp3.num_items_invalid", PI_MALFORMED, PI_ERROR, "Number of items is invalid for normally empty object.  Potentially malicious packet", EXPFILL }},
      /* Generated from convert_proto_tree_add_text.pl */
#if 0
      { &ei_dnp3_buffering_user_data_until_final_frame_is_received, { "dnp3.buffering_user_data_until_final_frame_is_received", PI_PROTOCOL, PI_WARN, "Buffering User Data Until Final Frame is Received..", EXPFILL }},
#endif
    };

  module_t *dnp3_module;
  expert_module_t* expert_dnp3;

  reassembly_table_register(&al_reassembly_table,
                        &addresses_reassembly_table_functions);

/* Register the protocol name and description */
  proto_dnp3 = proto_register_protocol("Distributed Network Protocol 3.0", "DNP 3.0", "dnp3");

/* Register the dissector so it may be used as a User DLT payload protocol */
  dnp3_tcp_handle = register_dissector("dnp3.tcp", dissect_dnp3_tcp, proto_dnp3);
  dnp3_udp_handle = register_dissector("dnp3.udp", dissect_dnp3_udp, proto_dnp3);

/* Required function calls to register the header fields and subtrees used */
  proto_register_field_array(proto_dnp3, hf, array_length(hf));
  proto_register_subtree_array(ett, array_length(ett));
  expert_dnp3 = expert_register_protocol(proto_dnp3);
  expert_register_field_array(expert_dnp3, ei, array_length(ei));

  dnp3_module = prefs_register_protocol(proto_dnp3, NULL);
  prefs_register_obsolete_preference(dnp3_module, "heuristics");
  prefs_register_bool_preference(dnp3_module, "desegment",
    "Reassemble DNP3 messages spanning multiple TCP segments",
    "Whether the DNP3 dissector should reassemble messages spanning multiple TCP segments."
    " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
    &dnp3_desegment);
}


calculateCRCtvb(tvbuff_t *tvb, guint offset, guint len) {
  guint16 crc = crc16_0x3D65_tvb_offset_seed(tvb, offset, len, 0);
  return ~crc;
}


dnp3_al_obj_procprefix(tvbuff_t *tvb, int offset, guint8 al_objq_prefix, guint32 *al_ptaddr, proto_tree *item_tree)
{
  int         prefixbytes = 0;
  proto_item *prefix_item;

  switch (al_objq_prefix)
  {
    case AL_OBJQL_PREFIX_NI:        /* No Prefix */
      prefixbytes = 0;
      prefix_item = proto_tree_add_uint(item_tree, hf_dnp3_al_point_index, tvb, offset, 0, *al_ptaddr);
      proto_item_set_generated(prefix_item);
      break;
    case AL_OBJQL_PREFIX_1O:
      *al_ptaddr = tvb_get_guint8(tvb, offset);
      proto_tree_add_item(item_tree, hf_dnp3_al_index8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
      prefixbytes = 1;
      break;
    case AL_OBJQL_PREFIX_2O:
      *al_ptaddr = tvb_get_letohs(tvb, offset);
      proto_tree_add_item(item_tree, hf_dnp3_al_index16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
      prefixbytes = 2;
      break;
    case AL_OBJQL_PREFIX_4O:
      *al_ptaddr = tvb_get_letohl(tvb, offset);
      proto_tree_add_item(item_tree, hf_dnp3_al_index32, tvb, offset, 4, ENC_LITTLE_ENDIAN);
      prefixbytes = 4;
      break;
    case AL_OBJQL_PREFIX_1OS:
      *al_ptaddr = tvb_get_guint8(tvb, offset);
      proto_tree_add_item(item_tree, hf_dnp3_al_size8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
      prefixbytes = 1;
      break;
    case AL_OBJQL_PREFIX_2OS:
      *al_ptaddr = tvb_get_letohs(tvb, offset);
      proto_tree_add_item(item_tree, hf_dnp3_al_size16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
      prefixbytes = 2;
      break;
    case AL_OBJQL_PREFIX_4OS:
      *al_ptaddr = tvb_get_letohl(tvb, offset);
      proto_tree_add_item(item_tree, hf_dnp3_al_size32, tvb, offset, 4, ENC_LITTLE_ENDIAN);
      prefixbytes = 4;
      break;
  }
  return prefixbytes;
}


get_dnp3_message_len(packet_info *pinfo _U_, tvbuff_t *tvb,
                     int offset, void *data _U_)
{
  guint16 message_len;  /* need 16 bits as total can exceed 255 */
  guint16 data_crc;     /* No. of user data CRC bytes */

  message_len = tvb_get_guint8(tvb, offset + 2);

  /* Add in 2 bytes for header start octets,
            1 byte for len itself,
            2 bytes for header CRC
            data CRC bytes (2 bytes per 16 bytes of data
  */

  data_crc = (guint16)(ceil((message_len - 5) / 16.0)) * 2;
  message_len += 2 + 1 + 2 + data_crc;
  return message_len;
}


dnp3_udp_check_header(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_, void *data _U_)
{
    return check_dnp3_header(tvb, FALSE);
}