mono_stack_walk (MonoStackWalk func, gpointer user_data)
{
	stack_walk (func, TRUE, user_data);
}

struct _MonoDllMap {
	char *dll;
	char *target;
	char *func;
	char *target_func;
	MonoDllMap *next;
}

static MonoStackWalkImpl stack_walk = default_stack_walk;


mono_dllmap_lookup (MonoImage *assembly, const char *dll, const char* func, const char **rdll, const char **rfunc)
{
	int res;
	if (assembly && assembly->dll_map) {
		res = mono_dllmap_lookup_list (assembly->dll_map, dll, func, rdll, rfunc);
		if (res)
			return res;
	}
	return mono_dllmap_lookup_list (global_dll_map, dll, func, rdll, rfunc);
}

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.

struct _MonoDllMap {
	char *dll;
	char *target;
	char *func;
	char *target_func;
	MonoDllMap *next;
}

static MonoDllMap *global_dll_map;


mono_loader_set_error_bad_image (char *msg)
{
	MonoLoaderError *error;

	if (mono_loader_get_last_error ())
		return;

	error = g_new0 (MonoLoaderError, 1);
	error->exception_type = MONO_EXCEPTION_BAD_IMAGE;
	error->msg = msg;

	set_loader_error (error);
}

struct _MonoDllMap {
	char *dll;
	char *target;
	char *func;
	char *target_func;
	MonoDllMap *next;
}


mono_install_stack_walk (MonoStackWalkImpl func)
{
	stack_walk = func;
}


mono_method_get_last_managed (void)
{
	MonoMethod *m = NULL;
	stack_walk (last_managed, FALSE, &m);
	return m;
}

static void dllmap_cleanup (void);

static MonoStackWalkImpl stack_walk = default_stack_walk;

static gboolean loader_lock_track_ownership = FALSE;


mono_method_get_flags (MonoMethod *method, guint32 *iflags)
{
	if (iflags)
		*iflags = method->iflags;
	return method->flags;
}

static guint32 inflated_signatures_size;

static guint32 memberref_sig_cache_size;

guint32 loader_error_thread_id;

guint32 loader_lock_nest_id;


cache_memberref_sig (MonoImage *image, guint32 sig_idx, gpointer sig)
{
	gpointer prev_sig;

	mono_loader_lock ();
	prev_sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (sig_idx));
	if (prev_sig) {
		/* Somebody got in before us */
		sig = prev_sig;
	}
	else {
		g_hash_table_insert (image->memberref_signatures, GUINT_TO_POINTER (sig_idx), sig);
		/* An approximation based on glib 2.18 */
		memberref_sig_cache_size += sizeof (gpointer) * 4;
	}

	mono_loader_unlock ();

	return sig;
}


method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typespec_context,
		       gboolean *used_context)
{
	MonoClass *klass = NULL;
	MonoMethod *method = NULL;
	MonoTableInfo *tables = image->tables;
	guint32 cols[6];
	guint32 nindex, class, sig_idx;
	const char *mname;
	MonoMethodSignature *sig;
	const char *ptr;

	mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
	nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
	class = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
	/*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
		mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/

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

	/*
	 * Whether we actually used the `typespec_context' or not.
	 * This is used to tell our caller whether or not it's safe to insert the returned
	 * method into a cache.
	 */
	if (used_context)
		*used_context = class == MONO_MEMBERREF_PARENT_TYPESPEC;

	switch (class) {
	case MONO_MEMBERREF_PARENT_TYPEREF:
		klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
		if (!klass) {
			char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_REF | nindex);
			g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
			mono_loader_set_error_type_load (name, image->assembly_name);
			g_free (name);
			return NULL;
		}
		break;
	case MONO_MEMBERREF_PARENT_TYPESPEC:
		/*
		 * Parse the TYPESPEC in the parent's context.
		 */
		klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, typespec_context);
		if (!klass) {
			char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_SPEC | nindex);
			g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
			mono_loader_set_error_type_load (name, image->assembly_name);
			g_free (name);
			return NULL;
		}
		break;
	case MONO_MEMBERREF_PARENT_TYPEDEF:
		klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
		if (!klass) {
			char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_DEF | nindex);
			g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
			mono_loader_set_error_type_load (name, image->assembly_name);
			g_free (name);
			return NULL;
		}
		break;
	case MONO_MEMBERREF_PARENT_METHODDEF:
		return mono_get_method (image, MONO_TOKEN_METHOD_DEF | nindex, NULL);

	default:
		{
			/* This message leaks */
			char *message = g_strdup_printf ("Memberref parent unknown: class: %d, index %d", class, nindex);
			mono_loader_set_error_method_load ("", message);
			return NULL;
		}

	}
	g_assert (klass);
	mono_class_init (klass);

	sig_idx = cols [MONO_MEMBERREF_SIGNATURE];

	if (!mono_verifier_verify_memberref_signature (image, sig_idx, NULL)) {
		mono_loader_set_error_method_load (klass->name, mname);
		return NULL;
	}

	ptr = mono_metadata_blob_heap (image, sig_idx);
	mono_metadata_decode_blob_size (ptr, &ptr);

	sig = find_cached_memberref_sig (image, sig_idx);
	if (!sig) {
		sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
		if (sig == NULL)
			return NULL;

		sig = cache_memberref_sig (image, sig_idx, sig);
	}

	switch (class) {
	case MONO_MEMBERREF_PARENT_TYPEREF:
	case MONO_MEMBERREF_PARENT_TYPEDEF:
		method = find_method (klass, NULL, mname, sig, klass);
		break;

	case MONO_MEMBERREF_PARENT_TYPESPEC: {
		MonoType *type;

		type = &klass->byval_arg;

		if (type->type != MONO_TYPE_ARRAY && type->type != MONO_TYPE_SZARRAY) {
			MonoClass *in_class = klass->generic_class ? klass->generic_class->container_class : klass;
			method = find_method (in_class, NULL, mname, sig, klass);
			break;
		}

		/* we're an array and we created these methods already in klass in mono_class_init () */
		method = mono_method_search_in_array_class (klass, mname, sig);
		break;
	}
	default:
		g_error ("Memberref parent unknown: class: %d, index %d", class, nindex);
		g_assert_not_reached ();
	}

	if (!method) {
		char *msig = mono_signature_get_desc (sig, FALSE);
		char * class_name = mono_type_get_name (&klass->byval_arg);
		GString *s = g_string_new (mname);
		if (sig->generic_param_count)
			g_string_append_printf (s, "<[%d]>", sig->generic_param_count);
		g_string_append_printf (s, "(%s)", msig);
		g_free (msig);
		msig = g_string_free (s, FALSE);

		g_warning (
			"Missing method %s::%s in assembly %s, referenced in assembly %s",
			class_name, msig, klass->image->name, image->name);
		mono_loader_set_error_method_load (class_name, mname);
		g_free (msig);
		g_free (class_name);
	}

	return method;
}

