Ethereal-dev: [Ethereal-dev] New OSI Session dissector.

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: "Sid Sid" <ysidelnikov@xxxxxxxxxxx>
Date: Mon, 27 Oct 2003 11:07:17 +0000
Hi,

I've added some additional checking and used a value_string table where it makes sense.
Fixed casting to void and so on.

Thanks.
Yuriy.




From: Guy Harris <guy@xxxxxxxxxxxx>
To: Sid Sid <ysidelnikov@xxxxxxxxxxx>
CC: ethereal-dev@xxxxxxxxxxxx
Subject: Re: [Ethereal-dev] New OSI Session dissector.
Date: Fri, 26 Sep 2003 15:57:28 -0700


On Sep 25, 2003, at 1:01 PM, Sid Sid wrote:

Please, have a look at attachment.

It returns FALSE even if the packet is a session packet, except when it appears to return a number rather than a true/false value.

The only check it does is to check whether the packet is at least 4 bytes long; that's not enough - that means that it could accept packets that aren't session-layer packets, which means that other heuristic dissectors for COTP, such as the SMB dissector, might not get a chance to check whether the packet is one of theirs.

If it's not possible to have a good heuristic to check for OSI Session packets, perhaps the COTP dissector should try its heuristics and, if none of them match, try the session dissector.

It also casts "dissect_ses" to a "void *", which hides the compiler errors that would have detected the original problem. Remove those casts, and either fix or remove the lines that get errors or warnings as a result of that change. (All the lines I saw could just be removed.)

Note also that you have a number of places where you do a "switch()" on some value and select a constant string based on the value; that's probably best done using a value_string table - especially if the value has a field associated with it, because you can then associate that value_string table with the field.

_______________________________________________
Ethereal-dev mailing list
Ethereal-dev@xxxxxxxxxxxx
http://www.ethereal.com/mailman/listinfo/ethereal-dev

_________________________________________________________________
MSN 8 helps eliminate e-mail viruses. Get 2 months FREE*. http://join.msn.com/?page=features/virus
/* packet-ses.c
*
* Routine to dissect ISO 8327-1 OSI Session Protocol packets
*
* $Id: packet-ses.c,v 1.00 2003/09/01 21:00:36
*
* Yuriy Sidelnikov <YSidelnikov@xxxxxxxxxxx>
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@xxxxxxxxxxxx>
* Copyright 1998 Gerald Combs
*
* 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 <glib.h>
#include <epan/packet.h>

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

#include "packet-tpkt.h"
#include "packet-ses.h"
#include "packet-frame.h"
#include "prefs.h"

#include <epan/strutil.h>
#include "etypes.h"





/* ses header fields             */
static int proto_ses          = -1;
static int hf_ses_version     = -1;
static int hf_ses_reserved    = -1;
static int hf_ses_length      = -1;
static proto_tree *ses_tree = NULL;
/* ses fields defining a sub tree */
static gint ett_ses           = -1;

/* ----------------------------------------------------------------------------------------------------------*/
static dissector_handle_t pres_handle = NULL;
/* ----------------------------------------------------------------------------------------------------------*/


/* flags */
static int hf_connect_protocol_options_flags = -1;
static int hf_session_user_req_flags = -1;
static int hf_version_number_options_flags = -1;
static int hf_enclosure_item_options_flags = -1;
static int hf_token_item_options_flags = -1;


static gint ett_connect_protocol_options_flags = -1;
static gint ett_protocol_version_flags = -1;
static gint ett_enclosure_item_flags = -1;
static gint ett_token_item_flags = -1;
static gint ett_ses_req_options_flags = -1;

static int able_to_receive_extended_concatenated_SPDU = -1;
static int half_duplex_function_unit = -1;
static int duplex_function_unit= -1;
static int session_exception_report= -1;
static int data_separation_function_unit= -1;
static int symmetric_syncronize_function_unit= -1;
static int typed_data_function_unit= -1;
static int exception_function_unit= -1;
static int negotiated_relese_function_unit= -1;
static int activity_management_function_unit= -1;
static int resyncronize_function_unit= -1;
static int major_resyncronize_function_unit= -1;
static int minor_resyncronize_function_unit= -1;
static int expedited_data_resyncronize_function_unit= -1;
static int capability_function_unit=-1;

/* protocol version */
static int protocol_version_1 = -1;
static int protocol_version_2 = -1;

/*  enclosure item */
static int beginning_of_SSDU = -1;
static int end_of_SSDU = -1;

/* token item */
static int release_token = -1;
static int major_activity_token = -1;
static int syncronize_minor_token = -1;
static int data_token = -1;

static const value_string ses_vals[] =
{
 {SES_CONNECTION_REQUEST,  "Connection request PDU" },
 {SES_CONNECTION_ACCEPT,    "Connection accept PDU"   },
 {SES_EXCEPTION_REPORT,    "Exception report PDU"   },
 {SES_DATA_TRANSFER,  "Data transfer PDU" },
 {SES_PLEASE_TOKENS,    "Please tokens PDU"   },
 {SES_EXPEDITED,    "Expedited PDU"   },
 {SES_PREPARE,    "Prepare PDU"   },
 {SES_NOT_FINISHED,    "Not finished PDU"   },
 {SES_FINISH,    "Finish PDU"   },
 {SES_DISCONNECT,    "Disconnect PDU"   },
 {SES_REFUSE,    "Refuse PDU"   },
 {SES_CONNECTION_DATA_OVERFLOW,    "Data overflow PDU"   },
 {SES_OVERFLOW_ACCEPT,    "Overflow accept PDU"   },
 {SES_GIVE_TOKENS_CONFIRM,    "Tokens confirm PDU"   },
 {SES_GIVE_TOKENS_ACK,    "Give tokens ACK PDU"   },
 {SES_ABORT,    "Abort PDU"   },
 {SES_ABORT_ACCEPT,    "Abort accept PDU"   },
 {SES_ACTIVITY_RESUME,    "Activity resume PDU"   },
 {SES_TYPED_DATA,    "Typed data PDU"   },
 {SES_RESYNCHRONIZE_ACK,    "Resynchronize ACK PDU"   },
 {SES_MAJOR_SYNC_POINT,    "Session major sync point PDU"   },
 {SES_MAJOR_SYNC_ACK,    "Session major sync ACK PDU"   },
 {SES_ACTIVITY_START,    "Activity start PDU"   },
 {SES_EXCEPTION_DATA,    "Exception data PDU"   },
 {SES_MINOR_SYNC_POINT,    "Minor sync point PDU"   },
 {SES_MINOR_SYNC_ACK,    "Minor sync ACK PDU"   },
 {SES_RESYNCHRONIZE,    "Resynchronize PDU"   },
 {SES_ACTIVITY_DISCARD,    "Activity discard PDU"   },
 {SES_ACTIVITY_DISCARD_ACK,    "Activity discard ACK PDU"   },
 {SES_CAPABILITY,    "Capability PDU"   },
 {SES_CAPABILITY_DATA_ACK,    "Capability data ACK PDU"   },
 {0,             NULL           }
};

