Index: epan/dissectors/packet-gsm.h
===================================================================
--- epan/dissectors/packet-gsm.h	(revision 0)
+++ epan/dissectors/packet-gsm.h	(revision 0)
@@ -0,0 +1,328 @@
+/* packet-gsm.h
+ * Headers for GSM message dissection
+ * Copyright 2001, ip.access Ltd <Neil.Piercy@ipaccess.com>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@unicom.net>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from README.developer
+ *
+ * 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.
+ */
+
+#include <epan/packet.h>
+
+#define GSM0408_HEADER_LEN   2
+#define GSM0808_HEADER_LEN   1
+#define IPA_HEADER_LEN       3
+#define IPA_UDP_HEADER_LEN   4
+
+#define MAX_DATA_STR      5
+
+#define rd_match_strval(a,b)	((char *)val_to_str((a), (const value_string *)(b), "Unknown"))
+
+/* maximum numbers for signalling over IP conversation tracking */
+#define BTS_MAX				200
+#define CONFIG_MGR_LINK_MAX	10
+#define BTS_LINK_MAX		(2*BTS_MAX)			/* OML & RSL */
+#define IPA_LINK_MAX		(1+CONFIG_MGR_LINK_MAX+BTS_LINK_MAX)	/* BTS links + config manager + SCCP over IP */
+
+/* defines for the Signalling over IP streams */
+#define OML_STREAM			255
+#define CTRL_STREAM			254
+#define SCCP_STREAM			253
+#define SPIRIT_STREAM		253
+#define BSC_MGMT_STREAM		251
+#define BSC_SUBAGENT_STREAM 250
+#define SIGTRAN_STREAM		249
+#define FRIP_STREAM			248
+#define GNAT_STREAM			247
+#define IML_STREAM			129
+#define RSL_STREAM_MAX		 32
+
+/* defines for the fixed TCP/UDP port numbers */
+#define TCP_PORT_IPA_OML     3002
+#define TCP_PORT_IPA_RSL     3003
+#define TCP_PORT_IPA_2NDOML  3006
+#define TCP_PORT_IPA_HW_MON  3007
+#define TCP_PORT_IPA_FRIP	 3008
+#define TCP_PORT_IPA_SPIRIT	 3008
+#define TCP_PORT_IPA_GNAT    3009
+#define TCP_PORT_IPA_BSCMGMT 3010
+#define TCP_PORT_IPA_A_IF	 3011
+#define TCP_PORT_IPA_SITE_IML 3013
+#define TCP_PORT_IPA_BTS_IML 3014
+#define UDP_PORT_IPA         3006
+
+/* defines for the GSMSTAT interface */
+#define GSMSTAT_INTERFACE_NULL    -1
+#define GSMSTAT_INTERFACE_A        0
+#define GSMSTAT_INTERFACE_A_BIS    1
+#define GSMSTAT_INTERFACE_GB       2
+#define GSMSTAT_INTERFACE_MAX      2 /* until we add GB! */
+
+#define GSMSTAT_PROTO_NULL        -1
+#define GSMSTAT_PROTO_GSM0408      1
+#define GSMSTAT_PROTO_GSM0808      2
+#define GSMSTAT_PROTO_GSM0858      3
+#define GSMSTAT_PROTO_GSM0818      4
+#define GSMSTAT_PROTO_GSM1221      5
+
+#define GSMSTAT_PD_NULL            -1
+
+/* 04.08 Protocol Discriminator values */
+#define GSM0408_PD_VGCS     0x0
+#define GSM0408_PD_VBS      0x1
+#define GSM0408_PD_PDSS1    0x2
+#define GSM0408_PD_CC       0x3
+#define GSM0408_PD_PDSS2    0x4
+#define GSM0408_PD_MM       0x5
+#define GSM0408_PD_RR       0x6
+#define GSM0408_PD_GMM      0x8
+#define GSM0408_PD_SMS      0x9
+#define GSM0408_PD_SM       0xa
+#define GSM0408_PD_SS       0xb
+#define GSM0408_PD_LS       0xc
+
+/* RTP Paylod types in use for A-bis */
+#define RTP_PAYLOAD_GSM_FR	0
+#define RTP_PAYLOAD_GSM_EFR	1
+#define RTP_PAYLOAD_GSM_AMR	2
+#define RTP_PAYLOAD_GSM_CSD	3
+#define RTP_PAYLOAD_GSM_NANO_GSM_MUX	4
+
+#define GSMSTAT_MSG_TYPE_NULL    -1
+/* 08.58 Message Type values */
+#define GSM0858_MSG_TYPE_ESTABLISH_IND               0x06
+#define GSM0858_MSG_TYPE_ERROR_INDICATION            0x03
+#define GSM0858_MSG_TYPE_CHANNEL_REQUIRED            0x13
+#define GSM0858_MSG_TYPE_PAGING_COMMAND              0x15
+#define GSM0858_MSG_TYPE_IMMEDIATE_ASSIGN            0x16
+#define GSM0858_MSG_TYPE_ERROR_REPORT                0x1c
+#define GSM0858_MSG_TYPE_CHAN_ACTIVATE               0x21
+#define GSM0858_MSG_TYPE_CHAN_ACTIVATE_ACK           0x22
+#define GSM0858_MSG_TYPE_CONNECTION_FAIL_IND         0x24
+#define GSM0858_MSG_TYPE_HANDOVER_DETECT             0x27
+#define GSM0858_MSG_TYPE_RF_CHAN_REL                 0x2e
+#define GSM0858_MSG_TYPE_RF_CHAN_REL_ACK             0x33
+#define GSM0858_MSG_TYPE_PREPROC_MEAS_RESULTS        0x32
+#define GSM0858_MSG_TYPE_CREATE_CONNECTION		     0x70
+#define GSM0858_MSG_TYPE_CREATE_CONNECTION_ACK	     0x71
+#define GSM0858_MSG_TYPE_MODIFY_CONNECTION		     0x73
+#define GSM0858_MSG_TYPE_MODIFY_CONNECTION_ACK	     0x74
+#define GSM0858_MSG_TYPE_CREATE_MULTIPLEX_CONNECTION 0x53
+/* 04.08 RR Message Type values */
+#define GSM0408_MSG_TYPE_PAGING_RESPONSE             0x27
+#define GSM0408_MSG_TYPE_HANDOVER_FAILURE            0x28
+#define GSM0408_MSG_TYPE_HANDOVER_COMMAND            0x2b
+#define GSM0408_MSG_TYPE_HANDOVER_COMPLETE           0x2c
+#define GSM0408_MSG_TYPE_ASSIGNMENT_COMMAND          0x2e
+#define GSM0408_MSG_TYPE_ASSIGNMENT_COMPLETE         0x29
+#define GSM0408_MSG_TYPE_ASSIGNMENT_FAILURE          0x2f
+#define GSM0408_MSG_TYPE_CHANNEL_MODE_MODIFY         0x10
+#define GSM0408_MSG_TYPE_CHANNEL_MODE_MODIFY_ACK     0x17
+/* 04.08 MM Message Type values */
+#define GSM0408_MSG_TYPE_LOCATION_UPDATE_ACCEPT      0x02
+#define GSM0408_MSG_TYPE_LOCATION_UPDATE_REJECT      0x04
+#define GSM0408_MSG_TYPE_LOCATION_UPDATE_REQUEST     0x08
+/* 04.08 CC Message Type values */
+#define GSM0408_MSG_TYPE_SETUP                       0x05
+#define GSM0408_MSG_TYPE_CONNECT                     0x07
+#define GSM0408_MSG_TYPE_DISCONNECT                  0x25
+/* GSMSTAT Cause values */
+#define GSMSTAT_CAUSE_NULL                            -1
+#define GSMSTAT_GSM0858_L3INFO                       0x01
+/* GSM 04.08 Cause values */
+#define GSM0408_CAUSE_UNASSIGNED_NUMBER              0x01
+#define GSM0408_CAUSE_NO_ROUTE_TO_DESTINATION        0x03
+#define GSM0408_CAUSE_OPERATOR_DETERMINED_BARRING    0x08
+#define GSM0408_CAUSE_NORMAL_CALL_CLEARING           0x10
+#define GSM0408_CAUSE_USER_BUSY                      0x11
+#define GSM0408_CAUSE_NO_USER_RESPONDING             0x12
+#define GSM0408_CAUSE_USER_ALERTING_NO_ANSWER        0x13
+#define GSM0408_CAUSE_CALL_REJECTED                  0x15
+#define GSM0408_CAUSE_NORMAL_UNSPECIFIED             0x1f
+/* GSMSTAT Chan_type values */
+#define GSMSTAT_CHAN_TYPE_NULL                        -1
+#define GSMSTAT_CHAN_TYPE_TCH                        0x00
+#define GSMSTAT_CHAN_TYPE_SDCCH                      0x01
+#define GSMSTAT_CHAN_TYPE_CIC                        0x02
+#define GSMSTAT_CHAN_TYPE_MAX                        3
+/* 08.08 Message Type values */
+#define GSM0808_MSG_TYPE_ASSIGNMENT_REQUEST          0x01
+#define GSM0808_MSG_TYPE_ASSIGNMENT_COMPLETE         0x02
+#define GSM0808_MSG_TYPE_ASSIGNMENT_FAILURE          0x03
+#define GSM0808_MSG_TYPE_HANDOVER_REQUEST            0x10
+#define GSM0808_MSG_TYPE_HANDOVER_REQUIRED           0x11
+#define GSM0808_MSG_TYPE_HANDOVER_REQUEST_ACK        0x12
+#define GSM0808_MSG_TYPE_HANDOVER_COMPLETE			 0x14
+#define GSM0808_MSG_TYPE_HANDOVER_FAILURE			 0x16
+#define GSM0808_MSG_TYPE_HANDOVER_REQUIRED_REJECT    0x1A
+#define GSM0808_MSG_TYPE_HANDOVER_DETECT             0x1B
+#define GSM0808_MSG_TYPE_CLEAR_COMMAND               0x20
+#define GSM0808_MSG_TYPE_CLEAR_COMPLETE              0x21
+#define GSM0808_MSG_TYPE_CLEAR_REQUEST               0x22
+#define GSM0808_MSG_TYPE_PAGING                      0x52
+
+typedef void (*ie_dissector_t)(int msg_type, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *top_tree, void *extra);
+
+/* Note: the value parameter is to keep the dissector easy for type 1 IEs which can be in either half octet of the TVB */
+typedef void (*gsm0408_ie_dissector_t)(int msg_type, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *extra, guint8 value);
+
+typedef struct ie_def_t {
+    guint8    ie_ei;
+    char    *ie_name;
+    gint8    ie_len;    /* 0..N=fixed length; -1=1 octet length field, -2=2 octet length field etc. */
+    ie_dissector_t    ie_disector;
+    void    *info;    /* extra IE-dependent info */
+} ie_def_t;
+
+/* IE types defined in 04.07:
+    I        1/2 octet V with optional T
+    II        T only
+    III        V or TV
+    IV        LV or TLV
+*/
+
+typedef struct ie_t {
+    int                tag;        /* tag to match the tag in the ie_id_t */
+    guint8            type;        /* as defined in 04.07 - value 1..4 */
+    guint8            len;        /* only used for type 3 fixed length */
+    gsm0408_ie_dissector_t    dissector;    /* function to dissect the IE */
+    void            *info;        /* info to be used by the dissector specific to this IE - e.g cause vale strings */
+} ie_t;
+
+typedef struct ie_id_t {
+    int                tag;        /* really a tag to match the tag in the ie_t */
+    char            *name;        /* display string for the IE name */
+    guint8            iei;        /* standard messages have message dependent IEI values */
+} ie_id_t;
+
+#define MSG_IE_MAX    40            /* maximum number of IEs in a message -
+                                    compiler will throw an error in the initialisers
+                                    if this is not big enough ! */
+
+typedef struct msg_t {
+    guint8            format;        /* format 1 is normal, format 2 for RACH, format 3 for SACCH */
+    guint8            type;        /* msg type value */
+    char            *name;        /* name string */
+    ie_id_t            ie_id[MSG_IE_MAX];    /* array of mandatory and optional IE identifiers */
+} msg_t;
+
+/* Struct for passing info to the GSM stats tap function */
+#define ARG_MAX        10
+
+/* struct to hold the data from the message parsing to the tap function */
+typedef struct tap_gsmstat_t {
+    guint8            proto;            /* GSM protocol */
+    guint8            type;            /* msg type value */
+} tap_gsmstat_t;
+
+/* definitions of the counters */
+#define GSMSTAT_CHAN_REQS                    0
+#define GSMSTAT_PAGE_REQS                    1
+#define GSMSTAT_IMM_ASS_ATTEMPTS             2
+#define GSMSTAT_IMM_ASS_SUCCESSES            3
+#define GSMSTAT_HANDOVER_COMMAND             4
+#define GSMSTAT_HANDOVER_COMPLETE            5
+#define GSMSTAT_HANDOVER_FAILURE             6
+#define GSMSTAT_LU_REQS                      7
+#define GSMSTAT_LU_ACCEPT                    8
+#define GSMSTAT_LU_REJECTS                   9
+#define GSMSTAT_SETUPS                      10
+#define GSMSTAT_CONNECTS                    11
+#define GSMSTAT_DISC_NORMAL                 12
+#define GSMSTAT_DISC_ABNORMAL               13
+#define GSMSTAT_ASS_REQS                    14
+#define GSMSTAT_ASS_FAILS                   15
+#define GSMSTAT_CLEAR_REQS                  16
+#define GSMSTAT_ERRORS                      17
+#define GSMSTAT_PREPROC_MEAS_RESULTS        18
+#define GSMSTAT_CONN_FAIL_SDCCH             19
+#define GSMSTAT_ERROR_REPS                  20
+#define GSMSTAT_MSGS                        21
+#define GSMSTAT_OCTETS                      22
+#define GSMSTAT_IPPKTS                      23
+#define GSMSTAT_IPLEN                       24
+#define GSMSTAT_HANDOVER_REQUEST            25
+#define GSMSTAT_HANDOVER_REQUIRED           26
+#define GSMSTAT_HANDOVER_REQUIRED_REJECT    27
+#define GSMSTAT_PAGE_RESPONSE			    28
+#define GSMSTAT_HANDOVER_DETECT             29
+#define GSMSTAT_CONN_FAIL_TCH               30
+#define GSMSTAT_HANDOVER_ALLOC              31
+#define GSMSTAT_CLEAR_CMDS                  32
+#define GSMSTAT_ASS_CMD                     33
+#define GSMSTAT_ASS_EST                     34
+#define GSMSTAT_ASS_CPTE                    35
+#define GSMSTAT_MODE_MOD                    36
+#define GSMSTAT_ERROR_INDS                  37
+#define GSMSTAT_MAX                         38
+
+/* used to keep track of erlangs etc */
+typedef struct {
+    int current;
+    int peak;
+    int peak_count;
+    int peak_secs;
+    int peak_usecs;
+    int last_secs;
+    int last_usecs;
+    int chan_usecs;
+    int chan_secs;
+} usage_stats_t;
+
+/* used to keep track of the statistics for an entire tap instance - only one for GSM, but... */
+typedef struct _gsmstat_common_t {
+    int  secs;
+    int  usecs;
+    int  intface;
+    int  count[GSMSTAT_MAX];
+    usage_stats_t usage[GSMSTAT_CHAN_TYPE_MAX];
+} gsmstat_common_t;
+
+void dissect_gsm_generic_ie( guint8 msg_type, const ie_def_t *ie_defs, tvbuff_t *tvb, packet_info *pinfo, proto_tree *main_tree, proto_tree *top_tree);
+
+/* gsmstat interface routines */
+void gsmstat_set_reset(void);
+void gsmstat_set_interface(int intface, packet_info *pinfo);
+void gsmstat_set_proto(int proto);
+void gsmstat_set_pd(int pd);
+void gsmstat_set_msg_type(int msg_type);
+void gsmstat_set_cause(int cause);
+void gsmstat_set_chan_type(int chan_type);
+void gsmstat_set_chan_id(int chan_id);
+void gsmstat_set_cic(int cic);
+void gsmstat_common_reset(gsmstat_common_t *gsc);
+int gsmstat_common_packet(gsmstat_common_t *gsc, packet_info *pinfo, const void *pri);
+gchar *gsmstat_name(int tag);
+gchar *gsmstat_intface_name(int tag);
+int gsmstat_counts_max(int intface);
+int gsmstat_counts(int intface, int index);
+gchar *gsmstat_usage_name(int tag);
+int gsmstat_usage_max(int intface);
+int gsmstat_usage(int intface, int index);
+/* global data and a helper function to share a single tap across multiple protocols - and thus potentially multiple regsitrations etc */
+extern int gsmstat_tap;
+void gsmstat_register_tap(void);
+
+/* Some helper routines */
+/* gchar *rd_match_strval(guint32 val, const value_string *vs); */
+gchar *data_str( tvbuff_t *tvb, int offset, int data_len, gchar *buf, int buf_len );
+guint16 reduced_frame_number(guint16 fn);
+
+/* a few nasty cross-protocol routines for analysis */
+int analyze_immediate_assignment(guint8 ra, guint16 fn, packet_info *pinfo);
Index: epan/dissectors/Makefile.common
===================================================================
--- epan/dissectors/Makefile.common	(revision 31168)
+++ epan/dissectors/Makefile.common	(working copy)
@@ -476,6 +476,7 @@
 	packet-gsm_a_rp.c		\
 	packet-gsm_a_rr.c	\
 	packet-gsm_ipa.c	\
