/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

File: octvc1_msg_ctrl.c

Copyright (c) 2014 Octasic Inc. All rights reserved.

Description: Routines for vocallonet dissection

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Release: Octasic Application Development Framework OCTADF-01.00.01-B497 (2014/01/09)

$Octasic_Revision: $

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/


#include <config.h>
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/expert.h>

#include "../include/module.h"
#include "../include/octvc1_common.h"
#include "../include/plugin_info.h"
#include "../../../include/oct_ws_macro.h"

#include <color.h>
#include <color_filters.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmodule.h>

#include "../include/ws_util.h"

#include <octvc1_msg.h>
#include <octvc1_base.h>
#define OCTVC1_RC2STRING_DECLARE
#include <octvc1_rc2string.h>
#include <ctrl/octvc1_ctrl_api.h>

/* Define version if we are not building Wireshark statically */
/* Initialize the protocol and registered fields */
int proto_octvc1_ctrl = -1;

/* tOCTVC1_MSG_HEADER */
int hf_octvc1_msg_cmd	= -1;
int hf_octvc1_msg_rsp	= -1;
int hf_octvc1_msg_evt	= -1;

extern int g_fIsRegistered;

static int hf_octvc1_msg_header_ulLength		= -1;
static int hf_octvc1_msg_header_ulTransactionId = -1;
static int hf_octvc1_msg_header_ul_Type_R_CmdId = -1;
static int hf_octvc1_msg_header_ulSessionId		= -1;
static int hf_octvc1_msg_header_ulReturnCode	= -1;
static int hf_octvc1_msg_header_ulUserInfo		= -1;

static int hf_octvc1_msg_header_reject_expected_transaction_id	= -1;
static int hf_octvc1_msg_header_reject_rejected_command_id		= -1;


static int hf_octvc1_msg_header_ul_Type_R_CmdId_Type		= -1;
static int hf_octvc1_msg_header_ul_Type_R_CmdId_Resynch		= -1;
static int hf_octvc1_msg_header_ul_Type_R_CmdId_Base		= -1;
static int hf_octvc1_msg_header_ul_Type_R_CmdId_ModuleId	= -1;
static int hf_octvc1_msg_header_ul_Type_R_CmdId_MsgId		= -1;
static int hf_octvc1_msg_header_ul_Type_R_CmdId_Flag		= -1;


#define mWD_OCTVC1_CID_TYPE_BASE(uint32)			((uint32) & 0x00f00000)
#define mWD_OCTVC1_CID_UID(uint32)					((uint32) & 0x000f0000)
#define mWD_OCTVC1_CID_CODE(uint32)					((uint32) & 0x00000FFF)
#define mWD_OCTVC1_CID_FLAG(uint32)					((uint32) & 0x0000F000)

#define mWD_OCTVC1_CID_2_FLAG(uint32)				(((uint32)& 0x0000F000)>>12)
#define mWD_OCTVC1_CID_2_UID(uint32)				(((uint32)& 0x000F0000)>>16)
#define mWD_OCTVC1_CID_2_BASE(uint32)				(((uint32)& 0x00F00000)>>20)


const value_string octvc1_message_type_vals[] =
{
	{ cOCTVC1_MSG_TYPE_COMMAND,			"Command" },
	{ cOCTVC1_MSG_TYPE_RESPONSE,		"Response" },
	{ cOCTVC1_MSG_TYPE_NOTIFICATION,	"Notification" },
	{ cOCTVC1_MSG_TYPE_SUPERVISORY,		"Supervisory" },
	{ 0,		NULL },
};

const value_string octvc1_message_type_base_vals[] =
{
	{ cOCTVC1_CID_BASE>>20,		"Cmd/Rsp" },
	{ cOCTVC1_EID_BASE>>20,		"Notification" },
	{ cOCTVC1_SID_BASE>>20,		"Supervisory" },
	{ 0,		NULL },
};

