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

File: octpkt.c

$Octasic_Copyright: $

Description: 

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/>.

$Octasic_Release: $

$Revision: $

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

 #ifdef HAVE_CONFIG_H
# include "config.h"
#endif

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

#include "../include/moduleinfo.h"
#include "../../include/oct_ws_macro.h"
#include "../../include/oct_ws_priv.h"

#include <color.h>
#include <color_filters.h>

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

#include <octpkt_hdr.h>

/* Define version if we are not building Wireshark statically */

/* Initialize the protocol and registered fields */
static int proto_octpkt = -1;

static int hf_octpkt_format = -1;
static int hf_octpkt_trace_flag = -1;
static int hf_octpkt_api_type = -1;
static int hf_octpkt_size = -1;

static dissector_handle_t data_handle;
static dissector_handle_t vocallonet_handle;
static dissector_handle_t octmfa_handle;

/* fields defining a subtree */
static gint ett_octpkt       	= -1;


const value_string octpkt_api_type_vals[] =
{
	{ cOCTPKT_HDR_CONTROL_PROTOCOL_TYPE_ENUM_OCTVOCNET,	"OCTVOCNET" },
	{ cOCTPKT_HDR_CONTROL_PROTOCOL_TYPE_ENUM_OCTMFA,	"OCTMFA" },
	{ 0,		NULL },
};


#define OCTPKT_TRACE_BIT(octet)					((octet) & 0x80)
#define OCTPKT_TOTAL_PACKET_SIZE(uint16)		((uint16) & 0x07ff)
#define OCTPKT_API_TYPE(octet)					(((octet) & 0x78) >> 3 )



/*************************************************************************
*
*  Code to actually dissect the Vocallo common packet header
*
**************************************************************************/
static void dissect_octpkt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	proto_item*		ti				= NULL;
	proto_tree*		octpkt_tree	= NULL;
	unsigned int	offset	= 0;
	gboolean		trace_flag;
	guint32			format_trace_proto_len = 0;
	tOctWsPrivateData	*pPrivData;

	/* Make entries in Protocol column and Info column on summary display */
	if (check_col(pinfo->cinfo, COL_PROTOCOL))
		col_set_str(pinfo->cinfo, COL_PROTOCOL, "OCTPKT_FORMAT" );

	if( pinfo->private_data == NULL )
		pinfo->private_data = ep_alloc( sizeof( tOctWsPrivateData ) );

	pPrivData = (tOctWsPrivateData	*)pinfo->private_data;

	format_trace_proto_len = tvb_get_ntohl( tvb, offset );
	offset += sizeof(format_trace_proto_len);

	/* Get the format field [bit 24 to 31] */
	pPrivData->format = (format_trace_proto_len & cOCTPKT_HDR_FORMAT_PROTO_TYPE_LEN_MASK_FORMAT ) >> cOCTPKT_HDR_FORMAT_PROTO_TYPE_LEN_MASK_FORMAT_BIT_OFFSET;
	trace_flag = (format_trace_proto_len & cOCTPKT_HDR_FORMAT_PROTO_TYPE_LEN_MASK_TRACE ) >> cOCTPKT_HDR_FORMAT_PROTO_TYPE_LEN_MASK_TRACE_BIT_OFFSET;
	pPrivData->api_type = (format_trace_proto_len & cOCTPKT_HDR_FORMAT_PROTO_TYPE_LEN_MASK_CONTROL_PROTOCOL_TYPE ) >> cOCTPKT_HDR_FORMAT_PROTO_TYPE_LEN_MASK_CONTROL_PROTOCOL_TYPE_BIT_OFFSET;
	pPrivData->total_packet_size = (format_trace_proto_len & cOCTPKT_HDR_FORMAT_PROTO_TYPE_LEN_MASK_LENGTH ) >> cOCTPKT_HDR_FORMAT_PROTO_TYPE_LEN_MASK_LENGTH_BIT_OFFSET;
	pPrivData->pktHdt_size = offset;
	pPrivData->trace_flag = trace_flag;

	if(  pPrivData->total_packet_size < 46 )
		pPrivData->padding = 46 - pPrivData->total_packet_size;
	else
		pPrivData->padding = 0;

	/* Add summary display for the Vocallonet packet */
	if ( check_col( pinfo->cinfo, COL_INFO) )
	{
		col_add_fstr( pinfo->cinfo, COL_INFO,
		    "Format=%d, Size=%u bytes%s",
		    pPrivData->format,
		    pPrivData->total_packet_size,
		    pPrivData->trace_flag ? ", Trace" : "");
	}

	if ( tree )
	{

		/* create display subtree for the protocol */
		ti = proto_tree_add_item( tree, proto_octpkt, tvb, 0, offset, FALSE );
		octpkt_tree = proto_item_add_subtree(ti, ett_octpkt);

		/* Scroll back to the beginning of the header*/
		offset -=  sizeof(format_trace_proto_len);

		/* add the VocalloNet common fields to the UI */
		proto_tree_add_uint( octpkt_tree, hf_octpkt_format, tvb,
		    offset, 1, format_trace_proto_len );
		offset++;

		proto_tree_add_boolean( octpkt_tree, hf_octpkt_trace_flag, tvb,
		    offset, 1, format_trace_proto_len );

		offset++;

		proto_tree_add_uint( octpkt_tree, hf_octpkt_api_type, tvb,
		    offset, 1, format_trace_proto_len );

		proto_tree_add_uint( octpkt_tree, hf_octpkt_size, tvb,
		    offset, 2, format_trace_proto_len );
		offset+=2;
	}

	if (tvb_reported_length_remaining(tvb, offset) > 0)
	{
		tvb = tvb_new_subset(tvb, offset, -1, -1);

		switch( pPrivData->api_type )
		{
			case cOCTPKT_HDR_CONTROL_PROTOCOL_TYPE_ENUM_OCTVOCNET:

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

				if( vocallonet_handle )
					call_dissector(vocallonet_handle, tvb, pinfo, tree);
				else
					call_dissector(data_handle, tvb, pinfo, tree);
				break;

			case cOCTPKT_HDR_CONTROL_PROTOCOL_TYPE_ENUM_OCTMFA:	

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

				if( octmfa_handle )
					call_dissector(octmfa_handle, tvb, pinfo, tree);
				else
					call_dissector(data_handle, tvb, pinfo, tree);
				break;

			default:
				/* Dump the rest in raw format */
				call_dissector(data_handle, tvb, pinfo, tree);
				break;
		}
	}
}