+	packet-gsm_ipa_iml.c	\
 	packet-gsm_bsslap.c		\
 	packet-gsm_bssmap_le.c	\
 	packet-gsm_sms.c	\
Index: epan/dissectors/packet-gsm_ipa_iml.c
===================================================================
--- epan/dissectors/packet-gsm_ipa_iml.c	(revision 0)
+++ epan/dissectors/packet-gsm_ipa_iml.c	(revision 0)
@@ -0,0 +1,318 @@
+/* packet-ipa-iml.c
+ * Routines for ip.access BTS Internal Management Link dissection
+ * Copyright 2005, ip.access Ltd <Neil.Piercy@ipaccess.com>
+ *
+ * $Id: epan/dissectors/packet-ipa-iml.c 1.1 2006/07/13 18:50:51BST Neil P Piercy (npp) Exp  $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@unicom.net>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from README.developer
+ * 
+ * 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 <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include <epan/packet.h>
+#include "packet-gsm.h"
+
+static void dissect_ipa_iml_ie(guint8 msg_type, const ie_def_t *ie_defs, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *top_tree);
+
+/* Initialize the protocol and registered fields */
+static int proto_ipa_iml = -1;
+static int hf_ipa_iml_msg_type = -1;
+static int hf_ipa_iml_ie_ei = -1;
+static int hf_ipa_iml_ie_len8 = -1;
+static int hf_ipa_iml_ie_len16 = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_ipa_iml = -1;
+static gint ett_ipa_iml_ie = -1;
+
+static dissector_handle_t ipa_iml_handle;
+static dissector_handle_t data_handle;
+
+/* Value Strings */
+static const value_string msg_type_vals[] = {
+	{ 0, NULL }
+};
+
+static const value_string ie_ei_vals[] = {
+	{ 0, NULL }
+};
+
+
+static const ie_def_t ie_defs[] = {
+	{ 0, NULL, 0, NULL, NULL }
+};
+
+
+/* Code to dissect the iml packets */
+void
+dissect_ipa_iml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *main_tree)
+{
+	int offset=0, msg_len;
+	guint8 msg_type;
+	tvbuff_t *next_tvb;
+
+	/* Set up structures needed to add the protocol subtree and manage it */
+	proto_item *ti=NULL;
+	proto_tree *tree=NULL;
+
+	/* load the display labels 	*/
+	pinfo->current_proto = "ipa_iml";
+	
+	if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
+		col_add_str(pinfo->cinfo, COL_PROTOCOL, "iml");
+
+	msg_len = tvb_length_remaining(tvb,offset);
+	if (main_tree) {
+		/* create display subtree for the protocol */
+		ti = proto_tree_add_item(main_tree, proto_ipa_iml, tvb, offset, msg_len, FALSE);
+		tree = proto_item_add_subtree(ti, ett_ipa_iml);
+	}
+
+	if (msg_len>=1) {
+		msg_type = tvb_get_guint8(tvb, offset);
+		if (tree)
+			proto_tree_add_uint(tree, hf_ipa_iml_msg_type, tvb, offset, 1, msg_type);
+		offset += 1;
+		if (tree)
+			proto_item_set_text(ti, " iml: %s", rd_match_strval(msg_type, msg_type_vals));
+
+		if (check_col(pinfo->cinfo, COL_INFO))
+			col_append_fstr(pinfo->cinfo, COL_INFO, "iml:%s",rd_match_strval(msg_type,msg_type_vals));
+
+		next_tvb = tvb_new_subset(tvb, offset, msg_len-offset, -1);
+
+		dissect_ipa_iml_ie(msg_type, ie_defs, next_tvb, pinfo, tree, main_tree);
+
+	}
+	else {
+	 /* Duff or ... FIXME - partial message !!! */
+		if (main_tree)
+			proto_tree_add_text(main_tree, tvb, offset, tvb_length_remaining(tvb,offset),"Short Message!!!");
+		if (check_col(pinfo->cinfo, COL_INFO))
+			col_append_fstr(pinfo->cinfo, COL_INFO, " Short Message!!!");
+	}
+	return;
+}
+
+/* Code to dissect the IEs */
+void
+dissect_ipa_iml_ie( guint8 msg_type, const ie_def_t *ie_defs, tvbuff_t *tvb, packet_info *pinfo, proto_tree *main_tree, proto_tree *top_tree)
+{
+	int offset=0, msg_len, i;
+	guint8	ie_ei, ie_len8;
+	guint16 ie_len16, ie_len;
+	const ie_def_t	*p_ie_def;
+	tvbuff_t *new_tvb;
+	proto_item *ti=NULL, *hidden;
+	proto_tree *tree=NULL;
+	gchar	str[3*MAX_DATA_STR+4];
+
+	msg_len = tvb_length_remaining(tvb,offset);
+
+	if (msg_len>0) {
+		ie_ei = tvb_get_guint8(tvb, offset);
+		if (main_tree) {
+			hidden = proto_tree_add_uint(main_tree, hf_ipa_iml_ie_ei, tvb, offset, 1, ie_ei);
+                        PROTO_ITEM_SET_HIDDEN(hidden);
+                }
+		offset += 1;
+
+		for (p_ie_def=ie_defs; p_ie_def->ie_name!=0; p_ie_def++) {
+			if (p_ie_def->ie_ei==ie_ei)
+				break;
+		}
+
+		if (p_ie_def->ie_name!=0) {
+			if (p_ie_def->ie_len == 0){
+				ie_len=0;
+				if (main_tree)
+                                    ti = proto_tree_add_text(main_tree, tvb, 0, 1, "%s", p_ie_def->ie_name);
+			}
+			else if (p_ie_def->ie_len > 0) {
+				ie_len = p_ie_def->ie_len;
+
+				if (main_tree) {
+					if (p_ie_def->ie_disector==NULL && p_ie_def->info) {
+						ti = proto_tree_add_text(main_tree, tvb, 0, ie_len+1, "%s: %s", p_ie_def->ie_name, rd_match_strval(tvb_get_guint8(tvb, offset),(value_string *)(p_ie_def->info)));
+						for (i=2; i<ie_len+1; i++)
+							proto_item_append_text(ti, ", %s", rd_match_strval(tvb_get_guint8(tvb, i),(value_string *)(p_ie_def->info)));
+					}
+					else {
+						ti = proto_tree_add_text(main_tree, tvb, 0, ie_len+1, "%s: %s", p_ie_def->ie_name, data_str( tvb, offset, ie_len, str, sizeof(str) ));
+						tree = proto_item_add_subtree(ti, ett_ipa_iml_ie);
+					}
+				}
+			}
+			else if (p_ie_def->ie_len == -1) {
+				ie_len8 = tvb_get_guint8(tvb, offset);
+
+				if (main_tree) {
+					hidden = proto_tree_add_uint(main_tree, hf_ipa_iml_ie_len8, tvb, offset, 1, ie_len8);
+                                        PROTO_ITEM_SET_HIDDEN(hidden);
+					if (p_ie_def->ie_disector==NULL && p_ie_def->info) {
+						ti = proto_tree_add_text(main_tree, tvb, 0, ie_len8+2, "%s:", p_ie_def->ie_name);
+						for (i=2; i<ie_len8+2; i++) {
+							if (i==2)
+								proto_item_append_text(ti, " %s", rd_match_strval(tvb_get_guint8(tvb, i),(value_string *)(p_ie_def->info)));
+							else
+								proto_item_append_text(ti, ", %s", rd_match_strval(tvb_get_guint8(tvb, i),(value_string *)(p_ie_def->info)));
+						}
+					}
+					else {
+						ti = proto_tree_add_text(main_tree, tvb, 0, ie_len8+2, "%s: %s", p_ie_def->ie_name, data_str( tvb, offset+1, ie_len8, str, sizeof(str) ));
+						tree = proto_item_add_subtree(ti, ett_ipa_iml_ie);
+					}
+				}
+				offset += 1;
+				ie_len = ie_len8;
+			}
+			else if (p_ie_def->ie_len == -2) {
+				ie_len16 = tvb_get_ntohs(tvb, offset);
+
+				if (main_tree) {
+					hidden = proto_tree_add_uint(main_tree, hf_ipa_iml_ie_len16, tvb, offset, 2, ie_len16);
+                                        PROTO_ITEM_SET_HIDDEN(hidden);
+					if (p_ie_def->ie_disector==NULL && p_ie_def->info) {
+						ti = proto_tree_add_text(main_tree, tvb, 0, ie_len16+3, "%s:", p_ie_def->ie_name);
+						for (i=3; i<ie_len16+3; i++) {
+							if (i==3)
+								proto_item_append_text(ti, " %s", rd_match_strval(tvb_get_guint8(tvb, i),(value_string *)(p_ie_def->info)));
+							else
+								proto_item_append_text(ti, ", %s", rd_match_strval(tvb_get_guint8(tvb, i),(value_string *)(p_ie_def->info)));
+						}
+					}
+					else {
+						ti = proto_tree_add_text(main_tree, tvb, 0, ie_len16+3, "%s: %s", p_ie_def->ie_name, data_str( tvb, offset+2, ie_len16, str, sizeof(str) ));
+						tree = proto_item_add_subtree(ti, ett_ipa_iml_ie);
+					}
+				}
+				offset += 2;
+				ie_len = ie_len16;
+			}
+			else {			/* should never happen */
+				ie_len=0; /* safety! */
+			}
+
+			if (ie_len>0) {
+				new_tvb = tvb_new_subset(tvb, offset, ie_len, -1);
+				if (p_ie_def->ie_disector!=NULL)
+					(*p_ie_def->ie_disector)(msg_type, new_tvb, pinfo, tree, top_tree, p_ie_def->info);
+				else
+					call_dissector(data_handle, new_tvb, pinfo, tree);
+				offset+=ie_len;
+			}
+		
+				/* only recurse to this disector if this ie was decoded OK */
+			if (tvb_length_remaining(tvb,offset)>0) {
+
+				/* use a new subset TVB for the recursion */
+				new_tvb = tvb_new_subset(tvb, offset, -1, -1);
+
+				dissect_ipa_iml_ie(msg_type, ie_defs, new_tvb, pinfo, main_tree, top_tree);
+			}
+		}
+	}
+	return;
+}
+
+/* Register the protocol with Ethereal */
+
+/* this format is require because a script is used to build the C function
+   that calls all the protocol registration.
+*/
+
+void
+proto_register_ipa_iml(void)
+{		 
+
+/* Setup list of header fields  See Section 1.6.1 for details*/
+	static hf_register_info hf[] = {
+		{ &hf_ipa_iml_msg_type,
+			{ "Msg Type", "ipa_iml.msg_type",
+			FT_UINT8, BASE_HEX, VALS(msg_type_vals), 0x0,	  
+			"Message Type", HFILL }
+		},
+		{ &hf_ipa_iml_ie_ei,
+			{ "IE", "ipa_iml.ie.ei",
+			FT_UINT8, BASE_HEX, VALS(ie_ei_vals), 0x0,	  
+			"IE Element Identifier", HFILL }
+		},
+		{ &hf_ipa_iml_ie_len8,
+			{ "IE Len", "ipa_iml.ie.len8",
+			FT_UINT8, BASE_DEC, NULL, 0x0,	  
+			"IE Length", HFILL }
+		},
+		{ &hf_ipa_iml_ie_len16,
+			{ "IE Len", "ipa_iml.ie.len16",
+			FT_UINT16, BASE_DEC, NULL, 0x0,	  
+			"IE Length", HFILL }
+		},
+	};
+
+/* Setup protocol subtree array */
+	static gint *ett[] = {
+		&ett_ipa_iml,
+		&ett_ipa_iml_ie,
+	};
+
+	proto_ipa_iml = proto_register_protocol("ip.access Internal Management Link (IML)", "IML", "ipa_iml");
+
+	register_dissector("ipa_iml", dissect_ipa_iml, proto_ipa_iml);
+
+/* Required function calls to register the header fields and subtrees used */
+	proto_register_field_array(proto_ipa_iml, hf, array_length(hf));
+	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.
+
+   We use a Heuristic registration if the TCP port number isn't fixed
+   but if there is a defined port number register that instead
+*/
+void
+proto_reg_handoff_ipa_iml(void)
+{
+    ipa_iml_handle = find_dissector("ipa_iml");
+    data_handle = find_dissector("data");
+}