const value_string octvc1_cid_flag_vals[] =
{
	{ cOCTVC1_MSG_RETRANSMIT_FLAG >> cOCTVC1_MSG_FLAGS_BIT_OFFSET,			"Retransmit" },
	{ cOCTVC1_MSG_NO_RESPONSE_FLAG >> cOCTVC1_MSG_FLAGS_BIT_OFFSET,			"No Response" },
	{ cOCTVC1_MSG_LONG_PROCESSING_FLAG >> cOCTVC1_MSG_FLAGS_BIT_OFFSET,		"Long Processing" },
	{ 0,		"None" },
	{ 0,		NULL },
};



/* fields defining a subtree */
static gint ett_octvc1_msg_header   = -1;
static gint ett_octvc1_type_r_cmd	= -1;
gint		ett_octvc1_msg_type		= -1;





/*************************************************************************
*
*  Code to actually dissect the Vocallo event packet header
*
**************************************************************************/
void dissect_octvc1_ctrl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	unsigned int	packet_offset = 0;
	guint32			message_length;
	guint32			transaction_id;
	guint32			type_r_cmdid;
	guint8			message_type;
	guint8			message_resynch;
	guint32			message_command_id;

	guint32			command_id_type_base;
	guint32			command_id_uid;
	guint32			command_id_code;
	guint32			command_id_flag;

	guint32			session_id;
	guint32			return_code;
	guint32			user_info;
	guint32			expected_transaction_id = -1;
	guint32			rejected_command_id = -1;
	proto_tree*		msg_tree = NULL;
	gint32			module_index = -1;
	guint32			fOldMainCid = FALSE;
	const gchar*	pszValueStringCID=NULL;
	gint32			iRegistered = 1;


	if (check_col(pinfo->cinfo, COL_PROTOCOL))
		col_set_str(pinfo->cinfo, COL_PROTOCOL, "OCTVC1_CTRL");

	/* Now parse the message header */
	message_length = tvb_get_ntohl( tvb, packet_offset );
	packet_offset += sizeof(message_length);
	transaction_id = tvb_get_ntohl( tvb, packet_offset );
	packet_offset += sizeof(transaction_id);

	type_r_cmdid = tvb_get_ntohl( tvb, packet_offset );

	message_type = ( type_r_cmdid >> cOCTVC1_MSG_TYPE_BIT_OFFSET ) & cOCTVC1_MSG_TYPE_BIT_MASK;
	message_resynch = ( type_r_cmdid >> cOCTVC1_MSG_RESYNCH_BIT_OFFSET ) & cOCTVC1_MSG_RESYNCH_BIT_MASK;
	message_command_id = ( type_r_cmdid >> cOCTVC1_MSG_ID_BIT_OFFSET ) & cOCTVC1_MSG_ID_BIT_MASK;
	
	command_id_type_base = mWD_OCTVC1_CID_TYPE_BASE(message_command_id);
	command_id_uid = mWD_OCTVC1_CID_UID(message_command_id);
	command_id_code = mWD_OCTVC1_CID_CODE(message_command_id);
	command_id_flag = mWD_OCTVC1_CID_FLAG(message_command_id);

	/* Find Tbl Module Index */
	OCT_MATCH_STRVAL_IDX( mWD_OCTVC1_CID_2_UID(message_command_id), vals_OCTVC1_module_UID, &module_index );

	// Special process on main ... CID use to be 0x01yz and we are now 0x0zzz
	// if can't find 0x01yz try with 0x00yz

	if( cOCTVC1_MAIN_UID == mWD_OCTVC1_CID_2_UID(message_command_id) ) 
	{
		int cmd_index;
	
		OCT_MATCH_STRVAL_IDX( command_id_code, 
			aOCTVC1ModuleColInfo[module_index].apCodeIdValueString, &cmd_index );
		// did we found the cid
		if( cmd_index == -1 )
		{
			OCT_MATCH_STRVAL_IDX( command_id_code & 0x000000FF, 
				aOCTVC1ModuleColInfo[module_index].apCodeIdValueString, &cmd_index );

			if( cmd_index != -1 )
			{
				// This is an old trace ...
				command_id_code &= 0xFFFFFEFF;
				fOldMainCid = TRUE;
			}
		}
	}

	packet_offset += sizeof(type_r_cmdid);

	session_id = tvb_get_ntohl( tvb, packet_offset );
	packet_offset += sizeof(session_id);
	return_code = tvb_get_ntohl( tvb, packet_offset );
	packet_offset += sizeof(return_code);

	// Get no swap 
	tvb_memcpy( tvb, &user_info, packet_offset, sizeof(user_info) );
	// user_info = tvb_get_ntohl( tvb, packet_offset );
	packet_offset += sizeof(user_info);

	if( ( message_type == cOCTVC1_MSG_TYPE_SUPERVISORY ) &&
		( ( cOCTVC1_SUPERVISORY_MSG_MODULE_REJECT_CID == message_command_id ) ||
		  ( cOCTVC1_CTRL_MSG_MODULE_REJECT_SID == message_command_id ) ) )
	{
		expected_transaction_id = tvb_get_ntohl( tvb, packet_offset );
		packet_offset += sizeof(expected_transaction_id);
		rejected_command_id = tvb_get_ntohl( tvb, packet_offset );
		packet_offset += sizeof(rejected_command_id);
	}


	if ( check_col( pinfo->cinfo, COL_INFO) )
	{
		col_clear(pinfo->cinfo, COL_INFO);
		if( message_type != cOCTVC1_MSG_TYPE_SUPERVISORY )
		{
			if( module_index < 0 )
			{
				col_add_fstr( pinfo->cinfo, COL_INFO,
					"%s %s, CID=0x%04X, Trans ID=0x%x",
					val_to_str( mWD_OCTVC1_CID_2_UID(message_command_id), vals_OCTVC1_module_UID, "Unknown (%x)" ),
					val_to_str( message_type, octvc1_message_type_vals, "Unknown (%x)" ),
					command_id_code,
					transaction_id );
			}
			else
			{
				pszValueStringCID = val_to_str( command_id_code, aOCTVC1ModuleColInfo[module_index].apCodeIdValueString, cOCTVC1_UNKNOWN_STRING );

				// look for private
				if( strcmp( pszValueStringCID, cOCTVC1_PRIVATE_ID_STRING ) == 0 )
				{
					iRegistered = 0;
					// look if somebody register
					if( g_fIsRegistered )
					{
						pszValueStringCID = octvc1_chck_private( command_id_code, aOCTVC1ModuleColInfo[module_index].apPrivateCodeIdValueString, &iRegistered );
					}
					else
						pszValueStringCID = cOCTVC1_UNKNOWN_STRING;
				}

				col_add_fstr( pinfo->cinfo, COL_INFO,
						"%s%s_MSG_%s(0x%04X), Trans ID=0x%x",
						fOldMainCid ? "*" : "",
						aOCTVC1ModuleColInfo[module_index].pszModuleName,
						pszValueStringCID,
						command_id_code,
						transaction_id);
			}
			if (message_type == cOCTVC1_MSG_TYPE_RESPONSE)
			{
				if ( check_col(pinfo->cinfo, COL_PROTOCOL) )
					col_set_str(pinfo->cinfo, COL_PROTOCOL, "OCTVC1_RSP");

				col_append_fstr( pinfo->cinfo, COL_INFO,
					", Ret Code=%s (0x%08X)",
					mOCTVC1_RC2STRING(return_code), return_code );
			}
			else
			{
				if ( check_col(pinfo->cinfo, COL_PROTOCOL) )
					col_set_str(pinfo->cinfo, COL_PROTOCOL, "OCTVC1_CMD");
			}
		}
		else
		{
			if( ( cOCTVC1_SUPERVISORY_MSG_MODULE_REJECT_CID == message_command_id ) ||
				( cOCTVC1_CTRL_MSG_MODULE_REJECT_SID == message_command_id ) )
			{
				gint32			rej_module_index = -1;
				gint32			rej_command_id_code = mWD_OCTVC1_CID_CODE(rejected_command_id);

				/* Find Tbl Module Index */
				OCT_MATCH_STRVAL_IDX( mWD_OCTVC1_CID_2_UID(rejected_command_id), vals_OCTVC1_module_UID, &rej_module_index );

				if( ( rej_module_index != -1 ) && 
					( cOCTVC1_MAIN_UID == mWD_OCTVC1_CID_2_UID(rejected_command_id ) ) )
				{
					int cmd_index;
				
					OCT_MATCH_STRVAL_IDX( rejected_command_id, 
						aOCTVC1ModuleColInfo[rej_module_index].apCodeIdValueString, &cmd_index );
					// did we found the cid
					if( cmd_index == -1 )
					{
						OCT_MATCH_STRVAL_IDX( rejected_command_id & 0x000000FF, 
							aOCTVC1ModuleColInfo[rej_module_index].apCodeIdValueString, &cmd_index );

						if( cmd_index != -1 )
						{
							// This is an old trace ...
							rejected_command_id &= 0xFFFFFEFF;
							fOldMainCid = TRUE;
						}
					}
				}


				if( rej_module_index == -1 )
					col_add_fstr( pinfo->cinfo, COL_INFO,
						"Reject %s, CID=0x%04X, Exp trans ID=0x%x",
						val_to_str( mWD_OCTVC1_CID_2_UID(rejected_command_id), vals_OCTVC1_module_UID, "Unknown (%x)" ),
						rej_command_id_code,
						expected_transaction_id );
				else
				{
					pszValueStringCID = val_to_str( rej_command_id_code, aOCTVC1ModuleColInfo[rej_module_index].apCodeIdValueString, cOCTVC1_UNKNOWN_STRING );

					// look for private
					if( strcmp( pszValueStringCID, cOCTVC1_PRIVATE_ID_STRING ) == 0 )
					{
						iRegistered = 0;
						// look if somebody register
						if( g_fIsRegistered )
						{
							pszValueStringCID = octvc1_chck_private( rej_command_id_code, aOCTVC1ModuleColInfo[rej_module_index].apPrivateCodeIdValueString, &iRegistered );
						}
						else
							pszValueStringCID = cOCTVC1_UNKNOWN_STRING;
					}

					col_add_fstr( pinfo->cinfo, COL_INFO,
						"Reject %s%s_MSG_%s, Exp trans ID=0x%x",
						fOldMainCid ? "*" : "",
						aOCTVC1ModuleColInfo[rej_module_index].pszModuleName,
						pszValueStringCID,
						expected_transaction_id	);
				}
			}
		}
	}

	if (tree)
	{
		proto_item*		ti = NULL;

		proto_item *tf = NULL;
		proto_tree *field_tree;

		/* Add the subtree for struct tOCTVOCNET_PKT_CTL_HEADER */
		ti = proto_tree_add_item( tree, proto_octvc1_ctrl, tvb, 0, -1, FALSE );
		msg_tree = proto_item_add_subtree( ti, ett_octvc1_msg_header );

		/* Scroll back to the beginning of the packet */
		packet_offset = 0;

		proto_tree_add_uint( msg_tree, hf_octvc1_msg_header_ulLength, tvb, packet_offset, 4, message_length );
		packet_offset += sizeof(message_length);
		proto_tree_add_uint( msg_tree, hf_octvc1_msg_header_ulTransactionId, tvb, packet_offset, 4, transaction_id );
		packet_offset += sizeof(transaction_id);

		/* Validate the cmd */
		if( module_index < 0 )
		{
			proto_tree_add_uint(msg_tree, hf_octvc1_msg_header_ul_Type_R_CmdId, tvb, packet_offset, 4, type_r_cmdid );
		}
		else
		{
			if( message_type != cOCTVC1_MSG_TYPE_SUPERVISORY )
			{
				if( pszValueStringCID == NULL )
				{
					pszValueStringCID = val_to_str( command_id_code, aOCTVC1ModuleColInfo[module_index].apCodeIdValueString, cOCTVC1_UNKNOWN_STRING );

					// look for private
					if( strcmp( pszValueStringCID, cOCTVC1_PRIVATE_ID_STRING ) == 0 )
					{
						iRegistered = 0;
						// look if somebody register
						if( g_fIsRegistered )
						{
							pszValueStringCID = octvc1_chck_private( command_id_code, aOCTVC1ModuleColInfo[module_index].apPrivateCodeIdValueString, &iRegistered );
						}
						else
							pszValueStringCID = cOCTVC1_UNKNOWN_STRING;
					}
				}

				tf = proto_tree_add_uint_format(msg_tree, hf_octvc1_msg_header_ul_Type_R_CmdId, tvb,
					packet_offset, 4, type_r_cmdid,
					"Type/%s(0x%08X): %scOCTVC1_%s_MSG_%s_CID",
					(message_type == cOCTVC1_MSG_TYPE_RESPONSE) ? "Rsp" : "Cmd",
					type_r_cmdid,
					fOldMainCid ? "*" : "",
					aOCTVC1ModuleColInfo[module_index].pszModuleName,
					pszValueStringCID );
			}
			else
			{
				tf = proto_tree_add_uint_format(msg_tree, hf_octvc1_msg_header_ul_Type_R_CmdId, tvb,
					packet_offset, 4, type_r_cmdid,
					"Type/Sup(0x%08X): cOCTVC1_%s_MSG_%s_SID",
					type_r_cmdid,
					aOCTVC1ModuleColInfo[module_index].pszModuleName,
					val_to_str( command_id_code,aOCTVC1ModuleColInfo[module_index].apSupIdValueString, "Unknown (%x)" ));
			}
		}

		if( tf )
		{
			int iFlag = 0x00001000;
			int i,cFlag = 0;

			field_tree = proto_item_add_subtree(tf, ett_octvc1_type_r_cmd);

			proto_tree_add_uint( field_tree, hf_octvc1_msg_header_ul_Type_R_CmdId_Type, tvb,
				packet_offset, 1, message_type << 29 );

			proto_tree_add_uint( field_tree, hf_octvc1_msg_header_ul_Type_R_CmdId_Resynch, tvb,
				packet_offset, 1, message_resynch<<28 );

			proto_tree_add_uint( field_tree, hf_octvc1_msg_header_ul_Type_R_CmdId_Base, tvb,
				packet_offset+1, 1, command_id_type_base );

			proto_tree_add_uint( field_tree, hf_octvc1_msg_header_ul_Type_R_CmdId_ModuleId, tvb,
				packet_offset+1, 1, command_id_uid );

			// Count nb of flag
			for( i=0; i<4; i++)
			{
				if( command_id_flag & iFlag )
					cFlag++;
				iFlag = iFlag << 1;
			}

			if( cFlag < 2 )
				proto_tree_add_uint( field_tree, hf_octvc1_msg_header_ul_Type_R_CmdId_Flag, tvb,
					packet_offset+2, 1, command_id_flag );
			else
			{
				int i;
				proto_tree*	sub_tree = proto_item_add_subtree(field_tree, ett_octvc1_msg_type);

				proto_tree_add_uint_format_value( field_tree, hf_octvc1_msg_header_ul_Type_R_CmdId_Flag, tvb,
					packet_offset+2, 1, command_id_flag,
					"(0x%X)", (command_id_flag >>cOCTVC1_MSG_FLAGS_BIT_OFFSET) );


				for( i=0; i< mWS_COUNTOF(octvc1_cid_flag_vals); i++ )
				{
					if( ( octvc1_cid_flag_vals[i].value && 
						( octvc1_cid_flag_vals[i].value & ( command_id_flag >> cOCTVC1_MSG_FLAGS_BIT_OFFSET )) == 
						 octvc1_cid_flag_vals[i].value))
						proto_tree_add_text(sub_tree, tvb, packet_offset+2,1,"%s",
						decode_enumerated_bitfield(octvc1_cid_flag_vals[i].value, 0xFFFFFFFF, (4*1),
							VALS(octvc1_cid_flag_vals),"%s"));
				}
			}

			if( message_type != cOCTVC1_MSG_TYPE_SUPERVISORY )
				proto_tree_add_uint_format_value(field_tree, hf_octvc1_msg_header_ul_Type_R_CmdId_MsgId, tvb,
					packet_offset+2, 2, command_id_code,
					"%s%s (0x%03X)",
					fOldMainCid ? "*" : "",
					pszValueStringCID, command_id_code );
			else
				proto_tree_add_uint_format_value(field_tree, hf_octvc1_msg_header_ul_Type_R_CmdId_MsgId, tvb,
					packet_offset+2, 2, command_id_code,
					"%s (0x%03X)",
					val_to_str( command_id_code, aOCTVC1ModuleColInfo[module_index].apSupIdValueString,
						"Unknown (%x)" ), command_id_code );

		}

		packet_offset += sizeof(command_id_code);
		proto_tree_add_uint( msg_tree, hf_octvc1_msg_header_ulSessionId, tvb,
		    packet_offset, 4, session_id );
		packet_offset += sizeof(session_id);


		ti = proto_tree_add_uint_format_value(msg_tree, hf_octvc1_msg_header_ulReturnCode, tvb,
					packet_offset, 4, return_code,
					"%s (0x%08X)",
					mOCTVC1_RC2STRING(return_code), return_code );

		if( return_code )
		{
			if( return_code & cOCTDEV_RC_FATAL_FLAG )
				expert_add_info_format(pinfo, ti, PI_RESPONSE_CODE, PI_ERROR, "API:FATAL" );
			else
				expert_add_info_format(pinfo, ti, PI_RESPONSE_CODE, PI_WARN, "API:ERROR" );
		}

		packet_offset += sizeof(return_code);
		proto_tree_add_uint( msg_tree, hf_octvc1_msg_header_ulUserInfo, tvb,
		    packet_offset, 4, user_info );
		packet_offset += sizeof(user_info);

		if( ( message_type == cOCTVC1_MSG_TYPE_SUPERVISORY ) &&
			( ( cOCTVC1_SUPERVISORY_MSG_MODULE_REJECT_CID == message_command_id ) ||
			  ( cOCTVC1_CTRL_MSG_MODULE_REJECT_SID == message_command_id ) ) )
		{
			gint32			rej_module_index = -1;
			gint32			rej_command_id_code = mWD_OCTVC1_CID_CODE(rejected_command_id);

			/* Find Tbl Module Index */
			OCT_MATCH_STRVAL_IDX( mWD_OCTVC1_CID_2_UID(rejected_command_id), vals_OCTVC1_module_UID, &rej_module_index );

			if( ( rej_module_index != -1 ) && 
				( cOCTVC1_MAIN_UID == mWD_OCTVC1_CID_2_UID(rej_command_id_code) ) )
			{
				int cmd_index;
			
				OCT_MATCH_STRVAL_IDX( rejected_command_id, 
					aOCTVC1ModuleColInfo[rej_module_index].apCodeIdValueString, &cmd_index );
				// did we found the cid
				if( cmd_index == -1 )
				{
					OCT_MATCH_STRVAL_IDX( rej_command_id_code & 0x000000FF, 
						aOCTVC1ModuleColInfo[rej_module_index].apCodeIdValueString, &cmd_index );

					if( cmd_index != -1 )
					{
						// This is an old trace ...
						rej_command_id_code &= 0xFFFFFEFF;
						fOldMainCid = TRUE;
					}
				}
			}

			proto_tree_add_uint( msg_tree, hf_octvc1_msg_header_reject_expected_transaction_id, tvb,
			    packet_offset, 4, expected_transaction_id );
			packet_offset += sizeof(expected_transaction_id);

			if( rej_module_index == -1 )
				proto_tree_add_uint_format(msg_tree, hf_octvc1_msg_header_reject_rejected_command_id, tvb,
					packet_offset, 4, rejected_command_id,
					"Reject CID: %s, CID=0x%08X",
					val_to_str( mWD_OCTVC1_CID_2_UID(rejected_command_id), vals_OCTVC1_module_UID, "Unknown (%x)" ),
					rej_command_id_code );
			else
			{
				pszValueStringCID = val_to_str( rej_command_id_code, aOCTVC1ModuleColInfo[rej_module_index].apCodeIdValueString, cOCTVC1_UNKNOWN_STRING );

				// look for private
				if( strcmp( pszValueStringCID, cOCTVC1_PRIVATE_ID_STRING ) == 0 )
				{
					iRegistered = 0;
					// look if somebody register
					if( g_fIsRegistered )
					{
						pszValueStringCID = octvc1_chck_private( rej_command_id_code, aOCTVC1ModuleColInfo[rej_module_index].apPrivateCodeIdValueString, &iRegistered );
					}
					else
						pszValueStringCID = cOCTVC1_UNKNOWN_STRING;
				}


				proto_tree_add_uint_format(msg_tree, hf_octvc1_msg_header_reject_rejected_command_id, tvb,
					packet_offset, 4, rejected_command_id,
					"Rejected CID: %scOCTVC1_%s_MSG_%s_CID (0x%08X)",
					fOldMainCid ? "*" : "",
					aOCTVC1ModuleColInfo[rej_module_index].pszModuleName,
					pszValueStringCID,
					rejected_command_id );
			}

			packet_offset += sizeof(rejected_command_id);
		}
	}

	{
		int fDoData = 1;
		int reported_length = message_length ? ( message_length - sizeof(tOCTVC1_MSG_HEADER)) : 0;
		int available_length = tvb_length_remaining(tvb, packet_offset);
		tvbuff_t *tvbData;

		tvbData = tvb_new_subset(tvb, packet_offset, available_length, reported_length);

		if( ( module_index >= 0 )  && iRegistered )
		{
			/* Call the module dissector */
			fDoData = aOCTVC1ModuleColInfo[module_index].Dissector_fnc( message_type,
							message_command_id & ~(cOCTVC1_MSG_RETRANSMIT_FLAG),
							tvbData, pinfo, msg_tree );
		}

		if( fDoData )
		{
			/* Dump the rest in raw format */
			call_dissector(data_handle, tvbData, pinfo, msg_tree);
		}
	}