static gboolean loader_lock_inited;

static guint32 inflated_signatures_size;

static guint32 memberref_sig_cache_size;

guint32 loader_error_thread_id;

guint32 loader_lock_nest_id;

struct _MonoDllMap {
	char *dll;
	char *target;
	char *func;
	char *target_func;
	MonoDllMap *next;
}

static gboolean loader_lock_track_ownership = FALSE;


mono_method_signature_checked (MonoMethod *m, MonoError *error)
{
	int idx;
	int size;
	MonoImage* img;
	const char *sig;
	gboolean can_cache_signature;
	MonoGenericContainer *container;
	MonoMethodSignature *signature = NULL;
	guint32 sig_offset;

	/* We need memory barriers below because of the double-checked locking pattern */

	mono_error_init (error);

	if (m->signature)
		return m->signature;

	mono_loader_lock ();

	if (m->signature) {
		mono_loader_unlock ();
		return m->signature;
	}

	if (m->is_inflated) {
		MonoMethodInflated *imethod = (MonoMethodInflated *) m;
		/* the lock is recursive */
		signature = mono_method_signature (imethod->declaring);
		signature = inflate_generic_signature_checked (imethod->declaring->klass->image, signature, mono_method_get_context (m), error);
		if (!mono_error_ok (error)) {
			mono_loader_unlock ();
			return NULL;
		}

		inflated_signatures_size += mono_metadata_signature_size (signature);

		mono_memory_barrier ();
		m->signature = signature;
		mono_loader_unlock ();
		return m->signature;
	}

	g_assert (mono_metadata_token_table (m->token) == MONO_TABLE_METHOD);
	idx = mono_metadata_token_index (m->token);
	img = m->klass->image;

	sig = mono_metadata_blob_heap (img, sig_offset = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_SIGNATURE));

	g_assert (!m->klass->generic_class);
	container = mono_method_get_generic_container (m);
	if (!container)
		container = m->klass->generic_container;

	/* Generic signatures depend on the container so they cannot be cached */
	/* icall/pinvoke signatures cannot be cached cause we modify them below */
	can_cache_signature = !(m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !(m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && !container;

	/* If the method has parameter attributes, that can modify the signature */
	if (mono_metadata_method_has_param_attrs (img, idx))
		can_cache_signature = FALSE;

	if (can_cache_signature)
		signature = g_hash_table_lookup (img->method_signatures, sig);

	if (!signature) {
		const char *sig_body;
		/*TODO we should cache the failure result somewhere*/
		if (!mono_verifier_verify_method_signature (img, sig_offset, error)) {
			mono_loader_unlock ();
			return NULL;
		}

		size = mono_metadata_decode_blob_size (sig, &sig_body);

		signature = mono_metadata_parse_method_signature_full (img, container, idx, sig_body, NULL);
		if (!signature) {
			mono_loader_unlock ();
			mono_error_set_method_load (error, m->klass, m->name, "");
			return NULL;
		}

		if (can_cache_signature)
			g_hash_table_insert (img->method_signatures, (gpointer)sig, signature);
	}

	/* Verify metadata consistency */
	if (signature->generic_param_count) {
		if (!container || !container->is_method) {
			mono_loader_unlock ();
			mono_error_set_method_load (error, m->klass, m->name, "Signature claims method has generic parameters, but generic_params table says it doesn't for method 0x%08x from image %s", idx, img->name);
			return NULL;
		}
		if (container->type_argc != signature->generic_param_count) {
			mono_loader_unlock ();
			mono_error_set_method_load (error, m->klass, m->name, "Inconsistent generic parameter count.  Signature says %d, generic_params table says %d for method 0x%08x from image %s", signature->generic_param_count, container->type_argc, idx, img->name);
			return NULL;
		}
	} else if (container && container->is_method && container->type_argc) {
		mono_loader_unlock ();
		mono_error_set_method_load (error, m->klass, m->name, "generic_params table claims method has generic parameters, but signature says it doesn't for method 0x%08x from image %s", idx, img->name);
		return NULL;
	}
	if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
		signature->pinvoke = 1;
	else if (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
		MonoCallConvention conv = 0;
		MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)m;
		signature->pinvoke = 1;

		switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CALL_CONV_MASK) {
		case 0: /* no call conv, so using default */
		case PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI:
			conv = MONO_CALL_DEFAULT;
			break;
		case PINVOKE_ATTRIBUTE_CALL_CONV_CDECL:
			conv = MONO_CALL_C;
			break;
		case PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL:
			conv = MONO_CALL_STDCALL;
			break;
		case PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL:
			conv = MONO_CALL_THISCALL;
			break;
		case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL:
			conv = MONO_CALL_FASTCALL;
			break;
		case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC:
		case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST:
		default:
			mono_loader_unlock ();
			mono_error_set_method_load (error, m->klass, m->name, "unsupported calling convention : 0x%04x for method 0x%08x from image %s", piinfo->piflags, idx, img->name);
			return NULL;
		}
		signature->call_convention = conv;
	}

	mono_memory_barrier ();
	m->signature = signature;

	mono_loader_unlock ();
	return m->signature;
}


last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
{
	MonoMethod **dest = data;
	*dest = m;
	/*g_print ("In %s::%s [%d] [%d]\n", m->klass->name, m->name, no, ilo);*/

	return managed;
}

static gboolean loader_lock_inited;

static gboolean loader_lock_track_ownership = FALSE;


mono_loader_set_error_field_load (MonoClass *klass, const char *member_name)
{
	MonoLoaderError *error;

	/* FIXME: Store the signature as well */
	if (mono_loader_get_last_error ())
		return;

	error = g_new0 (MonoLoaderError, 1);
	error->exception_type = MONO_EXCEPTION_MISSING_FIELD;
	error->klass = klass;
	error->member_name = member_name;

	set_loader_error (error);
}


inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context)
{
	MonoMethodHeader *res;
	int i;
	res = g_malloc0 (MONO_SIZEOF_METHOD_HEADER + sizeof (gpointer) * header->num_locals);
	res->code = header->code;
	res->code_size = header->code_size;
	res->max_stack = header->max_stack;
	res->num_clauses = header->num_clauses;
	res->init_locals = header->init_locals;
	res->num_locals = header->num_locals;
	res->clauses = header->clauses;
	for (i = 0; i < header->num_locals; ++i)
		res->locals [i] = mono_class_inflate_generic_type (header->locals [i], context);
	if (res->num_clauses) {
		res->clauses = g_memdup (header->clauses, sizeof (MonoExceptionClause) * res->num_clauses);
		for (i = 0; i < header->num_clauses; ++i) {
			MonoExceptionClause *clause = &res->clauses [i];
			if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
				continue;
			clause->data.catch_class = mono_class_inflate_generic_class (clause->data.catch_class, context);
		}
	}
	return res;
}