/*************************************************************************
*
*  Code to register the protocol with Wireshark
*
**************************************************************************/
void proto_register_octpkt(void)
{
	/* Setup list of header fields */
	static hf_register_info hf_octpkt[] =
	{
		{ &hf_octpkt_format,
			{ "Format",           "octpkt.format",
			FT_UINT32, BASE_HEX, NULL, 0xff000000,
			"Packet format", HFILL }
		},
		{ &hf_octpkt_trace_flag,
			{ "Trace",           "octpkt.trace_flag",
			FT_BOOLEAN, 32, NULL, 0x00800000,
			"Debug trace flag", HFILL }
		},
		{ &hf_octpkt_api_type,
			{ "API Type",           "octpkt.api_type",
			FT_UINT32, BASE_HEX, VALS(octpkt_api_type_vals), 0x00007800,
			"API Type", HFILL }
		},

		{ &hf_octpkt_size,
			{ "Size",           "octpkt.size_in_bytes",
			FT_UINT32, BASE_DEC, NULL, 0x000007ff,
			"Total bit length", HFILL }
		}
	};

	/* Setup protocol subtree array */
	static gint* ett[] =
	{
		&ett_octpkt,
	};



	/* Register the protocol name and description */
	proto_octpkt = proto_register_protocol(	"OCTPKT Packets", "Octasic Packets", "octpkt");

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

/*************************************************************************
*
*  If this dissector uses sub-dissector registration add a registration routine.
*  This format is required because a script is used to find these routines and
*  create the code that calls these routines.
*
**************************************************************************/
void proto_reg_handoff_octpkt(void)
{
	dissector_handle_t octpkt_handle;

	data_handle = find_dissector("data");
	vocallonet_handle = find_dissector("vocallonet");
	octmfa_handle = find_dissector("octmfa");

	octpkt_handle = create_dissector_handle(dissect_octpkt, proto_octpkt);

	dissector_add_uint("ethertype", cOCTPKT_HDR_ETHERTYPE, octpkt_handle);

}