static const value_string reason_vals[] =
{
{reason_not_specified, "Reason Code: Rejection by called SS-user; reason not specified" }, {temporary_congestion, "Reason Code: Rejection by called SS-user due to temporary congestion" },
 {Subsequent,    "Reason Code: Rejection by called SS-user."   },
 {Session_Selector_unknown,  "Reason Code: Session Selector unknown" },
{SS_user_not_attached_to_SSAP, "Reason Code: SS-user not attached to SSAP" }, {SPM_congestion_at_connect_time, "Reason Code: SPM congestion at connect time" }, {versions_not_supported, "Reason Code: Proposed protocol versions not supported" }, {SPM_reason_not_specified, "Reason Code: Rejection by the SPM; reason not specified" },
 {SPM_implementation_restriction,    "Finish PDU"   },
{SES_DISCONNECT, "Reason Code: Rejection by the SPM; implementation restriction stated in the PICS" },
 {0,             NULL           }
};

/* desegmentation of OSI over ses  */
/*static gboolean ses_desegment = TRUE;*/


/* find the dissector for data */
static dissector_handle_t data_handle;

/*static struct SES_PDU* reply_pdu;*/

/* function declaration */
int print_item(struct PGI_PI_UNIT* parms,tvbuff_t *tvb,int offset,proto_tree *tree,packet_info *pinfo);


char * string_to_hex(unsigned char * in,char * out,int len)
{
	char ascii[MAXSTRING];
	int i;
	memset(&ascii,0x00,sizeof(ascii));
for(i=0;i<len;i++)
			{
	unsigned char o_out = *(in+i);
   sprintf(out+(i<<1),"%.2x",*  (in+i));
	if(  ( (o_out) >= 'a') & ( (o_out) <='z')  ||
		 ( (o_out) >= 'A') & ( (o_out) <='Z')  ||
		 ( (o_out) >= '0') & ( (o_out) <='9')
	   )
					{
					ascii[i] = o_out;
					}
				else
					{
					ascii[i] = '.';
					}

			}

		strcat(out," ");
		strcat(out,ascii);
   return out;
}

/* this program returns length of session PDU */
int get_item_len(struct PGI_PI_UNIT* unit)
{
  		if( unit->len == TWO_BYTE_LEN)
		{
			struct CHAR_SHORT item_len;
			item_len.data[0] = *( (((char*)(unit)) +2 ));
			item_len.data[1] = *( (((char*)(unit)) +3 ));
			return g_ntohs( item_len.short_data    );
		}

		return unit->len;

}
/* this program returns address of next PGI/PI   */
struct PGI_PI_UNIT* get_data_address(struct PGI_PI_UNIT* parms)
{

		   		if( parms->len == TWO_BYTE_LEN)
					{
						return (struct PGI_PI_UNIT*) &parms->data1;
					}
				else
					{
						return (struct PGI_PI_UNIT*)&parms->data;
					}

}

/* this program returns address of next PI item   */
struct PGI_PI_UNIT* get_next_PI(struct PGI_PI_UNIT* parms)
{

		   		if( parms->len == TWO_BYTE_LEN)
					{
						return (struct PGI_PI_UNIT*)  (&parms->data1+get_item_len(parms) );
					}
				else
					{
						return (struct PGI_PI_UNIT*)  (&parms->data+get_item_len(parms) );
					}

}

int   get_len_len(struct PGI_PI_UNIT* parms)
{

		   		if( parms->len == TWO_BYTE_LEN)
					{

							return 4;
					}
				else
					{

							return 2;
					}
}
int print_pgi(struct PGI_PI_UNIT* parm,tvbuff_t *tvb,int offset,proto_tree *tree,packet_info *pinfo)
{
	int res;
	/* get total PGI data lenght  */
	int len = get_item_len(parm) ;    /*- (get_len_len(parm));  */
	/* get data address into PGI */
	struct PGI_PI_UNIT* parms =  get_data_address(parm);
	offset = offset + get_len_len(parm);

	while(len > 0)
	{


		if( (res = print_item( parms,tvb,offset,tree,pinfo) )  )
			{
				return  res;
			}
		/* next item */
		len = len - (get_item_len(parms)+get_len_len(parms)) ;
		offset = offset + get_item_len(parms)+get_len_len(parms);
		parms = get_next_PI(parms) ;
		continue;
	}
	return FALSE;
}