MonoDefaults mono_defaults;

static CRITICAL_SECTION loader_mutex;

static gboolean loader_lock_inited;

static void dllmap_cleanup (void);

static GHashTable *global_module_map;

static guint32 inflated_signatures_size;

guint32 loader_error_thread_id;

static MonoDllMap *global_dll_map;

static guint32 memberref_sig_cache_size;

guint32 loader_lock_nest_id;

static gboolean loader_lock_track_ownership = FALSE;

static MonoStackWalkImpl stack_walk = default_stack_walk;

struct _MonoDllMap {
	char *dll;
	char *target;
	char *func;
	char *target_func;
	MonoDllMap *next;
}


mono_method_get_class (MonoMethod *method)
{
	return method->klass;
}


mono_method_get_wrapper_data (MonoMethod *method, guint32 id)
{
	void **data;
	g_assert (method != NULL);
	g_assert (method->wrapper_type != MONO_WRAPPER_NONE);

	if (method->is_inflated)
		method = ((MonoMethodInflated *) method)->declaring;
	data = ((MonoMethodWrapper *)method)->method_data;
	g_assert (data != NULL);
	g_assert (id <= GPOINTER_TO_UINT (*data));
	return data [id];
}

static guint32 inflated_signatures_size;

static guint32 memberref_sig_cache_size;

guint32 loader_error_thread_id;

guint32 loader_lock_nest_id;

static void dllmap_cleanup (void);


find_cached_memberref_sig (MonoImage *image, guint32 sig_idx)
{
	gpointer res;

	mono_loader_lock ();
	res = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (sig_idx));
	mono_loader_unlock ();

	return res;
}


find_method (MonoClass *in_class, MonoClass *ic, const char* name, MonoMethodSignature *sig, MonoClass *from_class)
{
	int i;
	char *qname, *fqname, *class_name;
	gboolean is_interface;
	MonoMethod *result = NULL;

	is_interface = MONO_CLASS_IS_INTERFACE (in_class);

	if (ic) {
		class_name = mono_type_get_name_full (&ic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);

		qname = g_strconcat (class_name, ".", name, NULL);
		if (ic->name_space && ic->name_space [0])
			fqname = g_strconcat (ic->name_space, ".", class_name, ".", name, NULL);
		else
			fqname = NULL;
	} else
		class_name = qname = fqname = NULL;

	while (in_class) {
		g_assert (from_class);
		result = find_method_in_class (in_class, name, qname, fqname, sig, from_class);
		if (result)
			goto out;

		if (name [0] == '.' && (!strcmp (name, ".ctor") || !strcmp (name, ".cctor")))
			break;

		g_assert (from_class->interface_offsets_count == in_class->interface_offsets_count);
		for (i = 0; i < in_class->interface_offsets_count; i++) {
			MonoClass *in_ic = in_class->interfaces_packed [i];
			MonoClass *from_ic = from_class->interfaces_packed [i];
			char *ic_qname, *ic_fqname, *ic_class_name;

			ic_class_name = mono_type_get_name_full (&in_ic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
			ic_qname = g_strconcat (ic_class_name, ".", name, NULL);
			if (in_ic->name_space && in_ic->name_space [0])
				ic_fqname = g_strconcat (in_ic->name_space, ".", ic_class_name, ".", name, NULL);
			else
				ic_fqname = NULL;

			result = find_method_in_class (in_ic, ic ? name : NULL, ic_qname, ic_fqname, sig, from_ic);
			g_free (ic_class_name);
			g_free (ic_fqname);
			g_free (ic_qname);
			if (result)
				goto out;
		}

		in_class = in_class->parent;
		from_class = from_class->parent;
	}
	g_assert (!in_class == !from_class);

	if (is_interface)
		result = find_method_in_class (mono_defaults.object_class, name, qname, fqname, sig, mono_defaults.object_class);

 out:
	g_free (class_name);
	g_free (fqname);
	g_free (qname);
	return result;
}

MonoDefaults mono_defaults;

static gboolean loader_lock_inited;

struct _MonoDllMap {
	char *dll;
	char *target;
	char *func;
	char *target_func;
	MonoDllMap *next;
}

static gboolean loader_lock_track_ownership = FALSE;


mono_get_method_full (MonoImage *image, guint32 token, MonoClass *klass,
		      MonoGenericContext *context)
{
	MonoMethod *result;
	gboolean used_context = FALSE;

	/* We do everything inside the lock to prevent creation races */

	mono_image_lock (image);

	if (mono_metadata_token_table (token) == MONO_TABLE_METHOD) {
		if (!image->method_cache)
			image->method_cache = g_hash_table_new (NULL, NULL);
		result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (mono_metadata_token_index (token)));
	} else {
		if (!image->methodref_cache)
			image->methodref_cache = g_hash_table_new (NULL, NULL);
		result = g_hash_table_lookup (image->methodref_cache, GINT_TO_POINTER (token));
	}
	mono_image_unlock (image);

	if (result)
		return result;

	result = mono_get_method_from_token (image, token, klass, context, &used_context);
	if (!result)
		return NULL;

	mono_image_lock (image);
	if (!used_context && !result->is_inflated) {
		MonoMethod *result2;
		if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
			result2 = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (mono_metadata_token_index (token)));
		else
			result2 = g_hash_table_lookup (image->methodref_cache, GINT_TO_POINTER (token));

		if (result2) {
			mono_image_unlock (image);
			return result2;
		}

		if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
			g_hash_table_insert (image->method_cache, GINT_TO_POINTER (mono_metadata_token_index (token)), result);
		else
			g_hash_table_insert (image->methodref_cache, GINT_TO_POINTER (token), result);
	}

	mono_image_unlock (image);

	return result;
}

static gboolean loader_lock_inited;

static guint32 inflated_signatures_size;

static guint32 memberref_sig_cache_size;

guint32 loader_error_thread_id;

guint32 loader_lock_nest_id;

static gboolean loader_lock_track_ownership = FALSE;


mono_loader_lock_track_ownership (gboolean track)
{
	loader_lock_track_ownership = track;
}


