Wireshark-dev: [Wireshark-dev] Rearranging packets
From: "Rach, Darshan" <DarshanR@xxxxxxx>
Date: Fri, 4 Dec 2009 13:24:27 +0530

Hi,

 

If data is split across packets, how to extract fields (from next packet) in continuation with the previous packet?

For example:

My full packet looks like this:

field 1

field 2

field 3

field 4

field 5

field 6

field 7

field 8

 

Initially, wireshark receives the following fragment only,

field 1

field 2

field 3

field 4

 

Then it receives this fragment,

field 5

field 6

field 7

field 8

 

What code changes need to be made (attached code file) to handle such a situation, where in parsing has to start from “Field 5” in the second packet.

 

I have followed all the guidelines for “Packet Reassembly” while coding. Still I am not able to parse the packet fragments properly.

Kindly help.

 



This message is confidential and intended only for the addressee. If you have received this message in error, please immediately notify the postmaster@xxxxxxx and delete it from your system as well as any copies. The content of e-mails as well as traffic data may be monitored by NDS for employment and security purposes.
To protect the environment please do not print this e-mail unless necessary.

An NDS Group Limited company. www.nds.com
/* packet-dash.c
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* 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 General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

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

#include <stdio.h>
#include <glib.h>
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/reassemble.h>
#include <epan/next_tvb.h>
#include <string.h>

#define PROTO_TAG_DASH	"DASH"
#define DEFAULT_OQTP_UDP_PORT (32772)

/* OQTP Packet Types */
#define OQTP_PACKET_OPCODE_RQ       (1)
#define OQTP_PACKET_OPCODE_BRQ      (2)
#define OQTP_PACKET_OPCODE_DATA     (3)
#define OQTP_PACKET_OPCODE_RESERVED (4)
#define OQTP_PACKET_OPCODE_ERROR    (5)

/* Wireshark ID of the DASH protocol */
static int proto_dash = -1;

/* These are the handles of our subdissectors */
static dissector_handle_t data_handle=NULL;
static dissector_handle_t dash_handle;

/* Function prototypes */
void proto_register_dash();
void proto_reg_handoff_dash();
static void msg_init_protocol();
void dissect_dash(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);

static int global_dash_port = DEFAULT_OQTP_UDP_PORT;

static gint hf_oqtp_opcode = -1;
static gint hf_oqtp_msgid = -1;
static gint hf_oqtp_last_packet_flag = -1;
static gint hf_oqtp_response_size = -1;
static gint hf_oqtp_data_packet_block_number = -1;
static gint hf_oqtp_error_code = -1;
static gint hf_oqtp_error_string = -1;
static gint hf_oqtp_root_path = -1;
static gint hf_oqtp_method = -1;
static gint hf_oqtp_reserved = -1;
static gint hf_catalogue_id = -1;
static gint hf_classif_id = -1;
static gint hf_direction = -1;
static gint hf_category_type = -1;
static gint hf_parental_rating = -1;
static gint hf_loc_classif_id = -1;
static gint hf_loc_order_num = -1;
static gint hf_loc_name_length = -1;
static gint hf_loc_name = -1;
static gint hf_request_satisfied = -1;
static gint hf_reserved_for_future_use = -1;
static gint hf_no_extended_pd_syntax = -1;
static gint hf_num_classifications = -1;
static gint hf_order_num = -1;
static gint hf_name_length = -1;
static gint hf_name = -1;
static gint hf_description_length = -1;
static gint hf_description = -1;
static gint hf_private_data_length = -1;
static gint hf_private_data_byte = -1;
static gint hf_x_private_data_length = -1;
static gint hf_x_private_data_byte = -1;
static gint hf_lang = -1;
static gint hf_skip_count = -1;
static gint hf_count = -1;
static gint hf_private_data_len = -1;
static gint hf_reserved_bits = -1;