int print_item(struct PGI_PI_UNIT* parms,tvbuff_t *tvb,int offset,proto_tree *tree,packet_info *pinfo)
{
	char tmp[MAXSTRING];
	proto_item *tf;
	gchar       *reason_str;
	int len = get_item_len((struct PGI_PI_UNIT*)parms);

	switch(parms->type)
	{
	case Called_SS_user_Reference:
				sprintf(tmp,"Called SS user Reference:");
				break;

	case Calling_SS_user_Reference:
				sprintf(tmp,"Calling SS user Reference:");
				break;

	case Common_Reference:
				sprintf(tmp,"Common Reference:");
				break;

	case Additional_Reference_Information:
				sprintf(tmp,"Additional Reference Information:");
				break;

	case Sync_Type_Item:
				sprintf(tmp,"Sync Type Item:");
				break;

	case Token_Item:
				sprintf(tmp,"Token Item:");
				if (tree)
				{
						guint8       flags = 0;
						proto_tree   *flags_tree=NULL;
						proto_tree_add_text(ses_tree, tvb, offset, len+2,tmp);
					    flags = *( (guint8*) get_data_address(parms))  ;
tf = proto_tree_add_uint_format(ses_tree, hf_token_item_options_flags, tvb, offset + 2, 1,
						flags, "Flags: 0x%02x", flags);
						flags_tree = proto_item_add_subtree(tf, ett_token_item_flags);
proto_tree_add_boolean(flags_tree, release_token, tvb, offset+2, 1, flags); proto_tree_add_boolean(flags_tree, major_activity_token, tvb, offset+2, 1, flags); proto_tree_add_boolean(flags_tree, syncronize_minor_token, tvb, offset+2, 1, flags); proto_tree_add_boolean(flags_tree, data_token, tvb, offset+2, 1, flags);
				}

				return FALSE;

	case Transport_Disconnect:
				sprintf(tmp,"Transport_Disconnect:");
					if (tree)
						{
proto_tree_add_text(ses_tree, tvb, offset, 1,"%s0x%02x",tmp,parms->type);
						}

				if(parms->data & transport_connection_is_released )
				{
						sprintf(tmp,"transport connection is released");
							if (tree) proto_tree_add_text(ses_tree, tvb, offset+1, 1,tmp);
				}
				else
				{
						sprintf(tmp,"transport connection is kept");
							if (tree) proto_tree_add_text(ses_tree, tvb, offset+1, 1,tmp);
				}

				if(parms->data & user_abort )
				{
						sprintf(tmp,"user abort");
						if (tree) proto_tree_add_text(ses_tree, tvb, offset+1, 1,tmp);
				}

				if(parms->data & protocol_error )
				{
						sprintf(tmp,"protocol error");
						if (tree) proto_tree_add_text(ses_tree, tvb, offset+1, 1,tmp);
				}
				if(parms->data & no_reason )
				{
						sprintf(tmp,"no reason");
						if (tree) proto_tree_add_text(ses_tree, tvb, offset+1, 1,tmp);
				}
				if(parms->data & implementation_restriction )
				{
						sprintf(tmp,"implementation restriction");
						if (tree) proto_tree_add_text(ses_tree, tvb, offset+1, 1,tmp);
				}
				return FALSE;



				break;

	case Protocol_Options:
				sprintf(tmp,"Protocol Options:");
				if (tree)
				{
						guint8       flags = 0;
						proto_tree   *flags_tree=NULL;
						proto_tree_add_text(ses_tree, tvb, offset, len+2,tmp);
					    flags = *( (guint8*) get_data_address(parms))  ;
tf = proto_tree_add_uint_format(ses_tree, hf_connect_protocol_options_flags, tvb, offset + 2, 1,
						flags, "Flags: 0x%02x", flags);
flags_tree = proto_item_add_subtree(tf, ett_connect_protocol_options_flags); proto_tree_add_boolean(flags_tree, able_to_receive_extended_concatenated_SPDU, tvb, offset+2, 1, flags);
				}
				return FALSE;

	case TSDU_Maximum_Size:
				sprintf(tmp,"TSDU Maximum Size:");
				break;

	case Version_Number:

				sprintf(tmp,"Version Number:");
				if (tree)
				{
						guint8       flags = 0;
						proto_tree   *flags_tree=NULL;
						proto_tree_add_text(ses_tree, tvb, offset, len+2,tmp);
					    flags = *( (guint8*) get_data_address(parms))  ;
tf = proto_tree_add_uint_format(ses_tree, hf_version_number_options_flags, tvb, offset + 2, 1,
						flags, "Flags: 0x%02x", flags);
						flags_tree = proto_item_add_subtree(tf, ett_protocol_version_flags);
proto_tree_add_boolean(flags_tree, protocol_version_2, tvb, offset+2, 1, flags); proto_tree_add_boolean(flags_tree, protocol_version_1, tvb, offset+2, 1, flags);

				}
				return FALSE;


	case Initial_Serial_Number:
				sprintf(tmp,"Initial Serial Number:");
				break;

	case Prepare_Type:
				sprintf(tmp,"Prepare Type:");
				break;

	case EnclosureItem:
				sprintf(tmp,"Enclosure Item:");
				if (tree)
				{
						guint8       flags = 0;
						proto_tree   *flags_tree=NULL;
						proto_tree_add_text(ses_tree, tvb, offset, len+2,tmp);
					    flags = *( (guint8*) get_data_address(parms))  ;
tf = proto_tree_add_uint_format(ses_tree, hf_enclosure_item_options_flags, tvb, offset + 2, 1,
						flags, "Flags: 0x%02x", flags);
						flags_tree = proto_item_add_subtree(tf, ett_enclosure_item_flags);
proto_tree_add_boolean(flags_tree, end_of_SSDU, tvb, offset+2, 1, flags); proto_tree_add_boolean(flags_tree, beginning_of_SSDU, tvb, offset+2, 1, flags);

				}
				return FALSE;

	case Token_Setting_Item:
				sprintf(tmp,"Token Setting Item:");
				break;

	case Resync_Type:
				sprintf(tmp,"Resync Type:");
				break;

	case Reason_Code:
/*
	0:	Rejection by called SS-user; reason not specified.
	1:	Rejection by called SS-user due to temporary congestion.
2: Rejection by called SS-user. Subsequent octets may be used for user data up to a length of 512 octets if Protocol Version 1 has been selected, and up to a length such that the total length (including SI and LI) of the SPDU does not exceed 65 539 octets if Protocol Version 2 has been selected.
	128 + 1:	Session Selector unknown.
	128 + 2:	SS-user not attached to SSAP.
	128 + 3:	SPM congestion at connect time.
	128 + 4:	Proposed protocol versions not supported.
	128 + 5:	Rejection by the SPM; reason not specified.
128 + 6: Rejection by the SPM; implementation restriction stated in the PICS. */

	if (!(reason_str = match_strval(parms->data, reason_vals)))
	{
if (tree) proto_tree_add_text(ses_tree, tvb, offset, 2,"Reason Code: Unknown %d",parms->data);
	}
	else
	{
		if (tree) proto_tree_add_text(ses_tree, tvb, offset, 2,reason_str);
	}

/* do we have what to send to next dissector */
			if (!tvb_bytes_exist(tvb, 0, 4))
						return FALSE;	/* No */
/* yes, call sub dissector.  */
				if(!pres_handle)
				{
					/* print as data */
					  offset = offset + get_len_len(parms);
call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
					  offset += tvb_length_remaining(tvb, offset);
				}
				else
				{
					/* call presentation dissector */
					  tvbuff_t *next_tvb;
					  offset = offset + get_len_len(parms);
					  next_tvb = tvb_new_subset(tvb, offset, -1, -1);
							TRY
						{
							call_dissector(pres_handle, next_tvb, pinfo, tree);

						}
							CATCH(BoundsError)
						{
							show_reported_bounds_error(tvb, pinfo, tree);
							RETHROW;
						}
							CATCH(ReportedBoundsError)
						{
							show_reported_bounds_error(tvb, pinfo, tree);
						}
							ENDTRY;
				}				return parms->len-1;


				break;

	case Calling_Session_Selector:
				sprintf(tmp,"Calling Session Selector:");
				break;

	case Called_Session_Selector:
				sprintf(tmp,"Called Session Selector:");
				break;

	case Second_Resync_Type:
				sprintf(tmp,"Second Resync Type:");
				break;

	case Second_Serial_Number:
				sprintf(tmp,"Second Serial Number:");
				break;

	case Second_Initial_Serial_Number:
				sprintf(tmp,"Second Initial Serial Number:");
				break;

	case Upper_Limit_Serial_Number:
				sprintf(tmp,"Upper Limit Serial Number:");
				break;

	case Large_Initial_Serial_Number:
				sprintf(tmp,"Large Initial Serial Number:");
				break;

	case Large_Second_Initial_Serial_Number:
				sprintf(tmp,"Large Second Initial Serial Number:");
				break;


	case Data_Overflow:
				sprintf(tmp,"Data Overflow:");
				break;

	case Session_Requirement:
				sprintf(tmp,"Session Requirement:");
				if (tree)
				{
						guint16       flags=0;
						proto_tree   *flags_tree=NULL;
						struct CHAR_SHORT flg;
						proto_tree_add_text(ses_tree, tvb, offset, len+2,tmp);
						flg.data[0] = *( (guint8*) get_data_address(parms));
						flg.data[1] = *( ((guint8*) get_data_address(parms)) +1);
						flags = g_ntohs(flg.short_data) ;
tf = proto_tree_add_uint_format(ses_tree, hf_session_user_req_flags, tvb, offset + 2, 2,
						flags, "Flags: 0x%04x", flags);
						flags_tree = proto_item_add_subtree(tf, ett_ses_req_options_flags);
proto_tree_add_boolean(flags_tree, session_exception_report, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, data_separation_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, symmetric_syncronize_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, typed_data_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, exception_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, capability_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, negotiated_relese_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, activity_management_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, resyncronize_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, major_resyncronize_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, minor_resyncronize_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, expedited_data_resyncronize_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, half_duplex_function_unit, tvb, offset+2, 2, flags); proto_tree_add_boolean(flags_tree, duplex_function_unit, tvb, offset+2, 2, flags);


				}



				return FALSE;
	case Reflect_Parameter:
				sprintf(tmp,"Reflect Parameter:");
				break;


	default:
		sprintf(tmp,"Unknown session parameter:0x%02x",parms->type);
		break;


	}
	if (tree)
	{
		char tm[MAXSTRING];
		memset(&tm,0x00,sizeof(tmp));
string_to_hex( (unsigned char*) get_data_address(parms),tm,get_item_len(parms)); proto_tree_add_text(ses_tree, tvb, offset, get_len_len(parms)+get_item_len(parms),"%s0x%s",tmp,tm );
	}

		return FALSE;

}
int print_ses_parameters(struct PGI_PI_UNIT* parm,int g_len,tvbuff_t *tvb,int offset,proto_tree *tree,packet_info *pinfo)
{

	char tmp[MAXSTRING];
	int res;

	while(g_len > 0)
	{
	int len = get_item_len(parm);
	if(parm->type == EXTENDED_USER_DATA )
				{
				sprintf(tmp,"Session extended user data:");
if (tree) proto_tree_add_text(ses_tree, tvb, offset+get_len_len(parm), len,tmp);
				return  TRUE;
				}
	if(parm->type == SES_USER_DATA )
				{
				sprintf(tmp,"Session user data:");
				/* do we have OSI presentation packet dissector ? */
				if(!pres_handle)
				{
					/* print as data */
					sprintf(tmp,"User data:");
if (tree) proto_tree_add_text(ses_tree, tvb, offset+get_len_len(parm), len,tmp);
				}
				else
				{
					/* call presentation dissector */
					  tvbuff_t *next_tvb;
					  offset = offset + get_len_len(parm);
next_tvb = tvb_new_subset(tvb, offset, offset+get_len_len(parm), len);
							TRY
						{
							call_dissector(pres_handle, next_tvb, pinfo, tree);

						}
							CATCH(BoundsError)
						{
							show_reported_bounds_error(tvb, pinfo, tree);
							RETHROW;
						}
							CATCH(ReportedBoundsError)
						{
							show_reported_bounds_error(tvb, pinfo, tree);
						}
							ENDTRY;

				}
				return  TRUE;
				}

	/* is it PGI ?   */
	if(parm->type == Connect_Accept_Item
		|| parm->type == Connection_Identifier
		|| parm->type == Linking_Information )
				{

				switch(parm->type)
						{
					case Connect_Accept_Item:
										sprintf(tmp,"Connect/Accept Item:0x%02x",parm->type);
if (tree) proto_tree_add_text(ses_tree, tvb, offset, get_item_len( (struct PGI_PI_UNIT*) parm)+get_len_len((struct PGI_PI_UNIT*)parm),tmp);
										break;

					case Connection_Identifier:
										sprintf(tmp,"Connection identifier:0x%02x",parm->type);
										if (tree) proto_tree_add_text(ses_tree, tvb, offset, 1,tmp);
										break;

					case Linking_Information:
										sprintf(tmp,"Linking information:0x%02x",parm->type);
										if (tree) proto_tree_add_text(ses_tree, tvb, offset, 1,tmp);
										break;


						}
				if(  (res = print_pgi(parm,tvb,offset,tree,pinfo)  ) )
							{
								return res;
							}
				g_len= g_len - (get_item_len(parm)+get_len_len(parm));
				offset = offset + get_item_len(parm)+get_len_len(parm);
				parm = get_next_PI( parm);
				continue;
				}

/*	 it should be PI     */
				if( (res = print_item(  parm,tvb,offset,tree,pinfo)) )
					{
						return res;
					}

				g_len= g_len - (get_item_len(parm)+get_len_len(parm));
				offset = offset + get_item_len(parm)+get_len_len(parm);
				parm = get_next_PI( parm);
				continue;

	}
/* do we have what to send to next dissector */
			if (!tvb_bytes_exist(tvb, 0, 4))
						return FALSE;	/* No */
/* yes, call sub dissector.  */
				if(!pres_handle)
				{
					/* print as data */
call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
					  offset += tvb_length_remaining(tvb, offset);
				}
				else
				{
					/* call presentation dissector */
					  tvbuff_t *next_tvb;
					  offset = offset + get_len_len(parm);
					  next_tvb = tvb_new_subset(tvb, offset, -1, -1);
							TRY
						{
							call_dissector(pres_handle, next_tvb, pinfo, tree);

						}
							CATCH(BoundsError)
						{
							show_reported_bounds_error(tvb, pinfo, tree);
							RETHROW;
						}
							CATCH(ReportedBoundsError)
						{
							show_reported_bounds_error(tvb, pinfo, tree);
						}
							ENDTRY;
				}
	return FALSE;
}