mono_loader_lock (void)
{
	mono_locks_acquire (&loader_mutex, LoaderLock);
	if (G_UNLIKELY (loader_lock_track_ownership)) {
		TlsSetValue (loader_lock_nest_id, GUINT_TO_POINTER (GPOINTER_TO_UINT (TlsGetValue (loader_lock_nest_id)) + 1));
	}
}

static CRITICAL_SECTION loader_mutex;

guint32 loader_lock_nest_id;

static void dllmap_cleanup (void);

static gboolean loader_lock_track_ownership = FALSE;


mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constrained_class,
			     MonoGenericContext *context, MonoMethod **cil_method)
{
	MonoMethod *method, *result;
	MonoClass *ic = NULL;
	MonoGenericContext *method_context = NULL;
	MonoMethodSignature *sig, *original_sig;

	mono_loader_lock ();

	*cil_method = mono_get_method_from_token (image, token, NULL, context, NULL);
	if (!*cil_method) {
		mono_loader_unlock ();
		return NULL;
	}

	mono_class_init (constrained_class);
	method = *cil_method;
	original_sig = sig = mono_method_signature (method);
	if (sig == NULL) {
		mono_loader_unlock ();
		return NULL;
	}

	if (method->is_inflated && sig->generic_param_count) {
		MonoMethodInflated *imethod = (MonoMethodInflated *) method;
		sig = mono_method_signature (imethod->declaring); /*We assume that if the inflated method signature is valid, the declaring method is too*/
		method_context = mono_method_get_context (method);

		original_sig = sig;
		/*
		 * We must inflate the signature with the class instantiation to work on
		 * cases where a class inherit from a generic type and the override replaces
		 * any type argument which a concrete type. See #325283.
		 */
		if (method_context->class_inst) {
			MonoError error;
			MonoGenericContext ctx;
			ctx.method_inst = NULL;
			ctx.class_inst = method_context->class_inst;
			/*Fixme, property propagate this error*/
			sig = inflate_generic_signature_checked (method->klass->image, sig, &ctx, &error);
			if (!mono_error_ok (&error)) {
				mono_loader_unlock ();
				mono_error_cleanup (&error);
				return NULL;
			}
		}
	}

	if ((constrained_class != method->klass) && (MONO_CLASS_IS_INTERFACE (method->klass)))
		ic = method->klass;

	result = find_method (constrained_class, ic, method->name, sig, constrained_class);
	if (sig != original_sig)
		mono_metadata_free_inflated_signature (sig);

	if (!result) {
		g_warning ("Missing method %s.%s.%s in assembly %s token %x", method->klass->name_space,
			   method->klass->name, method->name, image->name, token);
		mono_loader_unlock ();
		return NULL;
	}

	if (method_context)
		result = mono_class_inflate_generic_method (result, method_context);

	mono_loader_unlock ();
	return result;
}


inflate_generic_signature_checked (MonoImage *image, MonoMethodSignature *sig, MonoGenericContext *context, MonoError *error)
{
	MonoMethodSignature *res;
	gboolean is_open;
	int i;

	mono_error_init (error);
	if (!context)
		return sig;

	res = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((gint32)sig->param_count) * sizeof (MonoType*));
	res->param_count = sig->param_count;
	res->sentinelpos = -1;
	res->ret = mono_class_inflate_generic_type_checked (sig->ret, context, error);
	if (!mono_error_ok (error))
		goto fail;
	is_open = mono_class_is_open_constructed_type (res->ret);
	for (i = 0; i < sig->param_count; ++i) {
		res->params [i] = mono_class_inflate_generic_type_checked (sig->params [i], context, error);
		if (!mono_error_ok (error))
			goto fail;

		if (!is_open)
			is_open = mono_class_is_open_constructed_type (res->params [i]);
	}
	res->hasthis = sig->hasthis;
	res->explicit_this = sig->explicit_this;
	res->call_convention = sig->call_convention;
	res->pinvoke = sig->pinvoke;
	res->generic_param_count = sig->generic_param_count;
	res->sentinelpos = sig->sentinelpos;
	res->has_type_parameters = is_open;
	res->is_inflated = 1;
	return res;

fail:
	if (res->ret)
		mono_metadata_free_type (res->ret);
	for (i = 0; i < sig->param_count; ++i) {
		if (res->params [i])
			mono_metadata_free_type (res->params [i]);
	}
	g_free (res);
	return NULL;
}


default_stack_walk (MonoStackWalk func, gboolean do_il_offset, gpointer user_data) {
	g_error ("stack walk not installed");
}

static gboolean loader_lock_inited;

struct _MonoDllMap {
	char *dll;
	char *target;
	char *func;
	char *target_func;
	MonoDllMap *next;
}

static MonoStackWalkImpl stack_walk = default_stack_walk;

static gboolean loader_lock_track_ownership = FALSE;


mono_stack_walk_no_il (MonoStackWalk func, gpointer user_data)
{
	stack_walk (func, FALSE, user_data);
}

struct _MonoDllMap {
	char *dll;
	char *target;
	char *func;
	char *target_func;
	MonoDllMap *next;
}

static MonoStackWalkImpl stack_walk = default_stack_walk;

static gboolean loader_lock_track_ownership = FALSE;


mono_method_get_token (MonoMethod *method)
{
	return method->token;
}


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;
}

static guint32 inflated_signatures_size;

static guint32 memberref_sig_cache_size;

guint32 loader_error_thread_id;

guint32 loader_lock_nest_id;

struct _MonoDllMap {
	char *dll;
	char *target;
	char *func;
	char *target_func;
	MonoDllMap *next;
}


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


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

static gboolean loader_lock_inited;

static void dllmap_cleanup (void);


mono_loader_cleanup (void)
{
	dllmap_cleanup ();

	TlsFree (loader_error_thread_id);
	TlsFree (loader_lock_nest_id);

	DeleteCriticalSection (&loader_mutex);
	loader_lock_inited = FALSE;
}

static CRITICAL_SECTION loader_mutex;

static gboolean loader_lock_inited;

guint32 loader_error_thread_id;

guint32 loader_lock_nest_id;

static void dllmap_cleanup (void);

static gboolean loader_lock_track_ownership = 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);
}

static gboolean loader_lock_inited;

struct _MonoDllMap {
	char *dll;
	char *target;
	char *func;
	char *target_func;
	MonoDllMap *next;
}

static gboolean loader_lock_track_ownership = FALSE;


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;
}

static gboolean loader_lock_track_ownership = FALSE;


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

struct timerqueue_node {
	struct rb_node node;
	ktime_t expires;
}

struct timerqueue_head {
	struct rb_root_cached rb_root;
}

extern bool timerqueue_add(struct timerqueue_head *head,
			   struct timerqueue_node *node);