/* These are the ids of the subtrees that we may be creating */
static gint ett_oqtp_opcode = -1;
static gint ett_oqtp_msgid = -1;
static gint ett_oqtp_last_packet_flag = -1;
static gint ett_oqtp_response_size = -1;
static gint ett_oqtp_data_packet_block_number = -1;
static gint ett_oqtp_error_code = -1;
static gint ett_oqtp_error_string = -1;
static gint ett_oqtp_root_path = -1;
static gint ett_oqtp_method = -1;
static gint ett_oqtp_reserved = -1;
static gint oqtp_subtree_1 = -1;

static const value_string packettypenames[] = {
	{ 1, "RQ - Call" },
	{ 2, "BRQ - Burst Call" },
	{ 3, "DATA" },
	{ 4, "RESERVED" },
	{ 5, "ERROR" },
    { 0, NULL }
};

static const value_string methodtypenames[] = {
	{ 1, "RQ - Call" },
	{ 2, "BRQ - Burst Call" },
	{ 3, "DATA" },
	{ 4, "RESERVED" },
	{ 5, "ERROR" },
    { 0, NULL }
};

static const value_string reserved_field_coding[] = {
    { 1, "fragment" },
    { 2, "last_fragment" },
    { 0, NULL }
};

static const value_string direction_field_coding[] = {
    { 0, "Forwards" },
    { 1, "Backwards" }
};

static int hf_msg_fragments = -1;
static int hf_msg_fragment = -1;
static int hf_msg_fragment_overlap = -1;
static int hf_msg_fragment_overlap_conflicts = -1;
static int hf_msg_fragment_multiple_tails = -1;
static int hf_msg_fragment_too_long_fragment = -1;
static int hf_msg_fragment_error = -1;
static int hf_msg_reassembled_in = -1;

static gint ett_msg_fragment = -1;
static gint ett_msg_fragments = -1;

static const fragment_items msg_frag_items = {
	/* Fragment subtrees */
	&ett_msg_fragment,
	&ett_msg_fragments,
	/* Fragment fields */
	&hf_msg_fragments,
	&hf_msg_fragment,
	&hf_msg_fragment_overlap,
	&hf_msg_fragment_overlap_conflicts,
	&hf_msg_fragment_multiple_tails,
	&hf_msg_fragment_too_long_fragment,
	&hf_msg_fragment_error,
	/* Reassembled in field */
	&hf_msg_reassembled_in,
	/* Tag */
	"Message fragments"
};

/* OQTP protocol subtree array */
static gint *oqtp_subtree_array[] = {
	&ett_oqtp_opcode,
	&ett_oqtp_last_packet_flag,
	&ett_oqtp_msgid,
	&ett_oqtp_response_size,
	&ett_oqtp_data_packet_block_number,
	&ett_oqtp_error_code,
	&ett_oqtp_error_string,
	&ett_oqtp_root_path,
	&ett_oqtp_method,
	&ett_oqtp_reserved,
	&oqtp_subtree_1,
	/* Fragment subtrees */
	&ett_msg_fragment,
	&ett_msg_fragments
};