int print_spdu(tvbuff_t *tvb,int offset,proto_tree *tree,packet_info *pinfo)
{
/*  print length                                           */
	    char    tmp[MAXSTRING];
		int		total_len=0;
		struct PGI_PI_UNIT* parms;
		/* get total len of spdu */
	    unsigned char len_type = tvb_get_guint8(tvb, offset+1);

  		if( len_type == TWO_BYTE_LEN)
		{
			total_len =  tvb_get_ntohs(tvb, offset+2);
			sprintf(tmp,"User data len: 0x%02x",(total_len) );
			if (tree) proto_tree_add_text(ses_tree, tvb, offset+1, 3,tmp);
			parms = (struct PGI_PI_UNIT*) tvb_get_ptr(tvb, offset+4, total_len);
			offset = offset + 4;

		}
		else
		{
			total_len = len_type;
			sprintf(tmp,"User data len: 0x%x",(total_len) );
			if (tree) proto_tree_add_text(ses_tree, tvb, offset+1, 1,tmp);
			parms = (struct PGI_PI_UNIT*) tvb_get_ptr(tvb, offset+2, total_len);
			offset = offset + 2;

		}
		return print_ses_parameters( parms,total_len,tvb,offset,tree,pinfo);

}



/*
* Dissect ses-encapsulated data in a SES stream.
*/