extern bool timerqueue_del(struct timerqueue_head *head,
			   struct timerqueue_node *node);

extern struct timerqueue_node *timerqueue_iterate_next(
						struct timerqueue_node *node);


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;
}

/* No explicit global definitions found. */


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.

#define TCP_PORT_DNP    20000

#define UDP_PORT_DNP    20000

#define TCP_PORT_DNP_TLS    19999

#define AL_FUNC_FRZCLR     0x09    /* 09  - Freeze and Clear */

#define AL_FUNC_FRZCLRNACK 0x0A    /* 10  - Freeze and Clear No ACK */

#define AL_OBJQL_RANGE_SSI8    0x00    /* 00 8-bit Start and Stop Indices in Range Field */

#define AL_OBJQL_RANGE_SSI16   0x01    /* 01 16-bit Start and Stop Indices in Range Field */

#define AL_OBJQL_RANGE_SSI32   0x02    /* 02 32-bit Start and Stop Indices in Range Field */

#define AL_OBJ_DA_GRP           0x0000   /* 00 00 Device Attributes Group and null variation */

#define AL_OBJ_DA_USR_ATTR      0x00D3   /* 00 211 Device Attributes - Identifier of support for user-specific attributes */

#define AL_OBJ_DA_MSTR_DSP      0x00D4   /* 00 212 Device Attributes - Number of master-defined data set prototypes  */

#define AL_OBJ_DA_OS_DSP        0x00D5   /* 00 213 Device Attributes - Number of outstation-defined data set prototypes */

#define AL_OBJ_DA_MSTR_DS       0x00D6   /* 00 214 Device Attributes - Number of master-defined data sets  */

#define AL_OBJ_DA_OS_DS         0x00D7   /* 00 215 Device Attributes - Number of outstation-defined data sets  */

#define AL_OBJ_DA_AO_EVT        0x00DB   /* 00 219 Device Attributes - Support for analog output events  */

#define AL_OBJ_DA_BO_EVT        0x00DE   /* 00 222 Device Attributes - Support for binary output events  */

#define AL_OBJ_DA_FCTR_EVT      0x00E1   /* 00 225 Device Attributes - Support for frozen counter events */

#define AL_OBJ_DA_FCTR          0x00E2   /* 00 226 Device Attributes - Support for frozen counters       */

#define AL_OBJ_DA_CTR_EVT       0x00E3   /* 00 227 Device Attributes - Support for counter events        */

#define AL_OBJ_DA_AIF           0x00E6   /* 00 230 Device Attributes - Support for frozen analog inputs  */

#define AL_OBJ_DA_AI_EVT        0x00E7   /* 00 231 Device Attributes - Support for analog input events   */

#define AL_OBJ_DA_2BI_EVT       0x00EA   /* 00 234 Device Attributes - Support for Double-Bit BI Events  */

#define AL_OBJ_DA_BI_EVT        0x00ED   /* 00 237 Device Attributes - Support for Binary Input Events   */

#define AL_OBJ_DA_CONF          0x00F9   /* 00 249 Device Attributes - DNP Subset and Conformance        */

#define AL_OBJ_DA_PROD          0x00FA   /* 00 250 Device Attributes - Device Product Name and Model     */

#define AL_OBJCTLC_CODE    0x0F    /* Bit-Mask xxxx1111 for Control Code 'Code' */


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, ")");
}

#define AL_FUNC_COLDRST    0x0D    /* 13  - Cold Restart */

#define AL_FUNC_WARMRST    0x0E    /* 14  - Warm Restart */

#define AL_IIN_DOL         0x2000   /* Bit 5 - Outputs in Local Mode */

#define AL_IIN_RST         0x8000   /* Bit 7 - Device Restart */

#define AL_IIN_FCNI        0x0001   /* Bit 0 - Function code not implemented */

#define AL_IIN_PIOOR       0x0004   /* Bit 2 - Parameters Invalid or Out of Range */

#define AL_OBJQ_RANGE          0x0F    /* xxxx1111 Masks Range from Qualifier */

#define AL_OBJQL_RANGE_SSI8    0x00    /* 00 8-bit Start and Stop Indices in Range Field */

#define AL_OBJQL_RANGE_SSI16   0x01    /* 01 16-bit Start and Stop Indices in Range Field */

#define AL_OBJQL_RANGE_SSI32   0x02    /* 02 32-bit Start and Stop Indices in Range Field */

#define AL_OBJQL_RANGE_AA8     0x03    /* 03 8-bit Absolute Address in Range Field */

#define AL_OBJQL_RANGE_AA16    0x04    /* 04 16-bit Absolute Address in Range Field */

#define AL_OBJQL_RANGE_AA32    0x05    /* 05 32-bit Absolute Address in Range Field */

#define AL_OBJQL_RANGE_R0      0x06    /* 06 Length of Range field is 0 (no range field) */

#define AL_OBJ_DA_LOC_TA        0x00D9   /* 00 217 Device Attributes - Local timing accuracy             */

#define AL_OBJ_DA_BI_EVT        0x00ED   /* 00 237 Device Attributes - Support for Binary Input Events   */

#define AL_OBJ_DA_MAX_BI        0x00EE   /* 00 238 Device Attributes - Max Binary Input Point Index      */

#define AL_OBJ_DA_NUM_BI        0x00EF   /* 00 239 Device Attributes - Number of Binary Input Points     */

#define AL_OBJ_DA_ID            0x00F6   /* 00 246 Device Attributes - User-Assigned ID code/number      */

#define AL_OBJ_BI_ALL      0x0100   /* 01 00 Binary Input Default Variation */

#define AL_OBJ_BI_1BIT     0x0101   /* 01 01 Single-bit Binary Input */

#define AL_OBJ_BI_STAT     0x0102   /* 01 02 Binary Input With Status */

#define AL_OBJ_BIC_ALL     0x0200   /* 02 00 Binary Input Change Default Variation */

#define AL_OBJ_BIC_NOTIME  0x0201   /* 02 01 Binary Input Change Without Time */

#define AL_OBJ_BIC_TIME    0x0202   /* 02 02 Binary Input Change With Time */

#define AL_OBJ_BIC_RTIME   0x0203   /* 02 03 Binary Input Change With Relative Time */

#define AL_OBJ_2BI_ALL     0x0300   /* 03 00 Double-bit Input Default Variation */

#define AL_OBJ_2BI_NF      0x0301   /* 03 01 Double-bit Input No Flags */


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);
  }
}

#define AL_IIN_DT          0x4000   /* Bit 6 - Device Trouble */

#define AL_IIN_FCNI        0x0001   /* Bit 0 - Function code not implemented */