/* OQTP packet fields */
static hf_register_info hf_oqtp[] = {
	{&hf_oqtp_opcode,
	{"Opcode", "oqtp.opcode",FT_UINT16, BASE_DEC,NULL, 0x0,
	 "Packet Type --> 1 - RQ ; 2 - BRQ ; 3 - DATA ; 4 - Reserved ; 5 - ERROR", HFILL}},
	{&hf_oqtp_reserved,
	{"Reserved", "oqtp.reserved",FT_UINT8, BASE_DEC,NULL, 0x0,
	 "Reserved for future use", HFILL}},
	{&hf_oqtp_last_packet_flag,
	{"Last Packet Flag", "oqtp.last_packet_flag",FT_UINT8, BASE_DEC,NULL, 0x0,
	 "Last packet in response group", HFILL}},
	{&hf_oqtp_msgid,
	{"Message ID", "oqtp.msg_id",FT_UINT16, BASE_DEC,NULL, 0x0,
	 "Message ID used to match request & response", HFILL}},
	{&hf_oqtp_response_size,
	{"Response Size", "oqtp.response_size",FT_UINT16, BASE_DEC,NULL, 0x0,
	 "Response Size for response data to use within DATA responses", HFILL}},
	{&hf_oqtp_data_packet_block_number,
	{"Block Number", "oqtp.block_number",FT_UINT16, BASE_DEC,NULL, 0x0,
	 "Block Number", HFILL}},
	{&hf_oqtp_error_code,
	{"Error code", "oqtp.error_code",FT_UINT16, BASE_DEC,NULL, 0x0,
	 "Error code", HFILL}},
	{&hf_oqtp_error_string,
	{"Error String", "oqtp.error_string",FT_STRINGZ, BASE_CUSTOM,NULL, 0x0,
	 "Error String", HFILL}},
	{&hf_oqtp_root_path,
	{"Root Path", "oqtp.root_path",FT_STRING, BASE_CUSTOM,NULL, 0x0,
	 "Root Path", HFILL}},
	{&hf_oqtp_method,
	{"Method", "oqtp.method",FT_STRING, BASE_CUSTOM,NULL, 0x0,
	 "Class & Method", HFILL}},
	{&hf_catalogue_id,
	{"Catalogue ID","oqtp.catalogue_id",FT_UINT16, BASE_DEC,NULL, 0x0,
	 "Catalogue ID", HFILL}},
	{&hf_classif_id,
	{"Classification ID","oqtp.classif_id",FT_UINT16, BASE_DEC,NULL, 0x0,
	 "Classification ID", HFILL}},
	{&hf_direction,
	{"Direction","oqtp.direction",FT_UINT8, BASE_DEC,NULL, 0x0,
	 "Direction", HFILL}},
	{&hf_category_type,
	{"Category Type","oqtp.category_type",FT_UINT8, BASE_DEC,NULL, 0x0,
	 "Category Type", HFILL}},
	{&hf_parental_rating,
	{"Parental Rating","oqtp.parental_rating",FT_UINT8, BASE_DEC,NULL, 0x0,
	 "Parental Rating", HFILL}},
	{&hf_loc_classif_id,
	{"Locator Classification ID","oqtp.loc_classif_id",FT_UINT16, BASE_DEC,NULL, 0x0,
	 "Locator Classification ID", HFILL}},
	{&hf_loc_order_num,
	{"Order Number","oqtp.loc_order_num",FT_UINT8, BASE_DEC,NULL, 0x0,
	 "Order Number", HFILL}},
	{&hf_loc_name_length,
	{"Location Name Length","oqtp.loc_name_length",FT_UINT8, BASE_DEC,NULL, 0x0,
	 "Location Name Length", HFILL}},
	{&hf_loc_name,
	{"Location Name","oqtp.loc_name",FT_STRING, BASE_CUSTOM,NULL, 0x0,
	 "Location Name", HFILL}},
	{&hf_request_satisfied,
	{"Request Satisfied","oqtp.request_satisfied",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Request Satisfied", HFILL}},
	{&hf_reserved_for_future_use,
	{"Reserved For Future Use","oqtp.reserved_for_future_use",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Request Satisfied", HFILL}},
	{&hf_no_extended_pd_syntax,
	{"No Extended pd syntax","oqtp.no_extended_pd_syntax",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "No Extended pd syntax", HFILL}},
	{&hf_num_classifications,
	{"Number of classifications","oqtp.num_classifications",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Number of classifications", HFILL}},
	{&hf_order_num,
	{"Order Number","oqtp.order_num",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Order Number", HFILL}},
	{&hf_name_length,
	{"Name Length","oqtp.name_length",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Name Length", HFILL}},
	{&hf_name,
	{"Classification Name","oqtp.name",FT_STRING, BASE_CUSTOM, NULL, 0x0,
	 "Classification Name", HFILL}},
	{&hf_description_length,
	{"Description Length","oqtp.description_length",FT_UINT16, BASE_DEC, NULL, 0x0,
	 "Description Length", HFILL}},
	{&hf_description,
	{"Description","oqtp.description",FT_STRING, BASE_CUSTOM, NULL, 0x0,
	 "Description", HFILL}},
	{&hf_private_data_length,
	{"Private Data Length","oqtp.private_data_length",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Private Data Length", HFILL}},
	{&hf_private_data_byte,
	{"Private Data Byte","oqtp.private_data_byte",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Private Data Byte", HFILL}},
	{&hf_x_private_data_length,
	{"x Private Data Length","oqtp.x_private_data_length",FT_UINT16, BASE_DEC, NULL, 0x0,
	 "x Private Data Length", HFILL}},
	{&hf_x_private_data_byte,
	{"Private Data","oqtp.x_private_data_byte",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Private Data", HFILL}},
	{&hf_lang,
	{"Language Code","oqtp.language_code",FT_STRING, BASE_CUSTOM, NULL, 0x0,
	 "Language Code", HFILL}},
	{&hf_skip_count,
	{"Skip Count","oqtp.skip_count",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Skip Count", HFILL}},
	{&hf_count,
	{"Count","oqtp.count",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Count", HFILL}},
	{&hf_private_data_len,
	{"Private Data Length","oqtp.private_data_len",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Private Data Length", HFILL}},
	{&hf_reserved_bits,
	{"Reserved Bits","oqtp.reserved_bits",FT_UINT8, BASE_DEC, NULL, 0x0,
	 "Reserved Bits", HFILL}},
	 /*
	 * Short Message fragment reassembly
	 */
	 {&hf_msg_fragments,
	 {"Message fragments", "msg.fragments",
	  FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
	 {&hf_msg_fragment,
	 {"Message fragment", "msg.fragment",
	  FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
	 {&hf_msg_fragment_overlap,
	 {"Message fragment overlap", "msg.fragment.overlap",
	  FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
	 {&hf_msg_fragment_overlap_conflicts,
	 {"Message fragment overlapping with conflicting data","msg.fragment.overlap.conflicts",
	  FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
	 {&hf_msg_fragment_multiple_tails,
	 {"Message has multiple tail fragments","msg.fragment.multiple_tails",
	  FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
	 {&hf_msg_fragment_too_long_fragment,
	 {"Message fragment too long", "msg.fragment.too_long_fragment",
	  FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
	 {&hf_msg_fragment_error,
	 {"Message defragmentation error", "msg.fragment.error",
	  FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
	 {&hf_msg_reassembled_in,
	 {"Reassembled in", "msg.reassembled.in",
	  FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }

};

/*Hash tables are declared, and these are initialised in the following protocol initialisation routine*/
static GHashTable *msg_fragment_table = NULL;
static GHashTable *msg_reassembled_table = NULL;

static void msg_init_protocol(void)
{
	fragment_table_init(&msg_fragment_table);
	reassembled_table_init(&msg_reassembled_table);
}

/* This is called by Wireshark plugin manager when to allow the plugin initialise its dissector*/
void proto_reg_handoff_dash(void)
{
	static gboolean initialized=FALSE;

	if (!initialized)
	{
		data_handle = find_dissector("data");
		dash_handle = create_dissector_handle(dissect_dash, proto_dash);
		dissector_add("udp.port", global_dash_port, dash_handle);
		initialized=TRUE;
	}
}

/* This function is called by the Wireshark Plugin manager at start-up to allow
the plugin register itself to wireshark*/
void proto_register_dash (void)
{
	/* A header field is something you can search/filter on.
	* We create a structure to register our fields. It consists of an
	* array of hf_register_info structures, each of which are of the format
	* {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}.
	*/

	proto_dash = proto_register_protocol ("DASH Protocol", "DASH", "dash");
	proto_register_field_array (proto_dash, hf_oqtp, array_length (hf_oqtp));
	proto_register_subtree_array (oqtp_subtree_array, array_length (oqtp_subtree_array));
	register_dissector("dash", dissect_dash, proto_dash);

	register_init_routine(msg_init_protocol);
}


static void dissect_dash(tvbuff_t *tvb, packet_info *pkt, proto_tree *tree)
{
	fragment_data *frag_msg = NULL;
    tvbuff_t *new_tvb = NULL;
    tvbuff_t *next_tvb = NULL;

	if (check_col(pkt->cinfo, COL_PROTOCOL))
		col_set_str(pkt->cinfo, COL_PROTOCOL, PROTO_TAG_DASH);

	/* Clear out stuff in the info column */
	if(check_col(pkt->cinfo,COL_INFO)){
		col_clear(pkt->cinfo,COL_INFO);
	}

	if (tree)
	{
		proto_item *trunk_proto_tree = NULL;
		proto_tree *oqtp_tree = NULL;
		proto_item *opcode_item=NULL;
		proto_item *direction_item=NULL;
		gboolean    save_fragmented;
		int packet_field_offset = 0, block_number = 0, reserved_bits = 0;
		gint root_path_start_offset = 0, root_path_end_offset = 0, oqtp_method_end_offset = 0, gl_method = 0;
		guint8 reserved = 0, last_packet_flag = 0, request_satisfied = 0, direction = 0, category_type = 0;
		guint8 reserved_for_future_use = 0, no_extended_pd_syntax = 0, loc_name_length =0, name_length = 0;
		guint8 private_data_len = 0;
		guint16 opcode = 0, msgid = 0, loc_classif_id = 0, private_data_length = 0;
		guint16 num_classifications = 0, description_length = 0, x_private_data_length = 0;
		guint16 loop_index = 0, index = 0;

		/* Adding an item for OQTP in the trunk i.e the main branch which
		   contains protocols like Ethernet, IP, UDP. OQTP is now another sibling
		   here. The trunk_proto_tree contains reference to the main tree.
		*/
		trunk_proto_tree = proto_tree_add_item(tree, proto_dash, tvb, 0, -1, FALSE);

		/* Create a sub-tree now, which contains the dissected details of the
		   OQTP packets */
		oqtp_tree = proto_item_add_subtree(trunk_proto_tree, oqtp_subtree_1);

		/* Now add the fields as items under the sub-tree */
		opcode_item = proto_tree_add_item(oqtp_tree, hf_oqtp_opcode, tvb, packet_field_offset, 2, FALSE);

		/* Retrieve the OQTP packet opcode */
		opcode = tvb_get_ntohs(tvb, packet_field_offset);
		packet_field_offset += 2;

		/*Display Opcode type next to the number*/
		proto_item_append_text(opcode_item, ", %s", val_to_str(opcode, packettypenames, "Unknown (0x%02x)"));

		/*2-lines commented by darshan. Because, Reserved is interpreted in a different way here
		reserved = tvb_get_guint8(tvb, packet_field_offset);
		proto_tree_add_uint(oqtp_tree, hf_oqtp_reserved, tvb, packet_field_offset, 1, ((reserved & 0x80) >> 7));*/

		last_packet_flag = tvb_get_guint8(tvb, packet_field_offset);
		proto_tree_add_uint(oqtp_tree, hf_oqtp_last_packet_flag, tvb, packet_field_offset, 1, ((last_packet_flag & 0x80) >> 7));

		/* If packet is of OQTP Data packet Type */
		/*if(OQTP_PACKET_OPCODE_DATA == opcode)
		{
			proto_item_append_text(oqtp_tree, ", %s",
								   val_to_str(1, reserved_field_coding, "Unknown (0x%02x)"));
		}*/

		/* Extract the msgid field */
		msgid = ((tvb_get_ntohs(tvb, packet_field_offset)) & 0x7FFF);

		/* Set the OQTP message id */
		proto_tree_add_uint(oqtp_tree, hf_oqtp_msgid, tvb, packet_field_offset, 2, msgid);
		packet_field_offset += 2;

		switch(opcode)
		{
			case OQTP_PACKET_OPCODE_RQ:
			case OQTP_PACKET_OPCODE_BRQ:
				/* Maximum response size that the requestor can handle */
				proto_tree_add_item(oqtp_tree, hf_oqtp_response_size, tvb, packet_field_offset, 2, FALSE);
				packet_field_offset += 2;

				/* Parse to find the root path and display as /VOD/ for example */
				root_path_start_offset = tvb_find_guint8(tvb, packet_field_offset, -1, '/');
				root_path_end_offset = tvb_find_guint8(tvb, root_path_start_offset + 1, -1, '/');

				proto_tree_add_item(oqtp_tree, hf_oqtp_root_path, tvb, root_path_start_offset, ((root_path_end_offset - root_path_start_offset) + 1), FALSE);
				packet_field_offset = root_path_end_offset + 1;

				oqtp_method_end_offset = tvb_find_guint8(tvb, packet_field_offset, -1, '/');
				proto_tree_add_item(oqtp_tree, hf_oqtp_method, tvb, packet_field_offset, (oqtp_method_end_offset - packet_field_offset), FALSE);

				//gl_method = tvb_find_guint8(tvb, packet_field_offset, -1, "GL");
				if((tvb_strneql(tvb, packet_field_offset, "AIGL", 4) == 0) ||
				   (tvb_strneql(tvb, packet_field_offset, "CIGL", 4) == 0))
				{
					packet_field_offset += 5; //move the offset of method name. For eg AIGL/

					/*CATALOGUE ID*/
					proto_tree_add_item(oqtp_tree, hf_catalogue_id, tvb, packet_field_offset, 2, FALSE);
					packet_field_offset += 2;

					/*CLASSIFICATION ID*/
					proto_tree_add_item(oqtp_tree, hf_classif_id, tvb, packet_field_offset, 2, FALSE);
					packet_field_offset += 2;

					/*DIRECTION*/
					direction = tvb_get_guint8(tvb, packet_field_offset);
					direction_item = proto_tree_add_uint(oqtp_tree, hf_direction, tvb, packet_field_offset, 1, ((direction & 0x80) >> 7));

					/*Category Type*/
					category_type = ((tvb_get_ntohs(tvb, packet_field_offset)) & 0x7F);
					proto_tree_add_uint(oqtp_tree, hf_category_type, tvb, packet_field_offset, 1, category_type);
					packet_field_offset += 1;

					/*Parental Rating*/
					proto_tree_add_item(oqtp_tree, hf_parental_rating, tvb, packet_field_offset, 1, FALSE);
					packet_field_offset += 1;

					/*Locator Classification ID*/
					proto_tree_add_item(oqtp_tree, hf_loc_classif_id, tvb, packet_field_offset, 2, FALSE);
					loc_classif_id = tvb_get_ntohs(tvb, packet_field_offset);
					packet_field_offset += 2;

					if(loc_classif_id != 0)
					{
						/*Order Number*/
						proto_tree_add_item(oqtp_tree, hf_loc_order_num, tvb, packet_field_offset, 1, FALSE);
						packet_field_offset += 1;

						/*Location Name Length*/
						proto_tree_add_item(oqtp_tree, hf_loc_name_length, tvb, packet_field_offset, 1, FALSE);
						loc_name_length = tvb_get_guint8(tvb, packet_field_offset);
						packet_field_offset += 1;

						/*Location Name*/
						if(loc_name_length != 0)
						{
							proto_tree_add_item(oqtp_tree, hf_loc_name, tvb, packet_field_offset + 1, loc_name_length - 1,FALSE);
							packet_field_offset = packet_field_offset + loc_name_length;
						}
						else if(loc_name_length == 0)
						{
							proto_tree_add_item(oqtp_tree, hf_loc_name, tvb, packet_field_offset + 1, loc_name_length ,FALSE);
							packet_field_offset = packet_field_offset + loc_name_length + 1;
						}
					}

					/*language code*/
					proto_tree_add_item(oqtp_tree, hf_lang, tvb, packet_field_offset, 3, FALSE);
					packet_field_offset += 3;

					/*skip_count*/
					proto_tree_add_item(oqtp_tree, hf_skip_count, tvb, packet_field_offset, 1, FALSE);
					packet_field_offset += 1;

					/*count*/
					proto_tree_add_item(oqtp_tree, hf_count, tvb, packet_field_offset, 1, FALSE);
					packet_field_offset += 1;

					/*Private Data Length*/
					proto_tree_add_item(oqtp_tree, hf_private_data_len, tvb, packet_field_offset, 1, FALSE);
					private_data_len = tvb_get_guint8(tvb, packet_field_offset);
					packet_field_offset += 1;

					for(index = 0 ; index < private_data_len; ++index)
					{
						/*private_data_byte*/
						proto_tree_add_item(oqtp_tree, hf_private_data_byte, tvb, packet_field_offset, 1, FALSE);
						packet_field_offset += 1;
					}

					/*if((reserved_bits = (packet_field_offset % 8)) != 0)
					{
						fprintf(stderr,"packet_field_offset: %d\n Reserved bits: %d\n",packet_field_offset,reserved_bits );
						for(index = 0 ; index < reserved_bits; ++index)
						{
							//reserved for future use
							proto_tree_add_item(oqtp_tree, hf_reserved_bits, tvb, packet_field_offset, 1, FALSE);
							packet_field_offset += 1;
						}
					}*/

				}

				break;
			case OQTP_PACKET_OPCODE_DATA:

				/* Extract the data packet block number */
				proto_tree_add_item(oqtp_tree, hf_oqtp_data_packet_block_number, tvb, packet_field_offset, 2, FALSE);
				block_number = tvb_get_ntohs(tvb, packet_field_offset);
				packet_field_offset += 2;

				/*save the fragmented state of this packet, so we can restore it later.*/
				save_fragmented = pkt->fragmented;

				/* Multiple packets in response - last_packet_flag field is the last packet flag */
				if(((block_number == 0) && (last_packet_flag == 0)) ||
				   (block_number > 0))
				{
					/*darshan*/
					pkt->fragmented = TRUE;

					frag_msg = fragment_add_seq_check(tvb, packet_field_offset, pkt,
													  msgid, /* ID for fragments belonging together */
													  msg_fragment_table, /* list of message fragments */
													  msg_reassembled_table, /* list of reassembled messages */
													  block_number, /* fragment sequence number */
													  tvb_length_remaining(tvb, packet_field_offset), /* fragment length - to the end */
													  !last_packet_flag); /* More fragments? */

					new_tvb = process_reassembled_data(tvb, packet_field_offset, pkt,
													   "Reassembled OQTP Message",
													   frag_msg,
													   &msg_frag_items,
													   NULL,
													   oqtp_tree);

					/* Reassembled */
					if (frag_msg)
					{
						col_append_str(pkt->cinfo, COL_INFO,
									   "(Reassembled OQTP Response)");
					}
					else
					{
						/* Not last packet of reassembled short message */
						col_append_fstr(pkt->cinfo, COL_INFO,
										"(OQTP fragment %u)", block_number);
					}

					if (new_tvb) /* take it all */
					{
						next_tvb = new_tvb;
					}
					else
					{
						/* make a new subset */
						next_tvb = tvb_new_subset(tvb, packet_field_offset, -1, -1);
					}
				}
				else
				{
					next_tvb = tvb_new_subset(tvb, packet_field_offset, -1, -1);
				}

				/*restoring fragmented state*/
				pkt->fragmented = save_fragmented;

				/*Request Satisfied*/
				request_satisfied = tvb_get_guint8(tvb, packet_field_offset);
				proto_tree_add_uint(oqtp_tree, hf_request_satisfied, tvb, packet_field_offset, 1, ((request_satisfied & 0x80) >> 7));

				/*Reserved_for_future_use*/
				reserved_for_future_use = ((tvb_get_guint8(tvb, packet_field_offset)& 0x7E) >> 1);
				proto_tree_add_uint(oqtp_tree, hf_reserved_for_future_use, tvb, packet_field_offset, 1, reserved_for_future_use );

				/*No Extended pd syntax*/
				no_extended_pd_syntax = (tvb_get_guint8(tvb, packet_field_offset) & 0x1);
				proto_tree_add_uint(oqtp_tree, hf_no_extended_pd_syntax, tvb, packet_field_offset, 1, no_extended_pd_syntax );
				packet_field_offset += 1;

				/*Number of classifications*/
				proto_tree_add_item(oqtp_tree, hf_num_classifications, tvb, packet_field_offset, 1, FALSE);
				num_classifications = tvb_get_guint8(tvb, packet_field_offset);
				packet_field_offset += 1;

				for(loop_index = 0 ; loop_index < num_classifications ; ++loop_index)
				{
					/*CLASSIFICATION ID*/
					proto_tree_add_item(oqtp_tree, hf_classif_id, tvb, packet_field_offset, 2, FALSE);
					packet_field_offset += 2;

					/*Category Type*/
					proto_tree_add_item(oqtp_tree, hf_category_type, tvb, packet_field_offset, 1, FALSE);
					packet_field_offset += 1;

					/*Order Number*/
					proto_tree_add_item(oqtp_tree, hf_order_num, tvb, packet_field_offset, 1, FALSE);
					packet_field_offset += 1;

					/*parental_rating*/
					proto_tree_add_item(oqtp_tree, hf_parental_rating, tvb, packet_field_offset, 1, FALSE);
					packet_field_offset += 1;

					/*Name Length*/
					proto_tree_add_item(oqtp_tree, hf_name_length, tvb, packet_field_offset, 1, FALSE);
					name_length = tvb_get_guint8(tvb, packet_field_offset);
					packet_field_offset += 1;

					/*name*/
					proto_tree_add_item(oqtp_tree, hf_name, tvb, packet_field_offset + 1, name_length ,FALSE);
					packet_field_offset = packet_field_offset + name_length;

					/*Description Length*/
					proto_tree_add_item(oqtp_tree, hf_description_length, tvb, packet_field_offset, 2, FALSE);
					description_length = tvb_get_ntohs(tvb, packet_field_offset);
					packet_field_offset += 2;

					fprintf (stderr, "Description Name length:%d\n", description_length);

					/*Description*/
					proto_tree_add_item(oqtp_tree, hf_description, tvb, packet_field_offset + 1, description_length - 1,FALSE);
					packet_field_offset = packet_field_offset + description_length;

					/*private_data_length*/
					proto_tree_add_item(oqtp_tree, hf_private_data_length, tvb, packet_field_offset, 1, FALSE);
					private_data_length = tvb_get_guint8(tvb, packet_field_offset);
					packet_field_offset += 1;

					for(index = 0 ; index < private_data_length ; ++index)
					{
						/*private_data_byte*/
						proto_tree_add_item(oqtp_tree, hf_private_data_byte, tvb, packet_field_offset, 1, FALSE);
						packet_field_offset += 1;
					}

					if(!no_extended_pd_syntax)
					{
						/*Private Data Length*/
						proto_tree_add_item(oqtp_tree, hf_x_private_data_length, tvb, packet_field_offset, 2, FALSE);
						x_private_data_length = tvb_get_ntohs(tvb, packet_field_offset);
						packet_field_offset += 2;

						for(index = 0 ; index < x_private_data_length ; ++index)
						{
							/*x_private_data_byte*/
							proto_tree_add_item(oqtp_tree, hf_x_private_data_byte, tvb, packet_field_offset, 1, FALSE);
							packet_field_offset += 1;
						}

					}
				}

				break;
			case OQTP_PACKET_OPCODE_ERROR:
			{
				int error_string_length = 0;
				char *error_string = NULL;

				/* Extract the error code */
				proto_tree_add_item(oqtp_tree, hf_oqtp_error_code, tvb, packet_field_offset, 2, FALSE);
				packet_field_offset += 2;

				/* Get the error string */
				error_string = tvb_get_stringz(tvb, packet_field_offset, &error_string_length);

				/* Display the error string */
				if(error_string)
					proto_tree_add_string(oqtp_tree, hf_oqtp_error_string, tvb, packet_field_offset, error_string_length, (const char *)error_string);
			}
				break;
			default:
				break;
        }

	}
}