static void
 dissect_ses(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
//	char tmp[MAXSTRING];
	proto_item *ti = NULL;
	unsigned char type = 0;
	volatile int offset = 0;
	gchar       *ses_str;

/*   get SPDU type */
	type = tvb_get_guint8(tvb, offset);
/* check SPDU type */
	if (!(ses_str = match_strval(type, ses_vals)))
	{
		ses_str = "Unknown Spdu type";
	}



			ti = proto_tree_add_item(tree, proto_ses, tvb,offset, -1, FALSE);
			ses_tree = proto_item_add_subtree(ti, ett_ses);

			if (check_col(pinfo->cinfo, COL_INFO))
					col_add_str(pinfo->cinfo, COL_INFO, "");
			pinfo->current_proto = "SES";

			if (check_col(pinfo->cinfo, COL_INFO))
					col_add_str(pinfo->cinfo, COL_INFO, PROTO_STRING_SES_INFO);

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

 	if (check_col(pinfo->cinfo, COL_INFO))
		col_add_str(pinfo->cinfo, COL_INFO, ses_str);
	if (tree)
	{
		proto_tree_add_text(ses_tree, tvb, offset, 1,"%s:0x%02x",ses_str,type);
	}
/* print session pdu     */
		print_spdu(tvb,offset,tree,pinfo);
		return  ;

}