#define AL_IIN_OBJU        0x0002   /* Bit 1 - Requested Objects Unknown */

#define AL_IIN_PIOOR       0x0004   /* Bit 2 - Parameters Invalid or Out of Range */

#define AL_IIN_EBO         0x0008   /* Bit 3 - Event Buffer Overflow */

#define AL_IIN_OAE         0x0010   /* Bit 4 - Operation Already Executing */

#define AL_IIN_CC          0x0020   /* Bit 5 - Device Configuration Corrupt */

#define AL_OBJ_FILE_MODE_NULL   0x00   /* NULL */

static int proto_dnp3 = -1;

static int hf_dnp3_start = -1;

static int hf_dnp3_len = -1;

static int hf_dnp3_ctl = -1;

static int hf_dnp3_ctl_prifunc = -1;

static int hf_dnp3_ctl_secfunc = -1;

static int hf_dnp3_ctl_dir = -1;

static int hf_dnp3_ctl_prm = -1;

static int hf_dnp3_ctl_fcb = -1;

static int hf_dnp3_ctl_fcv = -1;

static int hf_dnp3_ctl_dfc = -1;

static int hf_dnp3_dst = -1;

static int hf_dnp3_src = -1;

static int hf_dnp3_addr = -1;

static int hf_dnp3_data_hdr_crc = -1;

static int hf_dnp3_data_hdr_crc_status = -1;

static int hf_dnp3_tr_ctl = -1;

static int hf_dnp3_tr_fin = -1;

static int hf_dnp3_tr_fir = -1;

static int hf_dnp3_tr_seq = -1;

static int hf_dnp3_data_chunk = -1;

static int hf_dnp3_data_chunk_len = -1;

static int hf_dnp3_data_chunk_crc = -1;

static int hf_dnp3_data_chunk_crc_status = -1;

static int hf_dnp3_al_ctl = -1;

static int hf_dnp3_al_fir = -1;

static int hf_dnp3_al_fin = -1;

static int hf_dnp3_al_con = -1;

static int hf_dnp3_al_uns = -1;

static int hf_dnp3_al_seq = -1;

static int hf_dnp3_al_func = -1;

static int hf_dnp3_al_iin = -1;

static int hf_dnp3_al_iin_bmsg = -1;

static int hf_dnp3_al_iin_cls1d = -1;

static int hf_dnp3_al_iin_cls2d = -1;

static int hf_dnp3_al_iin_cls3d = -1;

static int hf_dnp3_al_iin_tsr = -1;

static int hf_dnp3_al_iin_dol = -1;

static int hf_dnp3_al_iin_dt = -1;

static int hf_dnp3_al_iin_rst = -1;

static int hf_dnp3_al_iin_fcni = -1;

static int hf_dnp3_al_iin_obju = -1;

static int hf_dnp3_al_iin_pioor = -1;

static int hf_dnp3_al_iin_ebo = -1;

static int hf_dnp3_al_iin_oae = -1;

static int hf_dnp3_al_iin_cc = -1;


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);
}

#define DNP_HDR_LEN     10

#define AL_OBJ_DA_MSTR_DSP      0x00D4   /* 00 212 Device Attributes - Number of master-defined data set prototypes  */

#define AL_OBJ_DA_OS_DSP        0x00D5   /* 00 213 Device Attributes - Number of outstation-defined data set prototypes */

#define AL_OBJ_DA_MSTR_DS       0x00D6   /* 00 214 Device Attributes - Number of master-defined data sets  */

#define AL_OBJ_DA_OS_DS         0x00D7   /* 00 215 Device Attributes - Number of outstation-defined data sets  */

void proto_register_dnp3(void);

void proto_reg_handoff_dnp3(void);


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);
}

#define DNP3_CTL_DIR    0x80

#define DNP3_CTL_PRM    0x40

#define DNP3_CTL_FCB    0x20

#define DNP3_CTL_FCV    0x10

#define DNP3_CTL_DFC    0x10

#define DNP3_CTL_FUNC   0x0f

#define DNP3_TR_FIR     0x40

#define DNP3_TR_FIN     0x80

#define DNP3_TR_SEQ     0x3f

#define DNP3_AL_UNS   0x10

#define DNP3_AL_CON   0x20

#define DNP3_AL_FIN   0x40

#define DNP3_AL_FIR   0x80

#define DNP3_AL_SEQ   0x0f

#define DNP3_AL_FUNC  0xff

#define AL_FUNC_CONFIRM    0x00    /* 00  - Confirm */

#define AL_FUNC_READ       0x01    /* 01  - Read */

#define AL_FUNC_WRITE      0x02    /* 02  - Write */

#define AL_FUNC_FRZCLR     0x09    /* 09  - Freeze and Clear */

#define AL_FUNC_FRZCLRNACK 0x0A    /* 10  - Freeze and Clear No ACK */

#define AL_FUNC_FRZT       0x0B    /* 11  - Freeze With Time */

#define AL_FUNC_FRZTNACK   0x0C    /* 12  - Freeze With Time No ACK */

#define AL_FUNC_COLDRST    0x0D    /* 13  - Cold Restart */

#define AL_FUNC_WARMRST    0x0E    /* 14  - Warm Restart */

#define AL_FUNC_INITDATA   0x0F    /* 15  - Initialize Data */

#define AL_FUNC_INITAPP    0x10    /* 16  - Initialize Application */

#define AL_FUNC_STARTAPP   0x11    /* 17  - Start Application */

#define AL_FUNC_STOPAPP    0x12    /* 18  - Stop Application */

#define AL_FUNC_SAVECFG    0x13    /* 19  - Save Configuration */

#define AL_FUNC_ENSPMSG    0x14    /* 20  - Enable Spontaneous Msg */

#define AL_FUNC_DISSPMSG   0x15    /* 21  - Disable Spontaneous Msg */

#define AL_FUNC_DELAYMST   0x17    /* 23  - Delay Measurement */

#define AL_FUNC_RECCT      0x18    /* 24  - Record Current Time */

#define AL_FUNC_OPENFILE   0x19    /* 25  - Open File */

#define AL_FUNC_CLOSEFILE  0x1A    /* 26  - Close File */

#define AL_FUNC_DELETEFILE 0x1B    /* 27  - Delete File */

#define AL_FUNC_GETFILEINF 0x1C    /* 28  - Get File Info */

#define AL_FUNC_AUTHFILE   0x1D    /* 29  - Authenticate File */

#define AL_FUNC_ABORTFILE  0x1E    /* 30  - Abort File */

#define AL_FUNC_AUTHREQ    0x20    /* 32  - Authentication Request */

#define AL_FUNC_AUTHERR    0x21    /* 33  - Authentication Error */