//	return tvb_length(tvb);

}




/*************************************************************************
*
*  Code to register the protocol with Wireshark
*
**************************************************************************/
void proto_register_octvc1_ctrl(void)
{

	static hf_register_info hf_octvc1_msg_header[] =
	{
		{ &hf_octvc1_msg_header_ulLength,
			{ "API Message Length (in bytes)", "octvc1.msg_header.ullength",
			FT_UINT32, BASE_DEC, NULL, 0x0,
			"API Message Length (in bytes)", HFILL }
		},
		{ &hf_octvc1_msg_header_ulTransactionId,
			{ "Transaction Id",           "octvc1.msg_header.ultransaction_id",
			FT_UINT32, BASE_HEX, 0, 0x0,
			"Transcation identifier", HFILL }
		},

		{ &hf_octvc1_msg_header_ul_Type_R_CmdId,
		{ "Msg type/Id",	"octvc1.msg_header.ul_Type_R_CmdId", FT_UINT32, BASE_HEX, NULL, 0x0,
			"", HFILL }},

		{ &hf_octvc1_msg_header_ulSessionId,
			{ "Session Id",           "octvc1.msg_header.ulsessionid",
			FT_UINT32, BASE_HEX, NULL, 0x0,
			"Session Id", HFILL }
		},
		{ &hf_octvc1_msg_header_ulReturnCode,
			{ "Return Code",           "octvc1.msg_header.ulReturnCode",
			FT_UINT32, BASE_HEX, NULL, 0x0,
			"Return Code", HFILL }
		},
		{ &hf_octvc1_msg_header_ulUserInfo,
			{ "User Info",           "octvc1.msg_header.ulUserInfo",
			FT_UINT32, BASE_HEX, NULL, 0x0,
			"User Info", HFILL }
		},

		{ &hf_octvc1_msg_header_reject_expected_transaction_id,
			{ "Expected transaction Id",      "octvc1.msg_header.reject.expected_transaction_id",
			FT_UINT32, BASE_HEX, NULL, 0x0,
			"Expected transaction Id", HFILL }
		},
		{ &hf_octvc1_msg_header_reject_rejected_command_id,
			{ "Rejected command ID",          "octvc1.msg_header.reject.rejected_command_id",
			FT_UINT32, BASE_HEX, NULL, 0x0,
			"Rejected command ID", HFILL }
		},


		{ &hf_octvc1_msg_header_ul_Type_R_CmdId_Type,
			{ "Message Type",           "octvc1.msg_header.message_type",
			FT_UINT32, BASE_HEX, VALS(octvc1_message_type_vals), 0xe0000000,
			"Message type", HFILL }
		},
		{ &hf_octvc1_msg_header_ul_Type_R_CmdId_Resynch,
			{ "Control Resynch",           "octvc1.msg_header.resynch",
			FT_UINT32, BASE_HEX, NULL, 0x10000000,
			"Control resynch", HFILL }
		},

		{ &hf_octvc1_msg_header_ul_Type_R_CmdId_Base,
			{ "Message Type Base",           "octvc1.msg_header.type_base",
			FT_UINT32, BASE_HEX, VALS(octvc1_message_type_base_vals), 0x00f00000,
			"Message identifier", HFILL }
		},

		{ &hf_octvc1_msg_header_ul_Type_R_CmdId_ModuleId,
			{ "Module ID",           "octvc1.msg_header.module_id",
			FT_UINT32, BASE_HEX, VALS(vals_OCTVC1_module_UID), 0x000f0000,
			"Module identifier", HFILL }
		},
		{ &hf_octvc1_msg_header_ul_Type_R_CmdId_Flag,
			{ "Msg Flag",           "octvc1.msg_header.msg_flag",
			FT_UINT32, BASE_HEX, VALS(octvc1_cid_flag_vals), 0x0000f000,
			"Message flag", HFILL }
		},

		{ &hf_octvc1_msg_header_ul_Type_R_CmdId_MsgId,
			{ "Msg ID",           "octvc1.msg_header.msg_id",
			FT_UINT32, BASE_HEX, NULL, 0x00000fff,
			"Message identifier", HFILL }
		},
		{ &hf_octvc1_msg_cmd,
			{ "Cmd",           "octvc1.msg_header.cmd",
			FT_NONE, BASE_NONE, NULL, 0x0,
			"Cmd", HFILL }
		},
		{ &hf_octvc1_msg_rsp,
			{ "Rsp",           "octvc1.msg_header.rsp",
			FT_NONE, BASE_NONE, NULL, 0x0,
			"Rsp", HFILL }
		},
		{ &hf_octvc1_msg_evt,
			{ "Evt",           "octvc1.msg_header.evt",
			FT_NONE, BASE_NONE, NULL, 0x0,
			"Evt", HFILL }
		},

	};

	/* Setup protocol subtree array */
	static gint* ett[] =
	{
		&ett_octvc1_msg_header,
		&ett_octvc1_type_r_cmd,
		&ett_octvc1_msg_type,

	};


	proto_octvc1_ctrl = proto_register_protocol(	"OCTVC1 Control Packets",
														"Octasic OCTVC1 Control", "octvc1_ctrl");

	/* Required function calls to register the header fields and subtrees used */
	proto_register_field_array( proto_octvc1_ctrl, hf_octvc1_msg_header, array_length(hf_octvc1_msg_header) );
	proto_register_subtree_array(ett, array_length(ett));

	register_dissector("Octvc1_Ctrl", dissect_octvc1_ctrl, proto_octvc1_ctrl);


}