void
proto_register_ses(void)
{
	static hf_register_info hf[] =
	{
		{
			&hf_ses_version,
			{
				"Version",
				"ses.version",
				FT_UINT8,
				BASE_DEC,
				NULL,
				0x0,
				"", HFILL
			}
		},
		{
			&hf_ses_reserved,
			{
				"Reserved",
				"ses.reserved",
				FT_UINT8,
				BASE_DEC,
				NULL,
				0x0,
				"", HFILL
			}
		},
		{
			&hf_ses_length,
			{
				"Length",
				"ses.length",
				FT_UINT16,
				BASE_DEC,
				NULL,
				0x0,
				"", HFILL
			}
		},

		{
			&expedited_data_resyncronize_function_unit,
			{
				"expedited data function unit",
				"ses.expedited.data",
				FT_BOOLEAN, 16,
				NULL,
				EXPEDITED_DATA_FUNCTION_UNIT,
				"expedited data function unit",
				HFILL
			}
		},

		{
			&minor_resyncronize_function_unit,
			{
				"minor resyncronize function unit",
				"ses.minor.resyncronize",
				FT_BOOLEAN, 16,
				NULL,
				MINOR_SYNCRONIZE_FUNCTION_UNIT,
				"minor resyncronize function unit",
				HFILL
			}
		},

		{
			&major_resyncronize_function_unit,
			{
				"major resyncronize function unit",
				"ses.major.resyncronize",
				FT_BOOLEAN, 16,
				NULL,
				MAJOR_SYNCRONIZE_FUNCTION_UNIT,
				"major resyncronize function unit",
				HFILL
			}
		},
		{
			&resyncronize_function_unit,
			{
				"resyncronize function unit",
				"ses.resyncronize",
				FT_BOOLEAN, 16,
				NULL,
				RESYNCRONIZE_FUNCTION_UNIT,
				"resyncronize function unit",
				HFILL
			}
		},


		{
			&activity_management_function_unit,
			{
				"activity management function unit",
				"ses.activity.management",
				FT_BOOLEAN, 16,
				NULL,
				ACTIVITY_MANAGEMENT_FUNCTION_UNIT,
				"activity management function unit",
				HFILL
			}
		},

		{
			&negotiated_relese_function_unit,
			{
				"negotiated relese function unit",
				"ses.negotiated.relese",
				FT_BOOLEAN, 16,
				NULL,
				NEGOTIATED_RELEASE_FUNCTION_UNIT,
				"negotiated relese function unit",
				HFILL
			}
		},


		{
			&capability_function_unit,
			{
				"capability function unit",
				"ses.capability.data",
				FT_BOOLEAN, 16,
				NULL,
				CAPABILITY_DATA_FUNCTION_UNIT,
				"capability function unit",
				HFILL
			}
		},

		{
			&exception_function_unit,
			{
				"exception function unit",
				"ses.exception.data",
				FT_BOOLEAN, 16,
				NULL,
				EXCEPTION_FUNCTION_UNIT,
				"exception function unit",
				HFILL
			}
		},


		{
			&typed_data_function_unit,
			{
				"typed data function unit",
				"ses.typed.data",
				FT_BOOLEAN, 16,
				NULL,
				TYPED_DATA_FUNCTION_UNIT,
				"typed data function unit",
				HFILL
			}
		},

		{
			&symmetric_syncronize_function_unit,
			{
				"symmetric syncronize function unit",
				"ses.symm.sync",
				FT_BOOLEAN, 16,
				NULL,
				SYMMETRIC_SYNCRONIZE_FUNCTION_UNIT,
				"symmetric syncronize function unit",
				HFILL
			}
		},
		{
			&data_separation_function_unit,
			{
				"data separation function unit",
				"ses.data.sep",
				FT_BOOLEAN, 16,
				NULL,
				DATA_SEPARATION_FUNCTION_UNIT,
				"data separation function unit",
				HFILL
			}
		},
		{
			&session_exception_report,
			{
				"session exception report",
				"ses.exception.report.",
				FT_BOOLEAN, 16,
				NULL,
				SES_EXCEPTION_REPORT,
				"session exception report",
				HFILL
			}
		},

		{
			&duplex_function_unit,
			{
				"half duplex functional unit",
				"ses.duplex",
				FT_BOOLEAN, 16,
				NULL,
				HALF_DUPLEX_FUNCTION_UNIT,
				"half duplex functional unit",
				HFILL
			}
		},
		{
			&half_duplex_function_unit,
			{
				"duplex functional unit",
				"ses.half.duplex",
				FT_BOOLEAN, 16,
				NULL,
				DUPLEX_FUNCTION_UNIT,
				"duplex functional unit",
				HFILL
			}
		},
		{
			&able_to_receive_extended_concatenated_SPDU,
			{
				"Able to receive extended concatenated SPDU",
				"ses.connect.f1",
				FT_BOOLEAN, 8,
				NULL,
				SES_EXT_CONT,
				"Able to receive extended concatenated SPDU",
				HFILL
			}
		},
		{
			&beginning_of_SSDU,
			{
				"beginning of SSDU",
				"ses.begininng.SPDU",
				FT_BOOLEAN, 8,
				NULL,
				BEGINNING_SPDU,
				"beginning of SSDU",
				HFILL
			}
		},
		{
			&end_of_SSDU,
			{
				"end of SSDU",
				"ses.end.SPDU",
				FT_BOOLEAN, 8,
				NULL,
				END_SPDU,
				"end of SSDU",
				HFILL
			}
		},
		{
			&major_activity_token,
			{
				"major/activity token",
				"ses.major.token",
				FT_BOOLEAN, 8,
				NULL,
				MAJOR_ACTIVITY_TOKEN,
				"major/activity token",
				HFILL
			}
		},
		{
			&syncronize_minor_token,
			{
				"syncronize minor token",
				"ses.syncronize.token",
				FT_BOOLEAN, 8,
				NULL,
				SYNCRONIZE_MINOR_TOKEN,
				"syncronize minor token",
				HFILL
			}
		},
		{
			&data_token,
			{
				"data token",
				"ses.data.token",
				FT_BOOLEAN, 8,
				NULL,
				DATA_TOKEN,
				"data  token",
				HFILL
			}
		},
		{
			&release_token,
			{
				"release token",
				"ses.release.token",
				FT_BOOLEAN, 8,
				NULL,
				RELEASE_TOKEN,
				"release token",
				HFILL
			}
		},
		{
			&protocol_version_1,
			{
				"Protocol Version 1",
				"ses.protocol.version2",
				FT_BOOLEAN, 8,
				NULL,
				PROTOCOL_VERSION_1,
				"Protocol Version 1",
				HFILL
			}
		},
		{
			&protocol_version_2,
			{
				"Protocol Version 2",
				"ses.protocol.version2",
				FT_BOOLEAN, 8,
				NULL,
				PROTOCOL_VERSION_2,
				"Protocol Version 2",
				HFILL
			}
		},


		{
			&hf_connect_protocol_options_flags,

			{
				"Flags",
				"ses.connect.flags",
				FT_UINT8,
				BASE_HEX,
				NULL,
				0x0,
				"",
				HFILL
			}
		},
		{
			&hf_version_number_options_flags,

			{
				"Flags",
				"ses.version.flags",
				FT_UINT8,
				BASE_HEX,
				NULL,
				0x0,
				"",
				HFILL
			}
		},

		{
			&hf_token_item_options_flags,

			{
				"Flags",
				"ses.tken_item.flags",
				FT_UINT8,
				BASE_HEX,
				NULL,
				0x0,
				"",
				HFILL
			}
		},

		{
			&hf_enclosure_item_options_flags,

			{
				"Flags",
				"ses.enclosure.flags",
				FT_UINT8,
				BASE_HEX,
				NULL,
				0x0,
				"",
				HFILL
			}
		},

		{
			&hf_session_user_req_flags,
			{
				"Flags",
				"ses.req.flags",
				FT_UINT16,
				BASE_HEX,
				NULL,
				0x0,
				"",
				HFILL
			}
		},


	};

	static gint *ett[] =
	{
		&ett_ses,
		&ett_connect_protocol_options_flags,
		&ett_protocol_version_flags,
		&ett_enclosure_item_flags,
		&ett_token_item_flags,
		&ett_ses_req_options_flags,
	};
	module_t *ses_module;


	proto_ses = proto_register_protocol(PROTO_STRING_SES, "SES", "ses");
	proto_register_field_array(proto_ses, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));

	ses_module = prefs_register_protocol(proto_ses, NULL);