#define AL_FUNC_UNSOLI     0x82    /* 130 - Unsolicited Response */

#define AL_FUNC_AUTHRESP   0x83    /* 131 - Authentication Response */


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

#define AL_MAX_CHUNK_SIZE 16

void proto_register_dnp3(void);

#define DNP_HDR_LEN     10

static reassembly_table al_reassembly_table;

#define DL_FUNC_ACK         0x00

#define DNP3_AL_FUNC  0xff

#define AL_OBJ_GRP_MASK 0xFF00

#define AL_DATA_TYPE_NONE         0x0

#define AL_DATA_TYPE_UINT         0x2

#define AL_DATA_TYPE_INT          0x3

#define AL_DATA_TYPE_TIME         0x7

void proto_reg_handoff_dnp3(void);

static int proto_dnp3 = -1;

static gint ett_dnp3 = -1;

static gboolean dnp3_desegment = TRUE;

#define DL_FUNC_RESET_LINK  0x00

#define DL_FUNC_RESET_PROC  0x01

#define DL_FUNC_TEST_LINK   0x02

#define DL_FUNC_USER_DATA   0x03

#define DL_FUNC_LINK_STAT   0x09

#define DL_FUNC_NACK        0x01

#define DL_FUNC_STAT_LINK   0x0B

#define DL_FUNC_NO_FUNC     0x0E

#define DL_FUNC_NOT_IMPL    0x0F

#define AL_OBJ_VAR_MASK 0x00FF

#define AL_DATA_TYPE_VSTR         0x1

#define AL_DATA_TYPE_FLT          0x4

#define AL_DATA_TYPE_OSTR         0x5

#define AL_DATA_TYPE_BSTR         0x6

#define AL_DATA_TYPE_UNCD         0x8

#define AL_OBJCTL_STATUS_MASK 0x7F

static int hf_dnp3_start = -1;

static int hf_dnp3_len = -1;

static int hf_dnp3_ctl = -1;

static int hf_dnp3_dst = -1;

static int hf_dnp3_src = -1;

static int hf_dnp3_addr = -1;

static gint ett_dnp3_dl = -1;

static gint ett_dnp3_al = -1;

static dissector_handle_t dnp3_tcp_handle;

static dissector_handle_t dnp3_udp_handle;

#define TCP_PORT_DNP    20000

#define UDP_PORT_DNP    20000

#define DNP3_CTL_DIR    0x80

#define DNP3_CTL_RES    0x20

#define DNP3_CTL_FUNC   0x0f

#define DNP3_TR_FIN     0x80

#define DNP3_TR_SEQ     0x3f

#define DL_FUNC_UNC_DATA    0x04

#define DNP3_AL_UNS   0x10

#define DNP3_AL_CON   0x20

#define DNP3_AL_FIN   0x40

#define DNP3_AL_SEQ   0x0f

static int hf_dnp3_ctl_dir = -1;

static int hf_dnp3_tr_ctl = -1;

static int hf_dnp3_tr_fin = -1;

static int hf_dnp3_tr_seq = -1;

static int hf_dnp3_data_chunk = -1;

static int hf_dnp3_al_ctl = -1;

static int hf_dnp3_al_fin = -1;

static int hf_dnp3_al_con = -1;

static int hf_dnp3_al_seq = -1;

static int hf_dnp3_al_func = -1;

static int hf_dnp3_al_obj = -1;

static int hf_dnp3_al_timestamp = -1;

static int hf_dnp3_al_bit = -1;

static int hf_dnp3_al_count = -1;

static gint ett_dnp3_dl_ctl = -1;

static gint ett_dnp3_tr_ctl = -1;

static gint ett_dnp3_dl_data = -1;

static gint ett_dnp3_dl_chunk = -1;


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;
}

#define AL_OBJQ_PREFIX         0x70    /* x111xxxx Masks Prefix from Qualifier */

#define AL_OBJQL_PREFIX_NI     0x00    /* Objects are Packed with no index */

#define AL_OBJQL_PREFIX_1O     0x01    /* Objects are prefixed w/ 1-octet index */

#define AL_OBJQL_PREFIX_2O     0x02    /* Objects are prefixed w/ 2-octet index */

#define AL_OBJQL_PREFIX_4O     0x03    /* Objects are prefixed w/ 4-octet index */

#define AL_OBJQL_PREFIX_1OS    0x04    /* Objects are prefixed w/ 1-octet object size */

#define AL_OBJQL_PREFIX_2OS    0x05    /* Objects are prefixed w/ 2-octet object size */

#define AL_OBJQL_PREFIX_4OS    0x06    /* Objects are prefixed w/ 4-octet object size */

#define AL_OBJCTL_STAT7    0x07    /* Request Not Accepted; Local/Remote switch in Local*/

static int proto_dnp3 = -1;

static int hf_dnp3_start = -1;

static int hf_dnp3_len = -1;

static int hf_dnp3_ctl = -1;

static int hf_dnp3_ctl_prifunc = -1;

static int hf_dnp3_ctl_secfunc = -1;

static int hf_dnp3_ctl_dir = -1;

static int hf_dnp3_ctl_prm = -1;

static int hf_dnp3_ctl_fcb = -1;

static int hf_dnp3_ctl_fcv = -1;

static int hf_dnp3_ctl_dfc = -1;

static int hf_dnp3_dst = -1;

static int hf_dnp3_src = -1;

static int hf_dnp3_addr = -1;

static int hf_dnp3_data_hdr_crc = -1;

static int hf_dnp3_data_hdr_crc_status = -1;

static int hf_dnp3_tr_ctl = -1;

static int hf_dnp3_tr_fin = -1;

static int hf_dnp3_tr_fir = -1;

static int hf_dnp3_tr_seq = -1;

static int hf_dnp3_data_chunk = -1;

static int hf_dnp3_data_chunk_len = -1;

static int hf_dnp3_data_chunk_crc = -1;

static int hf_dnp3_data_chunk_crc_status = -1;

static int hf_dnp3_al_ctl = -1;

static int hf_dnp3_al_fir = -1;

static int hf_dnp3_al_fin = -1;

static int hf_dnp3_al_con = -1;

static int hf_dnp3_al_uns = -1;

static int hf_dnp3_al_seq = -1;

static int hf_dnp3_al_func = -1;

static int hf_dnp3_al_iin = -1;

static int hf_dnp3_al_iin_bmsg = -1;

static int hf_dnp3_al_iin_cls1d = -1;

static int hf_dnp3_al_iin_cls2d = -1;

static int hf_dnp3_al_iin_cls3d = -1;

static int hf_dnp3_al_iin_tsr = -1;

static int hf_dnp3_al_iin_dol = -1;