/*
	prefs_register_bool_preference(ses_module, "desegment",
	    "Desegment all session packets ",
"Whether the ses dissector should desegment all messages spanning multiple SES segments",
	    &ses_desegment);  */
 /*
  * Register the dissector by name, so other dissectors can
  * grab it by name rather than just referring to it directly
  * (you can't refer to it directly from a plugin dissector
  * on Windows without stuffing it into the Big Transfer Vector).
  */
   register_dissector("ses", dissect_ses, proto_ses);
}

static gboolean
dissect_ses_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
{
	/* must check that this really is a ses packet */
	unsigned char type = 0;
	volatile int offset = 0;
	int len=0;
	struct PGI_PI_UNIT* parms;
	gchar       *ses_str;
 /* first, check do we have at least 4 bytes */
			if (!tvb_bytes_exist(tvb, 0, 4))
					return  FALSE;	/* no */
 /*  OK,let's check SPDU length  */
 /* get at least 4 bytes */
 	parms = (struct PGI_PI_UNIT*) tvb_get_ptr(tvb, offset, 4);
 /*  get length of SPDU */
	len = get_item_len((struct PGI_PI_UNIT*)parms);
 /* do we have enough bytes ? */
			if (!tvb_bytes_exist(tvb, 0, len))
					return  FALSE;	/* no */
/* can we regognize session PDU ? Return FALSE if  not */
/*   get SPDU type */
	type = tvb_get_guint8(tvb, offset);
/* check SPDU type */
	if (!(ses_str = match_strval(type, ses_vals)))
	{
		return FALSE;  /* no, it isn't a session PDU */
	}

	dissect_ses(tvb, pinfo, parent_tree);
	return TRUE;
}



void
proto_reg_handoff_ses(void)
{
	dissector_handle_t ses_handle;
/*   find data dissector  */
	data_handle = find_dissector("data");
	ses_handle = create_dissector_handle(dissect_ses, proto_ses);
	/* define sub dissector */
	pres_handle = find_dissector("pres");
	/* add our session dissector to cotp dissector list */
	heur_dissector_add("cotp", dissect_ses_heur, proto_ses);
}

/* packet-ses.h
*
* Routine to dissect ISO 8327-1 OSI Session Protocol packets
*
*
* $Id: packet-ses.h,v 1.0 2003/09/01 21:00:36
* Yuriy Sidelnikov <YSidelnikov@xxxxxxxxxxx>
*

* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@xxxxxxxxxxxx>
* Copyright 1998 Gerald Combs
*
* 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.
*/