static int hf_dnp3_al_iin_dt = -1;

static int hf_dnp3_al_iin_rst = -1;

static int hf_dnp3_al_iin_fcni = -1;

static int hf_dnp3_al_iin_obju = -1;


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;
}

#define AL_OBJ_DA_SEC_STAT      0x00D2   /* 00 210 Device Attributes - Number of security statistics per association */

#define AL_OBJ_DA_USR_ATTR      0x00D3   /* 00 211 Device Attributes - Identifier of support for user-specific attributes */

#define AL_OBJ_DA_MSTR_DSP      0x00D4   /* 00 212 Device Attributes - Number of master-defined data set prototypes  */

#define AL_OBJ_DA_OS_DSP        0x00D5   /* 00 213 Device Attributes - Number of outstation-defined data set prototypes */

#define AL_OBJ_DA_MSTR_DS       0x00D6   /* 00 214 Device Attributes - Number of master-defined data sets  */

#define AL_OBJ_DA_OS_DS         0x00D7   /* 00 215 Device Attributes - Number of outstation-defined data sets  */

#define AL_OBJ_DA_BO_REQ        0x00D8   /* 00 216 Device Attributes - Max number of binary outputs per request  */

#define AL_OBJ_DA_AO_EVT        0x00DB   /* 00 219 Device Attributes - Support for analog output events  */

#define AL_OBJ_DA_BO_EVT        0x00DE   /* 00 222 Device Attributes - Support for binary output events  */

#define AL_OBJ_DA_FCTR_EVT      0x00E1   /* 00 225 Device Attributes - Support for frozen counter events */

#define AL_OBJ_DA_FCTR          0x00E2   /* 00 226 Device Attributes - Support for frozen counters       */

#define AL_OBJ_DA_CTR_EVT       0x00E3   /* 00 227 Device Attributes - Support for counter events        */

#define AL_OBJ_DA_AIF           0x00E6   /* 00 230 Device Attributes - Support for frozen analog inputs  */

#define AL_OBJ_DA_AI_EVT        0x00E7   /* 00 231 Device Attributes - Support for analog input events   */

#define AL_OBJ_DA_2BI_EVT       0x00EA   /* 00 234 Device Attributes - Support for Double-Bit BI Events  */

#define AL_OBJ_DA_BI_EVT        0x00ED   /* 00 237 Device Attributes - Support for Binary Input Events   */

#define AL_OBJCTLC_CODE    0x0F    /* Bit-Mask xxxx1111 for Control Code 'Code' */

#define AL_OBJCTLC_MISC    0x30    /* Bit-Mask xx11xxxx for Control Code Queue (obsolete) and Clear Fields */

#define AL_OBJCTLC_TC      0xC0    /* Bit-Mask 11xxxxxx for Control Code 'Trip/Close' */

#define AL_OBJCTLC_NOTSET  0x00    /* xx00xxxx for Control Code, Clear and Queue not set */

#define AL_OBJCTLC_QUEUE   0x01    /* xxx1xxxx for Control Code, Clear Field 'Queue' */

#define AL_OBJCTLC_CLEAR   0x02    /* xx1xxxxx for Control Code, Clear Field 'Clear' */

#define AL_OBJCTLC_BOTHSET 0x03    /* xx11xxxx for Control Code, Clear and Queue both set */

#define AL_OBJCTL_STAT4    0x04    /* Control Operation Not Supported for this point */

void proto_register_dnp3(void);

void proto_reg_handoff_dnp3(void);

static int proto_dnp3 = -1;


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

#define AL_OBJ_DA_MSTR_DSP      0x00D4   /* 00 212 Device Attributes - Number of master-defined data set prototypes  */

#define AL_OBJ_DA_OS_DSP        0x00D5   /* 00 213 Device Attributes - Number of outstation-defined data set prototypes */

#define AL_OBJ_DA_MSTR_DS       0x00D6   /* 00 214 Device Attributes - Number of master-defined data sets  */

#define AL_OBJ_DA_OS_DS         0x00D7   /* 00 215 Device Attributes - Number of outstation-defined data sets  */

void proto_register_dnp3(void);

void proto_reg_handoff_dnp3(void);

static int proto_dnp3 = -1;

static int hf_dnp3_start = -1;

static int hf_dnp3_len = -1;

static int hf_dnp3_ctl = -1;

static int hf_dnp3_ctl_prifunc = -1;

static int hf_dnp3_ctl_secfunc = -1;

static int hf_dnp3_ctl_dir = -1;

static int hf_dnp3_ctl_prm = -1;

static int hf_dnp3_ctl_fcb = -1;

static int hf_dnp3_ctl_fcv = -1;

static int hf_dnp3_ctl_dfc = -1;

static int hf_dnp3_dst = -1;

static int hf_dnp3_src = -1;

static int hf_dnp3_addr = -1;

static int hf_dnp3_data_hdr_crc = -1;

static int hf_dnp3_data_hdr_crc_status = -1;

static int hf_dnp3_tr_ctl = -1;

static int hf_dnp3_tr_fin = -1;

static int hf_dnp3_tr_fir = -1;

static int hf_dnp3_tr_seq = -1;

static int hf_dnp3_data_chunk = -1;

static int hf_dnp3_data_chunk_len = -1;

static int hf_dnp3_data_chunk_crc = -1;

static int hf_dnp3_data_chunk_crc_status = -1;

static int hf_dnp3_al_ctl = -1;

static int hf_dnp3_al_fir = -1;

static int hf_dnp3_al_fin = -1;

static int hf_dnp3_al_con = -1;

static int hf_dnp3_al_uns = -1;

static int hf_dnp3_al_seq = -1;

static int hf_dnp3_al_func = -1;

static int hf_dnp3_al_iin = -1;

static int hf_dnp3_al_iin_bmsg = -1;

static int hf_dnp3_al_iin_cls1d = -1;

static int hf_dnp3_al_iin_cls2d = -1;

static int hf_dnp3_al_iin_cls3d = -1;

static int hf_dnp3_al_iin_tsr = -1;

static int hf_dnp3_al_iin_dol = -1;

static int hf_dnp3_al_iin_dt = -1;

static int hf_dnp3_al_iin_rst = -1;

static int hf_dnp3_al_iin_fcni = -1;

static int hf_dnp3_al_iin_obju = -1;

static int hf_dnp3_al_iin_pioor = -1;

static int hf_dnp3_al_iin_ebo = -1;

static int hf_dnp3_al_iin_oae = -1;

static int hf_dnp3_al_iin_cc = -1;

static int hf_dnp3_al_obj = -1;

static int hf_dnp3_al_objq_prefix = -1;