#define PROTO_STRING_SES "ISO 8327-1 OSI Session Protocol"
#define PROTO_STRING_SES_INFO "ISO 8327-1 OSI Session Protocol."
/*
* Dissect ses-encapsulated data in a TCP stream.
*/
static void
dissect_ses(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
/* max string lenght */
#define MAXSTRING 1024
/* session parms*/
#define  SES_EXT_CONT    0x01
/* protocol versions  */
#define  PROTOCOL_VERSION_1     0x01
#define  PROTOCOL_VERSION_2     0x02
/* enclosure item */
#define BEGINNING_SPDU			0x01
#define END_SPDU				0x02


#define DATA_TOKEN						0x01
#define RELEASE_TOKEN					0x40
#define SYNCRONIZE_MINOR_TOKEN			0x04
#define MAJOR_ACTIVITY_TOKEN			0x10
/* session user req  flag   */
#define HALF_DUPLEX_FUNCTION_UNIT							0x0001
#define DUPLEX_FUNCTION_UNIT								0x0002
#define EXPEDITED_DATA_FUNCTION_UNIT						0x0004
#define MINOR_SYNCRONIZE_FUNCTION_UNIT						0x0008
#define MAJOR_SYNCRONIZE_FUNCTION_UNIT						0x0010
#define RESYNCRONIZE_FUNCTION_UNIT							0x0020
#define ACTIVITY_MANAGEMENT_FUNCTION_UNIT					0x0040
#define NEGOTIATED_RELEASE_FUNCTION_UNIT					0x0080
#define CAPABILITY_DATA_FUNCTION_UNIT						0x0100
#define EXCEPTION_FUNCTION_UNIT								0x0200
#define TYPED_DATA_FUNCTION_UNIT							0x0400
#define SYMMETRIC_SYNCRONIZE_FUNCTION_UNIT					0x0800
#define DATA_SEPARATION_FUNCTION_UNIT						0x1000
#define SES_EXCEPTION_REPORT								0x2000
/*define SES_EXCEPTION_REPORT			0    */
#define SES_DATA_TRANSFER				1
#define SES_GIVE_TOKEN					1
#define SES_PLEASE_TOKENS				2
#define SES_EXPEDITED					5
#define SES_PREPARE						7
#define SES_NOT_FINISHED				8
#define SES_FINISH						9
#define SES_DISCONNECT					10
#define SES_REFUSE						12
#define SES_CONNECTION_REQUEST			13
#define SES_CONNECTION_ACCEPT			14
#define SES_CONNECTION_DATA_OVERFLOW	15
#define SES_OVERFLOW_ACCEPT				16
#define SES_GIVE_TOKENS_CONFIRM			21
#define SES_GIVE_TOKENS_ACK				22
#define SES_ABORT						25
#define SES_ABORT_ACCEPT				26
/*#define SES_ACTIVITY_INTERRUPT			25
#define SES_ACTIVITY_INTERRUPT_ACK		26  */
#define SES_ACTIVITY_RESUME				29
#define SES_TYPED_DATA					33
#define SES_RESYNCHRONIZE_ACK			34
#define SES_MAJOR_SYNC_POINT			41
/*#define SES_MAJOR_SYNC_POINT			41
#define SES_ACTIVITY_END				41  */
#define SES_MAJOR_SYNC_ACK				42
#define SES_ACTIVITY_START				45
#define SES_EXCEPTION_DATA				48
#define SES_MINOR_SYNC_POINT			49
#define SES_MINOR_SYNC_ACK				50
#define SES_RESYNCHRONIZE				53
#define SES_ACTIVITY_DISCARD			57
#define SES_ACTIVITY_DISCARD_ACK		58
#define SES_CAPABILITY					61
#define SES_CAPABILITY_DATA_ACK			62


#define	EXTENDED_USER_DATA				192
#define	SES_USER_DATA					193
/*
reason code
	0:	Rejection by called SS-user; reason not specified.
	1:	Rejection by called SS-user due to temporary congestion.
2: Rejection by called SS-user. Subsequent octets may be used for user data up to a length of 512 octets if Protocol Version 1 has been selected, and up to a length such that the total length (including SI and LI) of the SPDU does not exceed 65 539 octets if Protocol Version 2 has been selected.
	128 + 1:	Session Selector unknown.
	128 + 2:	SS-user not attached to SSAP.
	128 + 3:	SPM congestion at connect time.
	128 + 4:	Proposed protocol versions not supported.
	128 + 5:	Rejection by the SPM; reason not specified.
128 + 6: Rejection by the SPM; implementation restriction stated in the PICS.
*/
#define reason_not_specified			0
#define temporary_congestion			1
#define Subsequent						2
#define Session_Selector_unknown		128+1
#define SS_user_not_attached_to_SSAP	128+2
#define SPM_congestion_at_connect_time	128+3
#define versions_not_supported			128+4
#define SPM_reason_not_specified		128+5
#define SPM_implementation_restriction	128+6

#define		TWO_BYTE_LEN			0xff
/* PGI   */


#define		Connection_Identifier			1
#define		Connect_Accept_Item				5
#define		Linking_Information				33




#define Called_SS_user_Reference			9
#define Calling_SS_user_Reference			10
#define Common_Reference					11
#define Additional_Reference_Information	12

#define Sync_Type_Item						15
#define Token_Item							16
#define Transport_Disconnect				17

#define Protocol_Options					19
#define Session_Requirement					20
#define TSDU_Maximum_Size					21
#define Version_Number						22
#define Initial_Serial_Number				23
#define Prepare_Type						24
#define EnclosureItem						25
#define Token_Setting_Item					26
#define Resync_Type							27

#define Reflect_Parameter					49

#define Reason_Code							50
#define Calling_Session_Selector			51
#define Called_Session_Selector				52
#define Second_Resync_Type					53
#define Second_Serial_Number				54
#define Second_Initial_Serial_Number		55
#define Upper_Limit_Serial_Number			56
#define Large_Initial_Serial_Number			57
#define Large_Second_Initial_Serial_Number	58


#define		CALLED_SESSION_SELECTOR    0x33
#define		CALLING_SESSION_SELECTOR    0x34
#define		SES_USER_DATA				193


#define Data_Overflow						60



#define		SES_PDU_HEADER_LEN				2





#define SES_DATA					0x01

// transport disconnect values
#define		transport_connection_is_released	0x01
#define		user_abort							0x02
#define		protocol_error						0x04
#define		no_reason							0x08
#define		implementation_restriction			0x10




struct	SES_PDU
{
	unsigned char type;
	unsigned char len;
	union	{
			unsigned short len_short;
			unsigned char data;
			};
	unsigned char data1;
};

struct	PGI_PI_UNIT
{
	unsigned char type;
	unsigned char len;
	union	{
			unsigned short len_short;
			unsigned char data;
			};
	unsigned char data1;
};

struct CHAR_SHORT
{
		union	{
			unsigned short short_data;
			unsigned char data[2];
				};

};


struct	SES_PDU_PARM
{
	unsigned char parm_type;
	unsigned char len;
	unsigned char data;
};