Ethereal-dev: [ethereal-dev] Patch for ISIS support

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

From: Stuart Stanley <stuarts@xxxxxxxxxxxxxx>
Date: Tue, 14 Dec 1999 20:38:23 +0000 ( )
Attached is the patch file and new files for ISIS dissection.  As of
yet, I have been unable to test the CSNP and PSNP decodes, since in
an ok network they don't show up.  I should hopefully be able to force
these failure cases during the next week or two and submit patches if
there are problems (they decodes are pretty simple).

New files are:
packet-isis.h
packet-isis.c
packet-isis-hello.h
packet-isis-hello.c
packet-isis-lsp.h
packet-isis-lsp.c
packet-isis-snp.h
packet-isis-snp.c
packet-isis-clv.h
packet-isis-clv.c

Modified files are:
AUTHORS
Makefile.am
packet-osi.c


 "Computer Science is no more about computers than | Stuart Stanley
 astronomy is about telescopes." - E. W. Dijkstra  | stuarts@xxxxxxxxxx
                                                   | Lucent Technologies,
                                                   | Eden Prairie, MN
                                                   | 612.996.6829
/* packet-isis-clv.c
 * Common CLV decode routines.
 *
 * $Id: packet-osi.c,v 1.12 1999/11/16 11:42:44 guy Exp $
 * Stuart Stanley <stuarts@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "packet.h"
#include "packet-isis.h"
#include "packet-isis-clv.h"


/*
 * Name: isis_dissect_area_address_clv()
 * 
 * Description:
 *	Take an area address CLV and display it pieces.  An area address
 *	CLV is n, x byte hex strings.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 * 
 * Output:
 *	void, but we will add to proto tree if !NULL.
 */
void 
isis_dissect_area_address_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree ) {
	char 		*sbuf;
	int		mylen;

	while ( length > 0 ) {
		mylen = pd[offset];
		length--;
		if (length<=0) {
			isis_dissect_unknown( offset, length, tree, fd,
				"short address (no length for payload)");
			return;
		}
		if ( mylen > length) {
			isis_dissect_unknown(offset, length, tree, fd, 
				"short address, packet say %d, we have %d left",
				mylen, length );
			return;
		}

		/* 
		 * Lets turn the area address into "standard" 0000.0000.etc
		 * format string.  
		 */
		sbuf = isis_address_to_string ( pd, offset + 1, mylen );
		/* and spit it out */
		if ( tree ) {
			proto_tree_add_text ( tree, offset, mylen + 1,  
				"Area address (%d): %s", mylen, sbuf );
		}
		offset += mylen + 1;
		length -= mylen;	/* length already adjusted for len fld*/
	}
}


/*
 * Name: isis_dissect_authentication_clv()
 * 
 * Description:
 *	Take apart the CLV that hold authentication information.  This
 *	is currently 1 octet auth type (which must be 1) and then
 *	the clear text password.
 *	
 *	An ISIS password has different meaning depending where it
 *	is found.  Thus we support a passed in prefix string to 
 *	use to name this.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *	char * : Password meaning
 * 
 * Output:
 *	void, but we will add to proto tree if !NULL.
 */
void 
isis_dissect_authentication_clv(const u_char *pd, int offset, guint length, 
		frame_data *fd, proto_tree *tree, char *meaning) {
	u_char pw_type;
	char sbuf[300];		/* 255 + header info area */
	char *s = sbuf;
	int use_cleartext;

	if ( length <= 0 ) {
		return;
	}

	pw_type = pd[offset++];
	length--;
	use_cleartext = FALSE;
	switch (pw_type) {
	case 1:
		s += sprintf ( s, "type 1, clear text"  );
		use_cleartext = TRUE;
		break;
	default:
		s += sprintf ( s, "type 0x%02x, (must be 1)", pw_type );
		break;
	}

	s += sprintf ( s, " (0x%02x): ", length );

	if ( use_cleartext ) {
		if ( length > 0 ) {
			strncpy(s, &pd[offset], length);
			/* null terminate */
			s[length] = 0;
		} else {
			strcat(s, "<<no password found!!!>>" );
		}
	/* NOTE, s no longer valid */
	}
	proto_tree_add_text ( tree, offset - 1, length + 1,
			"%s %s", meaning, sbuf );
	if ( !use_cleartext ) {
		if ( length ) {
			isis_dissect_unknown(offset, length, tree, fd,
				"Unknown autheticion type" );
		}
	}
}
/*
 * Name: isis_dissect_ip_int_clv()
 * 
 * Description:
 *	Take apart the CLV that lists all the IP interfaces.  The
 *	meaning of which is slightly different for the different base packet
 *	types, but the display is not different.  What we have is n ip
 *	addresses, plain and simple.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *	gint : tree id to use for proto tree.
 * 
 * Output:
 *	void, but we will add to proto tree if !NULL.
 */
void 
isis_dissect_ip_int_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree, gint tree_id ) {
	guint32 addr;
	if ( length <= 0 ) {
		return;
	}

	while ( length > 0 ) {
		if ( length < 4 ) {
			isis_dissect_unknown(offset, length, tree, fd,
				"Short ip interface address (%d vs 4)",length );
			return;
		}
		memcpy(&addr, &pd[offset], sizeof(addr));
		if ( tree ) {
			proto_tree_add_item(tree, tree_id, offset, 4, addr);
		}
		offset += 4;
		length -= 4;
	}
}

/*
 * Name: isis_dissect_nlpid_clv()
 * 
 * Description:
 *	Take apart a NLPID packet and display it.  The NLPID (for intergrated
 *	ISIS, contains n network layer protocol IDs that the box supports.
 *	Our display buffer we use is upto 255 entries, 6 bytes per (0x00, )
 *	plus 1 for zero termination.  We just just 256*6 for simplicity.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 * 
 * Output:
 *	void, but we will add to proto tree if !NULL.
 */
void 
isis_dissect_nlpid_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree ) {
	char sbuf[256*6];
	char *s = sbuf;
	int hlen = length;
	int old_offset = offset;

	if ( !tree ) return;		/* nothing to do! */

	while ( length-- > 0 ) {
		if (s != sbuf ) {
			s += sprintf ( s, ", " );
		} 
		s += sprintf ( s, "0x%02x", pd[offset++] );
	}
	if ( hlen == 0 ) {
		sprintf ( sbuf, "--none--" );
	}

	proto_tree_add_text ( tree, old_offset, hlen,
			"NLPID: %s", sbuf );
}

/*
 * Name: isis_dissect_clvs()
 * 
 * Description:
 *	Dispatch routine to shred all the CLVs in a packet.  We just
 *	walk through the clv entries in the packet.  For each one, we
 *	search the passed in valid clv's for this protocol (opts) for
 *	a matching code.  If found, we add to the display tree and
 *	then call the dissector.  If it is not, we just post an
 *	"unknown" clv entrie using the passed in unknown clv tree id.
 *
 * Input:
 *	isis_clv_handle_t * : NULL dissector terminated array of codes
 *		and handlers (along with tree text and tree id's).
 *	int : length of CLV area.
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *	gint : unknown clv tree id
 * 
 * Output:
 *	void, but we will add to proto tree if !NULL.
 */
void 
isis_dissect_clvs(const isis_clv_handle_t *opts, int len, 
		const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
		gint unknown_tree_id ) { 
	guint8 code;
	guint8 length;
	int q;
	proto_item	*ti;
	proto_tree	*clv_tree;
	char		sbuf[255];
	int 		adj;

	while ( len > 0 ) {
		code = pd[offset++];
		length = pd[offset++];
		adj = (sizeof(code) + sizeof(length) + length);
		len -= adj;
		if ( len < 0 ) {
			isis_dissect_unknown(offset, adj, tree, fd,
				"Short CLV header (%d vs %d)",
				adj, len + adj );
			return;
		}
		q = 0;
		while ((opts[q].dissect != NULL )&&( opts[q].optcode != code )){
			q++;
		}
		if ( opts[q].dissect ) {
			if (tree) {
				/* adjust by 2 for code/len octets */
				snprintf ( sbuf, sizeof(sbuf), "%s (%d)", 
					opts[q].tree_text, length ); 
				ti = proto_tree_add_text(tree, offset - 2, 
					length + 2, sbuf);
				clv_tree = proto_item_add_subtree(ti, 
					*opts[q].tree_id );
			} else {
				clv_tree = NULL;
			}
			opts[q].dissect(pd, offset, length, fd, clv_tree );
		} else {
			if (tree) { 
				snprintf ( sbuf, sizeof(sbuf), 
					"Unknown code (%d:%d)", code, length ); 
				ti = proto_tree_add_text(tree, offset - 2, 
					length + 2, sbuf);
				clv_tree = proto_item_add_subtree(ti, 
					unknown_tree_id );
			} else { 
				clv_tree = NULL;
			}
		}
		offset += length;
	}
}
/* packet-isis-clv.h
 * Declares for common clv decoding functions.
 *
 * $Id: packet-osi.c,v 1.12 1999/11/16 11:42:44 guy Exp $
 * Stuart Stanley <stuarts@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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.
 *
 *
 */
#ifndef _PACKET_ISIS_CLV_H
#define _PACKET_ISIS_CLV_H

/*
 * Our sub-packet dismantle structure for CLV's
 */
typedef struct {
	int	optcode;		/* code for option */
	char	*tree_text;		/* text for fold out */
	gint	*tree_id;		/* id for add_item */
	void	(*dissect)(const u_char *pd, int offset, guint length,
			frame_data *fd, proto_tree *tree );
} isis_clv_handle_t;

/*
 * Published API functions.  NOTE, this are "local" API functions and
 * are only valid from with isis decodes.
 */
extern void isis_dissect_clvs(const isis_clv_handle_t *opts, int len,
        const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
	int unknown_ett_handle );
extern void isis_dissect_area_address_clv(const u_char *pd, int offset,
                guint length, frame_data *fd, proto_tree *tree );
extern void isis_dissect_metric(proto_tree *tree, int offset, guint8 value,
                char *pstr, int force_supported, gint tree_id );
extern void isis_dissect_authentication_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree, char *meaning);
extern void isis_dissect_ip_int_clv(const u_char *pd, int offset,
		guint length, frame_data *fd, proto_tree *tree, gint tree_id );
extern void isis_dissect_nlpid_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree );
#endif /* _PACKET_ISIS_CLV_H */
/* packet-isis-hello.c
 * Routines for decoding isis hello packets and their CLVs
 *
 * $Id: packet-osi.c,v 1.12 1999/11/16 11:42:44 guy Exp $
 * Stuart Stanley <stuarts@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "packet.h"
#include "packet-isis.h"
#include "packet-isis-clv.h"
#include "packet-isis-hello.h"

/* hello packets */
static int proto_isis_hello = -1;
static int hf_isis_hello_circuit_reserved = -1;
static int hf_isis_hello_source_id = -1;
static int hf_isis_hello_holding_timer = -1;
static int hf_isis_hello_pdu_length = -1;
static int hf_isis_hello_priority_reserved = -1;
static int hf_isis_hello_lan_id = -1;
static int hf_isis_hello_local_circuit_id = -1;
static int hf_isis_hello_clv_ipv4_int_addr = -1;

static gint ett_isis_hello = -1;
static gint ett_isis_hello_clv_area_addr = -1;
static gint ett_isis_hello_clv_is_neighbors = -1;
static gint ett_isis_hello_clv_padding = -1;
static gint ett_isis_hello_clv_unknown = -1;
static gint ett_isis_hello_clv_nlpid = -1;
static gint ett_isis_hello_clv_auth = -1;
static gint ett_isis_hello_clv_ipv4_int_addr = -1;

static const value_string isis_hello_circuit_type_vals[] = {
	{ ISIS_HELLO_TYPE_RESERVED,	"Reserved 0 (discard PDU)"},
	{ ISIS_HELLO_TYPE_LEVEL_1,	"Level 1 only"},
	{ ISIS_HELLO_TYPE_LEVEL_2,	"Level 2 only"},
	{ ISIS_HELLO_TYPE_LEVEL_12,	"Level 1 and 2"},
	{ 0,		NULL} };

/* 
 * Predclare dissectors for use in clv dissection.
 */
static void dissect_hello_area_address_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_hello_is_neighbors_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_hello_padding_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_hello_nlpid_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_hello_ip_int_addr_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_hello_auth_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);

static const isis_clv_handle_t clv_l1_hello_opts[] = {
	{
		ISIS_CLV_L1H_AREA_ADDRESS,
		"Area address(es)",
		&ett_isis_hello_clv_area_addr,
		dissect_hello_area_address_clv
	},
	{
		ISIS_CLV_L1H_IS_NEIGHBORS,
		"IS Neighbor(s)",
		&ett_isis_hello_clv_is_neighbors,
		dissect_hello_is_neighbors_clv
	},
	{
		ISIS_CLV_L1H_PADDING,
		"Padding",
		&ett_isis_hello_clv_padding,
		dissect_hello_padding_clv
	},
	{
		ISIS_CLV_L1H_NLPID,
		"NLPID",
		&ett_isis_hello_clv_nlpid,
		dissect_hello_nlpid_clv
	},
	{
		ISIS_CLV_L1H_IP_INTERFACE_ADDR,
		"IP Interface address(es)",
		&ett_isis_hello_clv_ipv4_int_addr,
		dissect_hello_ip_int_addr_clv
	},
	{
		ISIS_CLV_L1H_AUTHENTICATION_NS,
		"Authentication(non spec)",
		&ett_isis_hello_clv_auth,
		dissect_hello_auth_clv
	},
	{
		ISIS_CLV_L1H_AUTHENTICATION,
		"Authentication",
		&ett_isis_hello_clv_auth,
		dissect_hello_auth_clv
	},
	{
		0,
		"",
		NULL,
		NULL
	}
};

static const isis_clv_handle_t clv_l2_hello_opts[] = {
	{
		ISIS_CLV_L2H_AREA_ADDRESS,
		"Area address(es)",
		&ett_isis_hello_clv_area_addr,
		dissect_hello_area_address_clv
	},
	{
		ISIS_CLV_L2H_IS_NEIGHBORS,
		"IS Neighbor(s)",
		&ett_isis_hello_clv_is_neighbors,
		dissect_hello_is_neighbors_clv
	},
	{
		ISIS_CLV_L2H_PADDING,
		"Padding",
		&ett_isis_hello_clv_padding,
		dissect_hello_padding_clv
	},
	{
		ISIS_CLV_L2H_NLPID,
		"NLPID",
		&ett_isis_hello_clv_nlpid,
		dissect_hello_nlpid_clv
	},
	{
		ISIS_CLV_L2H_IP_INTERFACE_ADDR,
		"IP Interface address(es)",
		&ett_isis_hello_clv_ipv4_int_addr,
		dissect_hello_ip_int_addr_clv
	},
	{
		ISIS_CLV_L2H_AUTHENTICATION_NS,
		"Authentication(non spec)",
		&ett_isis_hello_clv_auth,
		dissect_hello_auth_clv
	},
	{
		ISIS_CLV_L2H_AUTHENTICATION,
		"Authentication",
		&ett_isis_hello_clv_auth,
		dissect_hello_auth_clv
	},
	{
		0,
		"",
		NULL,
		NULL
	}
};

static const isis_clv_handle_t clv_ptp_hello_opts[] = {
	{
		ISIS_CLV_PTP_AREA_ADDRESS,
		"Area address(es)",
		&ett_isis_hello_clv_area_addr,
		dissect_hello_area_address_clv
	},
	{
		ISIS_CLV_PTP_PADDING,
		"Padding",
		&ett_isis_hello_clv_padding,
		dissect_hello_padding_clv
	},
	{
		ISIS_CLV_PTP_NLPID,
		"NLPID",
		&ett_isis_hello_clv_nlpid,
		dissect_hello_nlpid_clv
	},
	{
		ISIS_CLV_PTP_IP_INTERFACE_ADDR,
		"IP Interface address(es)",
		&ett_isis_hello_clv_ipv4_int_addr,
		dissect_hello_ip_int_addr_clv
	},
	{
		ISIS_CLV_PTP_AUTHENTICATION_NS,
		"Authentication(non spec)",
		&ett_isis_hello_clv_auth,
		dissect_hello_auth_clv
	},
	{
		ISIS_CLV_PTP_AUTHENTICATION,
		"Authentication",
		&ett_isis_hello_clv_auth,
		dissect_hello_auth_clv
	},
	{
		0,
		"",
		NULL,
		NULL
	}
};

/*
 * Name: dissect_hello_nlpid_clv()
 *
 * Description:
 *	Decode for a hello packets NLPID clv.  Calls into the
 *	clv common one.
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_hello_nlpid_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_nlpid_clv(pd, offset, length, fd, tree );
}

/*
 * Name: dissect_hello_ip_int_addr_clv()
 *
 * Description:
 *	Decode for a hello packets ip interface addr clv.  Calls into the
 *	clv common one.
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_hello_ip_int_addr_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_ip_int_clv(pd, offset, length, fd, tree, 
		hf_isis_hello_clv_ipv4_int_addr );
}

/*
 * Name: dissect_hello_auth_clv()
 *
 * Description:
 *	Decode for a hello packets authenticaion clv.  Calls into the
 *	clv common one.  An auth inside a hello packet is a perlink
 *	password.
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_hello_auth_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
		"Per Link authentication" );
}

/*
 * Name: dissect_hello_area_address_clv()
 *
 * Description:
 *	Decode for a hello packets area address clv.  Calls into the
 *	clv common one.
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_hello_area_address_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_area_address_clv(pd, offset, length, fd, tree );
}

/*
 * Name: isis_dissect_is_neighbors_clv()
 * 
 * Description:
 *	Take apart a IS neighbor packet.  A neighbor is n 6 byte packets.
 *	(they tend to be an 802.3 MAC address, but its not required).
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *	gint : tree id to use for proto tree.
 * 
 * Output:
 *	void, but we will add to proto tree if !NULL.
 */
void 
dissect_hello_is_neighbors_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree ) {
	while ( length > 0 ) {
		if (length<6) {
			isis_dissect_unknown(offset, length, tree, fd, 
				"short is neighbor (%d vs 6)", length );
			return;
		}
		/* 
		 * Lets turn the area address into "standard" 0000.0000.etc
		 * format string.  
		 */
		if ( tree ) {
			proto_tree_add_text ( tree, offset, 6, 
				"IS Neighbor: %02x%02x.%02x%02x.%02x%02x",
				pd[offset], pd[offset+1], pd[offset+2],
				pd[offset+3], pd[offset+3], pd[offset+4] );
		}
		offset += 6;
		length -= 6;
	}
}


/*
 * Name: dissect_hello_padding_clv()
 *
 * Description:
 *	Decode for a hello packet's padding clv.  Padding does nothing,
 *	so we just return.
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void
 */
static void 
dissect_hello_padding_clv(const u_char *pd, int offset, guint length, 
		frame_data *fd, proto_tree *tree) {
	/* nothing to do here! */
}

/*
 * Name: isis_dissect_isis_hello()
 * 
 * Description:
 *	This procedure rips apart the various types of ISIS hellos.  L1H and
 *	L2H's are identicle for the most part, while the PTP hello has
 *	a shorter header.
 *
 * Input:
 *	int : hello type, alla packet-isis.h ISIS_TYPE_* values
 *	int : header length of packet.
 *	u_char * : packet data
 *	int offset : our offset into packet data.
 *	frame_data * : frame data
 *	proto_tree * : protocol display tree to add to.  May be NULL.
 *
 * Output:
 *	void, will modify proto_tree if not NULL.
 */	
void 
isis_dissect_isis_hello(int hello_type, int header_length, 
		const u_char *pd, int offset, frame_data *fd, proto_tree *tree){
	isis_hello_t	*ihp;
	proto_item	*ti;
	proto_tree	*hello_tree = NULL;
	int 		len;
	int		hlen;

	if (hello_type == ISIS_TYPE_PTP_HELLO) {
		hlen = sizeof(*ihp) - 6;	/* make length correct */
	} else {
		hlen = sizeof(*ihp);
	}

	if (fd->cap_len < (offset + hlen)) {
		isis_dissect_unknown(offset, hlen, tree, fd,
			"not enough capture data for header (%d vs %d)",
			hlen, offset - fd->cap_len);
		return;
	}

	ihp = (isis_hello_t *) &pd[offset];	

	if (tree) {
		ti = proto_tree_add_item(tree, proto_isis_hello,
			offset, fd->cap_len - offset, NULL);
		hello_tree = proto_item_add_subtree(ti, ett_isis_hello);
		proto_tree_add_item_format(hello_tree, 
			hf_isis_hello_circuit_reserved,
			offset, 1, ihp->isis_hello_circuit_reserved,
			"Circuit type: %s, reserved(0x%02x == 0)",
				val_to_str(ihp->isis_hello_circuit, 
					isis_hello_circuit_type_vals,
					"Unknown (0x%x)"),
				ihp->isis_hello_creserved
			);

		proto_tree_add_item_format(hello_tree, hf_isis_hello_lan_id,
			offset + 1, 6, ihp->isis_hello_source_id,
			"Lan ID: %02x%02x.%02x%02x.%02x%02x",
				ihp->isis_hello_lan_id[0],
				ihp->isis_hello_lan_id[1],
				ihp->isis_hello_lan_id[2],
				ihp->isis_hello_lan_id[3],
				ihp->isis_hello_lan_id[4],
				ihp->isis_hello_lan_id[5]);
		proto_tree_add_item(hello_tree, hf_isis_hello_holding_timer,
			offset + 7, 2,pntohs(&ihp->isis_hello_holding_timer[0]));
		proto_tree_add_item(hello_tree, hf_isis_hello_pdu_length,
			offset + 9, 2,pntohs(&ihp->isis_hello_pdu_length[0]));
		proto_tree_add_item_format(hello_tree, 
			hf_isis_hello_priority_reserved,
			offset + 11, 1, ihp->isis_hello_priority_reserved,
			"Priority: %d, reserved(0x%02x == 0)",
				ihp->isis_hello_priority,
				ihp->isis_hello_preserved );
		if (hello_type == ISIS_TYPE_PTP_HELLO) {
			proto_tree_add_item_format(hello_tree, 
				hf_isis_hello_local_circuit_id,
				offset + 12, 1, ihp->isis_hello_lan_id[0] );
		} else { 
			proto_tree_add_item_format(hello_tree, 
				hf_isis_hello_lan_id, offset + 12, 7, 
				ihp->isis_hello_lan_id,
				"Lan ID: %02x%02x.%02x%02x.%02x%02x-%02d",
					ihp->isis_hello_lan_id[0],
					ihp->isis_hello_lan_id[1],
					ihp->isis_hello_lan_id[2],
					ihp->isis_hello_lan_id[3],
					ihp->isis_hello_lan_id[4],
					ihp->isis_hello_lan_id[5],
					ihp->isis_hello_lan_id[6]);
		}
	}

	offset += hlen;
	len = pntohs(&ihp->isis_hello_pdu_length[0]);
	len -= header_length;
	if (len < 0) {
		isis_dissect_unknown(offset, header_length, tree, fd, 
			"packet header length %d went beyond packet", 
			header_length );
		return;
	}
	/*
	 * Now, we need to decode our CLVs.  We need to pass in
	 * our list of valid ones!
	 */
	if (hello_type == ISIS_TYPE_L1_HELLO){
		isis_dissect_clvs ( clv_l1_hello_opts, len, pd, offset, fd, 
			hello_tree, ett_isis_hello_clv_unknown );
	} else if (hello_type == ISIS_TYPE_L2_HELLO) {
		isis_dissect_clvs ( clv_l2_hello_opts, len, pd, offset, fd, 
			hello_tree, ett_isis_hello_clv_unknown );
	} else {
		isis_dissect_clvs ( clv_ptp_hello_opts, len, pd, offset, fd, 
			hello_tree, ett_isis_hello_clv_unknown );
	}
}

/*
 * Name: proto_register_isis_hello()
 *
 * Description:
 *	Register our protocol sub-sets with protocol manager.
 *	NOTE: this procedure is autolinked by the makefile process that
 *		builds register.c
 *
 * Input: 
 *	void
 *
 * Output:
 *	void
 */
void
proto_register_isis_hello(void) {
	static hf_register_info hf[] = {
		{ &hf_isis_hello_circuit_reserved,
		{ "Circuit type",		"", FT_UINT8, BASE_HEX, NULL, 
		  0x0, "" }},

		{ &hf_isis_hello_source_id,
		{ "Source ID",		"isis_hello.source_id", FT_ETHER, 
		  BASE_HEX, NULL, 0x0, "" }},

		{ &hf_isis_hello_holding_timer,
		{ "Holding timer",	"isis_hello.holding_timer", 
		  FT_UINT16, BASE_DEC, NULL, 0x0, "" }},

		{ &hf_isis_hello_pdu_length,
		{ "PDU length",           "isis_hello.pdu_length", FT_UINT16, 
		  BASE_DEC, NULL, 0x0, "" }},

		{ &hf_isis_hello_priority_reserved,
		 { "Priority",		"",FT_UINT8, BASE_DEC, NULL, 
		  ISIS_HELLO_P_RESERVED_MASK, "" }},

		{ &hf_isis_hello_lan_id,
		{ "LAN ID", "", FT_STRING, BASE_DEC, NULL, 0x0, "" }},

		{ &hf_isis_hello_local_circuit_id,
		{ "Local circuit ID", "isis_hello.local_circuit_id", FT_UINT8,
		   BASE_DEC, NULL, 0x0, "" }},

		{ &hf_isis_hello_clv_ipv4_int_addr,
		{ "IPv4 interface address", "", FT_IPv4,
		   BASE_NONE, NULL, 0x0, "" }},

	};
	static gint *ett[] = {
		&ett_isis_hello,
		&ett_isis_hello_clv_area_addr,
		&ett_isis_hello_clv_is_neighbors,
		&ett_isis_hello_clv_padding,
		&ett_isis_hello_clv_unknown,
		&ett_isis_hello_clv_nlpid,
		&ett_isis_hello_clv_auth,
		&ett_isis_hello_clv_ipv4_int_addr,
	};

	proto_isis_hello = proto_register_protocol("ISIS hello", "ISIS-hello");
	proto_register_field_array(proto_isis_hello, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));
}

/* packet-isis-hello.h
 * Declares for hello handling inside isis.
 *
 * $Id: packet-osi.c,v 1.12 1999/11/16 11:42:44 guy Exp $
 * Stuart Stanley <stuarts@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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.
 *
 *
 */

#ifndef _PACKET_ISIS_HELLO_H
#define _PACKET_ISIS_HELLO_H

/*
 * Declare L1/L2 hello base header.  
 */
typedef struct {
	guint8	isis_hello_circuit_reserved;	/* circuit type & reserved */
#define ISIS_HELLO_CTYPE_MASK		0x03
#define ISIS_HELLO_CT_RESERVED_MASK	0xfc
	guint8	isis_hello_source_id[6];	/* source id */
	guint8	isis_hello_holding_timer[2];	/* holding timer */
	guint8	isis_hello_pdu_length[2];	/* full length, including hdr */
	guint8	isis_hello_priority_reserved;	/* priority & reserved */
#define ISIS_HELLO_PRIORITY_MASK	0x7f
#define ISIS_HELLO_P_RESERVED_MASK	0x80
	guint8	isis_hello_lan_id[7];		/* LAN id */
} isis_hello_t;

#define isis_hello_circuit isis_hello_circuit_reserved&ISIS_HELLO_CTYPE_MASK
#define isis_hello_creserved \
	isis_hello_circuit_reserved&ISIS_HELLO_CT_RESERVED_MASK

#define isis_hello_priority \
	isis_hello_priority_reserved&ISIS_HELLO_PRIORITY_MASK
#define isis_hello_preserved \
	isis_hello_priority_reserved&ISIS_HELLO_P_RESERVED_MASK

#define ISIS_HELLO_TYPE_RESERVED	0
#define ISIS_HELLO_TYPE_LEVEL_1		1
#define ISIS_HELLO_TYPE_LEVEL_2		2
#define ISIS_HELLO_TYPE_LEVEL_12	3

/*
 * detail clv information on l1 hello packets
 */
#define ISIS_CLV_L1H_AREA_ADDRESS	1
#define ISIS_CLV_L1H_IS_NEIGHBORS	6
#define ISIS_CLV_L1H_PADDING		8
#define ISIS_CLV_L1H_NLPID		129
#define ISIS_CLV_L1H_IP_INTERFACE_ADDR	132
/*
 * Note, the spec say 133, but everyone seems to use 10. Any clue on why
 * this is would be appreciated!
 */
#define ISIS_CLV_L1H_AUTHENTICATION_NS	10	/*non spec */
#define ISIS_CLV_L1H_AUTHENTICATION	133

/*
 * detail clv information on l2 hello packets
 */
#define ISIS_CLV_L2H_AREA_ADDRESS	1
#define ISIS_CLV_L2H_IS_NEIGHBORS	6
#define ISIS_CLV_L2H_PADDING		8
#define ISIS_CLV_L2H_NLPID		129
#define ISIS_CLV_L2H_IP_INTERFACE_ADDR	132
/*
 * Note, the spec say 133, but everyone seems to use 10. Any clue on why
 * this is would be appreciated!
 */
#define ISIS_CLV_L2H_AUTHENTICATION_NS	10	/*non spec */
#define ISIS_CLV_L2H_AUTHENTICATION	133

/*
 * detail clv information on PTP hello packets
 */
#define ISIS_CLV_PTP_AREA_ADDRESS	1
#define ISIS_CLV_PTP_PADDING		8
#define ISIS_CLV_PTP_NLPID		129
#define ISIS_CLV_PTP_IP_INTERFACE_ADDR	132
/*
 * Note, the spec say 133, but everyone seems to use 10. Any clue on why
 * this is would be appreciated!
 */
#define ISIS_CLV_PTP_AUTHENTICATION_NS	10	/*non spec */
#define ISIS_CLV_PTP_AUTHENTICATION	133

/*
 * Published API functions.  NOTE, this are "local" API functions and
 * are only valid from with isis decodes.
 */
extern void isis_dissect_isis_hello(int hello_type, int header_length,
	const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
#endif /* _PACKET_ISIS_HELLO_H */
/* packet-isis-lsp.c
 * Routines for decoding isis lsp packets and their CLVs
 *
 * $Id: packet-osi.c,v 1.12 1999/11/16 11:42:44 guy Exp $
 * Stuart Stanley <stuarts@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <netinet/in.h>
#include "packet.h"
#include "resolv.h"
#include "packet-isis.h"
#include "packet-isis-clv.h"
#include "packet-isis-lsp.h"

/* lsp packets */
static int proto_isis_lsp = -1;
static int hf_isis_lsp_pdu_length = -1;
static int hf_isis_lsp_remaining_life = -1;
static int hf_isis_lsp_sequence_number = -1;
static int hf_isis_lsp_checksum = -1;
static int hf_isis_lsp_clv_ipv4_int_addr = -1;

static gint ett_isis_lsp = -1;
static gint ett_isis_lsp_clv_area_addr = -1;
static gint ett_isis_lsp_clv_is_neighbors = -1;
static gint ett_isis_lsp_clv_unknown = -1;
static gint ett_isis_lsp_clv_partition_dis = -1;
static gint ett_isis_lsp_clv_prefix_neighbors = -1;
static gint ett_isis_lsp_clv_nlpid = -1;
static gint ett_isis_lsp_clv_auth = -1;
static gint ett_isis_lsp_clv_ipv4_int_addr = -1;
static gint ett_isis_lsp_clv_ip_reachability = -1;

static const char *isis_lsp_attached_bits[] = {
	"error", "expense", "delay", "default" };

static const value_string isis_lsp_istype_vals[] = {
	{ ISIS_LSP_TYPE_UNUSED0,	"Unused 0x0 (invalid)"},
	{ ISIS_LSP_TYPE_LEVEL_1,	"Level 1 IS"},
	{ ISIS_LSP_TYPE_UNUSED2,	"Unused 0x2 (invalid)"},
	{ ISIS_LSP_TYPE_LEVEL_2,	"Level 2 IS"},
	{ 0, NULL } };

/* 
 * Predclare dissectors for use in clv dissection.
 */
static void dissect_lsp_area_address_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_lsp_l1_is_neighbors_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_lsp_l1_es_neighbors_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_lsp_l2_is_neighbors_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_lsp_partition_dis_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_lsp_prefix_neighbors_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_lsp_ip_reachability_clv(const u_char *pd, int offset,
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_lsp_nlpid_clv(const u_char *pd, int offset,
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_lsp_ip_int_addr_clv(const u_char *pd, int offset,
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_lsp_l1_auth_clv(const u_char *pd, int offset,
		guint length, frame_data *fd, proto_tree *tree);
static void dissect_lsp_l2_auth_clv(const u_char *pd, int offset,
		guint length, frame_data *fd, proto_tree *tree);

static const isis_clv_handle_t clv_l1_lsp_opts[] = {
	{
		ISIS_CLV_L1_LSP_AREA_ADDRESS,
		"Area address(es)",
		&ett_isis_lsp_clv_area_addr,
		dissect_lsp_area_address_clv
	},
	{
		ISIS_CLV_L1_LSP_IS_NEIGHBORS,
		"IS Neighbor(s)",
		&ett_isis_lsp_clv_is_neighbors,
		dissect_lsp_l1_is_neighbors_clv
	},
	{
		ISIS_CLV_L1_LSP_ES_NEIGHBORS,
		"ES Neighbor(s)",
		&ett_isis_lsp_clv_is_neighbors,
		dissect_lsp_l1_es_neighbors_clv
	},
	{
		ISIS_CLV_L1_LSP_IP_INT_REACHABLE,
		"IP Internal reachability",
		&ett_isis_lsp_clv_ip_reachability,
		dissect_lsp_ip_reachability_clv
	},
	{
		ISIS_CLV_L1_LSP_NLPID,
		"NLPID",
		&ett_isis_lsp_clv_nlpid,
		dissect_lsp_nlpid_clv
	},
	{
		ISIS_CLV_L1_LSP_IP_INTERFACE_ADDR,
		"IP Interface address(es)",
		&ett_isis_lsp_clv_ipv4_int_addr,
		dissect_lsp_ip_int_addr_clv
	},
	{
		ISIS_CLV_L1_LSP_AUTHENTICATION_NS,
		"Authentication(non-spec)",
		&ett_isis_lsp_clv_auth,
		dissect_lsp_l1_auth_clv
	},
	{
		ISIS_CLV_L1_LSP_AUTHENTICATION,
		"Authentication",
		&ett_isis_lsp_clv_auth,
		dissect_lsp_l1_auth_clv
	},
	{
		0,
		"",
		NULL,
		NULL
	}
};

static const isis_clv_handle_t clv_l2_lsp_opts[] = {
	{
		ISIS_CLV_L1_LSP_AREA_ADDRESS,
		"Area address(es)",
		&ett_isis_lsp_clv_area_addr,
		dissect_lsp_area_address_clv
	},
	{
		ISIS_CLV_L2_LSP_IS_NEIGHBORS,
		"IS Neighbor(s)",
		&ett_isis_lsp_clv_is_neighbors,
		dissect_lsp_l2_is_neighbors_clv
	},
	{
		ISIS_CLV_L2_LSP_PARTITION_DIS,
		"Parition Designated Level 2 IS",
		&ett_isis_lsp_clv_partition_dis,
		dissect_lsp_partition_dis_clv
	},
	{
		ISIS_CLV_L2_LSP_PREFIX_NEIGHBORS,
		"Prefix neighbors",
		&ett_isis_lsp_clv_prefix_neighbors,
		dissect_lsp_prefix_neighbors_clv
	},
	{
		ISIS_CLV_L2_LSP_IP_INT_REACHABLE,
		"IP Internal reachability",
		&ett_isis_lsp_clv_ip_reachability,
		dissect_lsp_ip_reachability_clv
	},
	{
		ISIS_CLV_L2_LSP_NLPID,
		"NLPID",
		&ett_isis_lsp_clv_nlpid,
		dissect_lsp_nlpid_clv
	},
	{
		ISIS_CLV_L2_LSP_IP_EXT_REACHABLE,
		"IP external reachability",
		&ett_isis_lsp_clv_ip_reachability,
		dissect_lsp_ip_reachability_clv
	},
	{
		ISIS_CLV_L2_LSP_IP_INTERFACE_ADDR,
		"IP Interface address(es)",
		&ett_isis_lsp_clv_ipv4_int_addr,
		dissect_lsp_ip_int_addr_clv
	},
	{
		ISIS_CLV_L2_LSP_AUTHENTICATION_NS,
		"Authentication(non spec)",
		&ett_isis_lsp_clv_auth,
		dissect_lsp_l2_auth_clv
	},
	{
		ISIS_CLV_L2_LSP_AUTHENTICATION,
		"Authentication",
		&ett_isis_lsp_clv_auth,
		dissect_lsp_l2_auth_clv
	},
	{
		0,
		"",
		NULL,
		NULL
	}
};


/*
 * Name: dissect_metric()
 * 
 * Description:
 *	Display a metric prefix portion.  ISIS has the concept of multple
 *	metric per prefix (default, delay, expense, and error).  This
 *	routine assists other dissectors by adding a single one of
 *	these to the display tree..  
 *
 *	The 8th(msbit) bit in the metric octet is the "supported" bit.  The
 *		"default" support is required, so we support a "force_supported"
 *		flag that tells us that it MUST be zero (zero==supported,
 *		so it really should be a "not supported" in the boolean sense)
 *		and to display a protocol failure accordingly.  Notably,
 *		Cisco IOS 12(6) blows this!
 *	The 7th bit must be zero (reserved).
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *	int : force supported.  True is the supported bit MUST be zero.
 * 
 * Output:
 *	void, but we will add to proto tree if !NULL.
 */
static void 
dissect_metric(proto_tree *tree, int offset, guint8 value, 
		char *pstr, int force_supported ) {
	int s;

	if ( !tree ) return;

	s = ISIS_LSP_CLV_METRIC_SUPPORTED(value);
	proto_tree_add_text ( tree, offset, 1, 
		"%s Metric: %s%s %s%d:%d", pstr,
		s ? "Not supported" : "Supported",
		(s && force_supported) ? "(but is required to be)":"",
		ISIS_LSP_CLV_METRIC_RESERVED(value) ? "(reserved bit != 0)":"",
		ISIS_LSP_CLV_METRIC_VALUE(value), value );
}
	

/*
 * Name: dissect_lsp_ip_reachabillityclv()
 *
 * Description:
 *	Decode an IP reachability CLV.  This can be either internal or
 *	external (the clv format does not change and which type we are
 *	displaying is put there by the dispatcher).  All of these
 *	are a metric block followed by an IP addr and mask.
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_lsp_ip_reachability_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	proto_item 	*ti;
	proto_tree	*ntree = NULL;
	guint32		src, mask;

	while ( length > 0 ) {
		if (length<12) {
			isis_dissect_unknown(offset, length, tree, fd,
				"short IP reachability (%d vs 12)", length );
			return;
		}
		/* 
		 * Gotta build a sub-tree for all our pieces
		 */
		if ( tree ) {
			memcpy(&src, &pd[offset+4], 4);
			memcpy(&mask, &pd[offset+8], 4);
			ti = proto_tree_add_text ( tree, offset, 12, 
				"IP prefix: %s (%s) : %s",
				get_hostname(src), ip_to_str((guint8*)&src),
				ip_to_str((guint8*)&mask) );
			ntree = proto_item_add_subtree(ti, 
				ett_isis_lsp_clv_ip_reachability);
			dissect_metric ( ntree, offset, pd[offset], "Default", 
				TRUE );
			dissect_metric ( ntree, offset + 1, pd[offset+1], 
				"Delay", FALSE );
			dissect_metric ( ntree, offset + 2, pd[offset+2], 
				"Expense",FALSE );
			dissect_metric ( ntree, offset + 3, pd[offset+3], 
				"Error", FALSE );
		}
		offset += 12;
		length -= 12;
	}
}
/*
 * Name: dissect_lsp_nlpid_clv()
 *
 * Description:
 *	Decode for a lsp packets NLPID clv.  Calls into the
 *	clv common one.
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_lsp_nlpid_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_nlpid_clv(pd, offset, length, fd, tree );
}

/*
 * Name: dissect_lsp_ip_int_addr_clv()
 *
 * Description:
 *	Decode for a lsp packets ip interface addr clv.  Calls into the
 *	clv common one.
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_lsp_ip_int_addr_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_ip_int_clv(pd, offset, length, fd, tree, 
		hf_isis_lsp_clv_ipv4_int_addr );
}

/*
 * Name: dissect_lsp_L1_auth_clv()
 *
 * Description:
 *	Decode for a lsp packets authenticaion clv.  Calls into the
 *	clv common one.  An auth inside a L1 LSP is a per area password
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_lsp_l1_auth_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
		"Per area authentication" );
}

/*
 * Name: dissect_lsp_L2_auth_clv()
 *
 * Description:
 *	Decode for a lsp packets authenticaion clv.  Calls into the
 *	clv common one.  An auth inside a L2 LSP is a per domain password
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_lsp_l2_auth_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
		"Per domain authentication" );
}

/*
 * Name: dissect_lsp_area_address_clv()
 *
 * Description:
 *	Decode for a lsp packet's area address clv.  Call into clv common
 *	one.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
static void 
dissect_lsp_area_address_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_area_address_clv(pd, offset, length, fd, tree );
}

/*
 * Name: dissect_lsp_eis_neighbors_clv_inner()
 *
 * Description:
 *	Real work horse for showing neighbors.  This means we decode the
 *	first octet as either virtual/!virtual (if show_virtual param is
 *	set), or as a must == 0 reserved value.
 *
 *	Once past that, we decode n neighbor elements.  Each neighbor
 *	is comprised of a metric block (is dissect_metric) and the
 *	addresses.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *	int : set to decode first octet as virtual vs reserved == 0
 *	int : set to indicate EIS instead of IS (6 octet per addr instead of 7)
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
static void 
dissect_lsp_eis_neighbors_clv_inner(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree,
		int show_virtual, int is_eis) {
	proto_item 	*ti;
	proto_tree	*ntree = NULL;
	int		tlen;

	if (is_eis) {
		tlen = 10;
	} else {
		tlen = 11;
		if ( tree ) {
			if ( show_virtual ) {
				/* virtual path flag */
				proto_tree_add_text ( tree, offset, 1, 
				   &pd[offset] ? "IsNotVirtual" : "IsVirtual" );
			} else {
				proto_tree_add_text ( tree, offset, 1, 
					"Reserved value 0x%02x, must == 0",
					pd[offset]  );
			}
		}
		offset++;
		length--;
			
	}

	while ( length > 0 ) {
		if (length<tlen) {
			isis_dissect_unknown(offset, length, tree, fd,
				"short E/IS reachability (%d vs %d)", length,
				tlen );
			return;
		}
		/* 
		 * Gotta build a sub-tree for all our pieces
		 */
		if ( tree ) {
			if ( is_eis ) {
				ti = proto_tree_add_text ( tree, offset, 11, 
					"ES Neighbor: %02x%02x.%02x%02x.%02x%02x",
					pd[offset+4], pd[offset+5], 
					pd[offset+6], pd[offset+7], 
					pd[offset+8], pd[offset+9] );
			} else {
				ti = proto_tree_add_text ( tree, offset, 11, 
					"IS Neighbor: %02x%02x.%02x%02x.%02x%02x-%02x",
					pd[offset+4], pd[offset+5], 
					pd[offset+6], pd[offset+7], 
					pd[offset+8], pd[offset+9],
					pd[offset+10] );
			}
			ntree = proto_item_add_subtree(ti, 
				ett_isis_lsp_clv_is_neighbors);
			dissect_metric ( ntree, offset, pd[offset], "Default", 
				TRUE );
			dissect_metric ( ntree, offset + 1, pd[offset+1], 
				"Delay", FALSE );
			dissect_metric ( ntree, offset + 2, pd[offset+2], 
				"Expense",FALSE );
			dissect_metric ( ntree, offset + 3, pd[offset+3], 
				"Error", FALSE );
		}
		offset += tlen;
		length -= tlen;
	}
}

/*
 * Name: dissect_lsp_l1_is_neighbors_clv()
 *
 * Description:
 *	Dispatch a l1 intermediate system neighbor by calling
 *	the inner function with show virtual set to TRUE and is es set to FALSE.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
static void 
dissect_lsp_l1_is_neighbors_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	dissect_lsp_eis_neighbors_clv_inner( pd, offset, length, fd, tree,TRUE,
		FALSE );
}

/*
 * Name: dissect_lsp_l1_es_neighbors_clv()
 *
 * Description:
 *	Dispatch a l1 end or intermediate system neighbor by calling
 *	the inner function with show virtual set to TRUE and es set to TRUE.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
static void 
dissect_lsp_l1_es_neighbors_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	dissect_lsp_eis_neighbors_clv_inner( pd, offset, length, fd, tree,
		TRUE, TRUE);
}

/*
 * Name: dissect_lsp_l2_is_neighbors_clv()
 *
 * Description:
 *	Dispatch a l2 intermediate system neighbor by calling
 *	the inner function with show virtual set to FALSE, and is es set
 *	to FALSE
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
static void 
dissect_lsp_l2_is_neighbors_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	dissect_lsp_eis_neighbors_clv_inner(pd,offset, length, fd, tree, FALSE,
		FALSE);
}

/*
 * Name: dissect_lsp_partition_dis_clv()
 *
 * Description:
 *	This CLV is used to indicate which system is the designated
 *	IS for partition repair.  This means just putting out the 6 octet
 *	IS.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
static void 
dissect_lsp_partition_dis_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {

	if ( length < 6 ) {
		isis_dissect_unknown(offset, length, tree, fd,
				"short lsp parition DIS(%d vs 6)", length );
		return;
	}
	/* 
	 * Gotta build a sub-tree for all our pieces
	 */
	if ( tree ) {
		proto_tree_add_text ( tree, offset+4, 6, 
			"Partition designated L2 IS: %02x%02x.%02x%02x.%02x%02x",
			pd[offset], pd[offset+1], pd[offset+2],
			pd[offset+3], pd[offset+4], pd[offset+5]);
	}
	length -= 6;
	offset +=  6;
	if ( length > 0 ){
		isis_dissect_unknown(offset, length, tree, fd,
				"Long lsp parition DIS, %d left over", length );
		return;
	}
}

/*
 * Name: dissect_lsp_prefix_neighbors_clv()
 *
 * Description:
 *	The prefix CLV describes what other (OSI) networks we can reach
 *	and what their cost is.  It is built from a metric block
 *	(see dissect_metric) followed by n addresses.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
static void 
dissect_lsp_prefix_neighbors_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	char *sbuf;
	int mylen;

	if ( length < 4 ) {
		isis_dissect_unknown(offset, length, tree, fd,
			"Short lsp prefix neighbors (%d vs 4)", length );
		return;
	}
	if ( tree ) {
		dissect_metric ( tree, offset, pd[offset], "Default", TRUE );
		dissect_metric ( tree, offset + 1, pd[offset+1], 
			"Delay", FALSE );
		dissect_metric ( tree, offset + 2, pd[offset+2], 
			"Expense", FALSE );
		dissect_metric ( tree, offset + 3, pd[offset+3], 
			"Error", FALSE );
	}
	offset += 4;
	length -= 4;
	while ( length > 0 ) {
		mylen = pd[offset];
		length--;
		if (length<=0) {
			isis_dissect_unknown(offset, length, tree, fd,
				"Zero payload space after length in prefix neighbor" );
			return;
		}
		if ( mylen > length) {
			isis_dissect_unknown(offset, length, tree, fd,
				"Interal length of prefix neighbor too long (%d vs %d)", 
				mylen, length );
			return;
		}

		/* 
		 * Lets turn the area address into "standard" 0000.0000.etc
		 * format string.  
		 */
		sbuf = isis_address_to_string ( pd, offset + 1, mylen );
		/* and spit it out */
		if ( tree ) {
			proto_tree_add_text ( tree, offset, mylen + 1, 
				"Area address (%d): %s", mylen, sbuf );
		}
		offset += mylen + 1;
		length -= mylen;	/* length already adjusted for len fld*/
	}
}

/*
 * Name: isis_lsp_decode_lsp_id()
 *
 * Description: 
 *	Display a LSP id into the display tree.
 *
 * Input:
 *	char * : title string
 *	proto_tree * : tree to display into. REQUIRED
 *	int : offset into packet data where we are.
 *	isis_lsp_id_t * : id to display.
 *
 * Output:
 *      void, but we will add to proto tree
 */
void
isis_lsp_decode_lsp_id(char *tstr, proto_tree *tree, int offset, 
		isis_lsp_id_t *id ) {
	proto_tree_add_text(tree, offset, 8, 
		"%s: %02x%02x.%02x%02x.%02x%02x.%02x-%02x", tstr,
			id->source_id[0],
			id->source_id[1],
			id->source_id[2],
			id->source_id[3],
			id->source_id[4],
			id->source_id[5],
			id->psuodonode_id,
			id->lsp_number );
}

/*
 * Name: isis_dissect_isis_lsp()
 *
 * Description:
 *	Print out the LSP part of the main header and then call the CLV
 *	de-mangler with the right list of valid CLVs.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
void 
isis_dissect_isis_lsp(int lsp_type, int header_length, 
		const u_char *pd, int offset, frame_data *fd, proto_tree *tree){
	isis_lsp_t	*ilp;
	proto_item	*ti;
	proto_tree	*lsp_tree = NULL;
	int		hlen;
	char		sbuf[128];
	int		inx, q, some, value, len;

	hlen = sizeof(*ilp);

	if (fd->cap_len < (offset + hlen)) {
		isis_dissect_unknown(offset, hlen, tree, fd,
			"not enough capture data for header (%d vs %d)",
			 hlen, offset - fd->cap_len);
		return;
	}
	
	ilp = (isis_lsp_t *) &pd[offset];

	if (tree) {
		ti = proto_tree_add_item(tree, proto_isis_lsp,
			offset, fd->cap_len - offset, NULL);
		lsp_tree = proto_item_add_subtree(ti, ett_isis_lsp);
		proto_tree_add_item(lsp_tree, hf_isis_lsp_pdu_length,
			offset, 2, pntohs(&ilp->isis_lsp_pdu_length));
		proto_tree_add_item(lsp_tree, hf_isis_lsp_remaining_life,
			offset + 2, 2, pntohs(&ilp->isis_lsp_remaining_life));
		isis_lsp_decode_lsp_id("LSP ID", lsp_tree, offset + 4, 
			&ilp->isis_lsp_id );
		proto_tree_add_item(lsp_tree, hf_isis_lsp_sequence_number,
			offset + 12, 4, 
			pntohl(&ilp->isis_lsp_sequence_number));

		/* XXX -> we could validate the cksum here! */
		proto_tree_add_item(lsp_tree, hf_isis_lsp_checksum,
			offset + 16, 2, pntohs(&ilp->isis_lsp_checksum));

		/*
		 * We need to build our type block values. 
		 */
		sbuf[0] = 0;
		some = 0;
		value = ISIS_LSP_ATT(ilp->isis_lsp_type_block);
		inx = 0;
		for ( q = (1<<ISIS_LSP_ATT_SHIFT); q > 0; q = q >> 1 ){
			if (q & value) { 
				if (some++) {
					strcat(sbuf, ", ");
				}
				strcat ( sbuf, isis_lsp_attached_bits[inx] );
			}
			inx++;
		}
		if (!some) { 
			strcat ( sbuf, "<none set!>" );
		}
		proto_tree_add_text(lsp_tree, offset + 18, 1, 
			"Type block(0x%02x): P:%d, Supported metric(s): %s, OL:%d, istype:%s",
			ilp->isis_lsp_type_block, 
			ISIS_LSP_PARTITION(ilp->isis_lsp_type_block) ? 1 : 0,
			sbuf,
			ISIS_LSP_HIPPITY(ilp->isis_lsp_type_block) ? 1 : 0,
			val_to_str(ISIS_LSP_IS_TYPE(ilp->isis_lsp_type_block),
				isis_lsp_istype_vals, "Unknown (0x%x)")
			);

	}

	offset += hlen;
	len = pntohs(&ilp->isis_lsp_pdu_length);
	len -= header_length;
	if (len < 0) {
		isis_dissect_unknown(offset, header_length, tree, fd,
			"packet header length %d went beyond packet",
			 header_length );
		return;
	}
	/*
	 * Now, we need to decode our CLVs.  We need to pass in
	 * our list of valid ones!
	 */
	if (lsp_type == ISIS_TYPE_L1_LSP){
		isis_dissect_clvs ( clv_l1_lsp_opts, len, pd, offset, fd, 
			lsp_tree, ett_isis_lsp_clv_unknown );
	} else {
		isis_dissect_clvs ( clv_l2_lsp_opts, len, pd, offset, fd, 
			lsp_tree, ett_isis_lsp_clv_unknown );
	}
}
/*
 * Name: proto_register_isis_lsp()
 *
 * Description: 
 *	Register our protocol sub-sets with protocol manager.
 *	NOTE: this procedure is autolinked by the makefile process that
 *		builds register.c
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
void 
proto_register_isis_lsp(void) {
	static hf_register_info hf[] = {
		{ &hf_isis_lsp_pdu_length,
		{ "PDU length",		"isis_lsp.pdu_length", FT_UINT16, 
		  BASE_DEC, NULL, 0x0, "" }},

		{ &hf_isis_lsp_remaining_life,
		{ "Remaining life",	"isis_lsp.remaining_life", FT_UINT16, 
		  BASE_DEC, NULL, 0x0, "" }},

		{ &hf_isis_lsp_sequence_number,
		{ "Sequence number",           "isis_lsp.sequence_number", 
		  FT_UINT32, BASE_HEX, NULL, 0x0, "" }},

		{ &hf_isis_lsp_checksum,
		{ "Checksum",		"isis_lsp.checksum",FT_UINT16, 
		  BASE_HEX, NULL, 0x0, "" }},

		{ &hf_isis_lsp_clv_ipv4_int_addr,
		{ "IPv4 interface address: ", "", FT_IPv4,
		   BASE_NONE, NULL, 0x0, "" }},
	};
	static gint *ett[] = {
		&ett_isis_lsp,
		&ett_isis_lsp_clv_area_addr,
		&ett_isis_lsp_clv_is_neighbors,
		&ett_isis_lsp_clv_unknown,
		&ett_isis_lsp_clv_partition_dis,
		&ett_isis_lsp_clv_prefix_neighbors,
		&ett_isis_lsp_clv_auth,
		&ett_isis_lsp_clv_nlpid,
		&ett_isis_lsp_clv_ipv4_int_addr,
		&ett_isis_lsp_clv_ip_reachability,
	};

	proto_isis_lsp = proto_register_protocol("ISIS lsp", "ISIS-lsp");
	proto_register_field_array(proto_isis_lsp, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));
}
/* packet-isis-lsp.h
 * Defines and such for LSP and their CLV decodes
 *
 * $Id: packet-osi.c,v 1.12 1999/11/16 11:42:44 guy Exp $
 * Stuart Stanley <stuarts@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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.
 *
 *
 */

#ifndef _PACKET_ISIS_LSP_H
#define _PACKET_ISIS_LSP_H

/*
 * Declare what an LSP id looks like (used by LSP and sequence number
 * packets)
 */
typedef struct {
	guint8	source_id[6];			/* source id part */
	guint8	psuodonode_id;			/* psn id */
	guint8	lsp_number;			/* frag number */
} isis_lsp_id_t;
   

/*
 * Declare L1/L2 LSP base header.  
 */
typedef struct {
	guint8	isis_lsp_pdu_length[2];		/* pdu length including hdr */
	guint8	isis_lsp_remaining_life[2];	/* seconds before expiration */
	isis_lsp_id_t isis_lsp_id;
	guint8	isis_lsp_sequence_number[4];
	guint8	isis_lsp_checksum[2];
	guint8	isis_lsp_type_block;		/* partition/att/hip/istype */
} isis_lsp_t;

#define ISIS_LSP_PARTITION_MASK	0x80
#define ISIS_LSP_ATT_MASK	0x78
#define ISIS_LSP_ATT_SHIFT	3
#define ISIS_LSP_HIPPITY_MASK	0x04
#define ISIS_LSP_IS_TYPE_MASK	0x03

#define ISIS_LSP_PARTITION(x)	(x&ISIS_LSP_PARTITION_MASK)
#define ISIS_LSP_ATT(x)		((x&ISIS_LSP_ATT_MASK)>>ISIS_LSP_ATT_SHIFT)
#define ISIS_LSP_HIPPITY(x)	(x&ISIS_LSP_HIPPITY_MASK)
#define ISIS_LSP_IS_TYPE(x)	(x&ISIS_LSP_IS_TYPE_MASK)

#define ISIS_LSP_TYPE_UNUSED0		0
#define ISIS_LSP_TYPE_LEVEL_1		1
#define ISIS_LSP_TYPE_UNUSED2		2
#define ISIS_LSP_TYPE_LEVEL_2		3

#define ISIS_LSP_CLV_METRIC_SUPPORTED(x)	((x)&0xf0)
#define ISIS_LSP_CLV_METRIC_RESERVED(x)		((x)&0x40)
#define ISIS_LSP_CLV_METRIC_VALUE(x)		((x)&0x3f)

/*
 * detail clv information on L1 lsp packets
 */
#define ISIS_CLV_L1_LSP_AREA_ADDRESS		1
#define ISIS_CLV_L1_LSP_IS_NEIGHBORS		2
#define ISIS_CLV_L1_LSP_ES_NEIGHBORS		3
#define ISIS_CLV_L1_LSP_IP_INT_REACHABLE	128
#define ISIS_CLV_L1_LSP_NLPID			129
#define ISIS_CLV_L1_LSP_IP_INTERFACE_ADDR	132
/* 
 * Note, the spec say 133, but everyone seems to use 10. Any clue on why
 * this is would be appreciated!
 */
#define ISIS_CLV_L1_LSP_AUTHENTICATION_NS	10	/* non spec */
#define ISIS_CLV_L1_LSP_AUTHENTICATION		133

/*
 * detail clv information on L2 lsp packets
 */
#define ISIS_CLV_L2_LSP_AREA_ADDRESS		1
#define ISIS_CLV_L2_LSP_IS_NEIGHBORS		2
#define ISIS_CLV_L2_LSP_PARTITION_DIS		4
#define ISIS_CLV_L2_LSP_PREFIX_NEIGHBORS	5
#define ISIS_CLV_L2_LSP_IP_INT_REACHABLE	128
#define ISIS_CLV_L2_LSP_NLPID			129
#define ISIS_CLV_L2_LSP_IP_EXT_REACHABLE	130
#define ISIS_CLV_L2_LSP_IDRP_INFO		131
#define ISIS_CLV_L2_LSP_IP_INTERFACE_ADDR	132
/* 
 * Note, the spec say 133, but everyone seems to use 10. Any clue on why
 * this is would be appreciated!
 */
#define ISIS_CLV_L2_LSP_AUTHENTICATION_NS	10  	/*non spec */
#define ISIS_CLV_L2_LSP_AUTHENTICATION		133

/*
 * Published API functions.  NOTE, this are "local" API functions and
 * are only valid from with isis decodes.
 */
extern void isis_dissect_isis_lsp(int hello_type, int header_length,
        const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
extern void isis_lsp_decode_lsp_id(char *tstr, proto_tree *tree, int offset,
                isis_lsp_id_t *id );

#endif /* _PACKET_ISIS_LSP_H */
/* packet-isis-snp.c
 * Routines for decoding isis complete & partial SNP and their payload
 *
 * $Id: packet-osi.c,v 1.12 1999/11/16 11:42:44 guy Exp $
 * Stuart Stanley <stuarts@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "packet.h"
#include "packet-isis.h"
#include "packet-isis-clv.h"
#include "packet-isis-lsp.h"
#include "packet-isis-snp.h"

/* csnp packets */
static int proto_isis_csnp = -1;
static int hf_isis_csnp_pdu_length = -1;
static gint ett_isis_csnp = -1;
static gint ett_isis_csnp_lsp_entries = -1;
static gint ett_isis_csnp_authentication = -1;
static gint ett_isis_csnp_clv_unknown = -1;

/* psnp packets */
static int proto_isis_psnp = -1;
static int hf_isis_psnp_pdu_length = -1;
static gint ett_isis_psnp = -1;
static gint ett_isis_psnp_lsp_entries = -1;
static gint ett_isis_psnp_authentication = -1;
static gint ett_isis_psnp_clv_unknown = -1;

static void dissect_snp_lsp_entries(const u_char *pd, int offset,
		guint length, frame_data *fd, proto_tree *tree );
static void dissect_l1_snp_authentication_clv(const u_char *pd, int offset,
		guint length, frame_data *fd, proto_tree *tree );
static void dissect_l2_snp_authentication_clv(const u_char *pd, int offset,
		guint length, frame_data *fd, proto_tree *tree );

static const isis_clv_handle_t clv_l1_csnp_opts[] = {
	{
		ISIS_CLV_L1_CSNP_LSP_ENTRIES,
		"LSP entries",
		&ett_isis_csnp_lsp_entries,
		dissect_snp_lsp_entries
	},
	{
		ISIS_CLV_L1_CSNP_AUTHENTICATION_NS,
		"Authentication(non spec)",
		&ett_isis_csnp_authentication,
		dissect_l1_snp_authentication_clv
	},
	{
		ISIS_CLV_L1_CSNP_AUTHENTICATION,
		"Authentication",
		&ett_isis_csnp_authentication,
		dissect_l1_snp_authentication_clv
	},
	{
		0, "", NULL, NULL 
	}
};

static const isis_clv_handle_t clv_l2_csnp_opts[] = {
	{
		ISIS_CLV_L2_CSNP_LSP_ENTRIES,
		"LSP entries",
		&ett_isis_csnp_lsp_entries,
		dissect_snp_lsp_entries
	},
	{
		ISIS_CLV_L2_CSNP_AUTHENTICATION_NS,
		"Authentication(non spec)",
		&ett_isis_csnp_authentication,
		dissect_l2_snp_authentication_clv
	},
	{
		ISIS_CLV_L2_CSNP_AUTHENTICATION,
		"Authentication",
		&ett_isis_csnp_authentication,
		dissect_l2_snp_authentication_clv
	},
	{
		0, "", NULL, NULL 
	}
};

static const isis_clv_handle_t clv_l1_psnp_opts[] = {
	{
		ISIS_CLV_L1_PSNP_LSP_ENTRIES,
		"LSP entries",
		&ett_isis_psnp_lsp_entries,
		dissect_snp_lsp_entries
	},
	{
		ISIS_CLV_L1_PSNP_AUTHENTICATION_NS,
		"Authentication(non spec)",
		&ett_isis_psnp_authentication,
		dissect_l1_snp_authentication_clv
	},
	{
		ISIS_CLV_L1_PSNP_AUTHENTICATION,
		"Authentication",
		&ett_isis_psnp_authentication,
		dissect_l1_snp_authentication_clv
	},
	{
		0, "", NULL, NULL 
	}
};

static const isis_clv_handle_t clv_l2_psnp_opts[] = {
	{
		ISIS_CLV_L2_PSNP_LSP_ENTRIES,
		"LSP entries",
		&ett_isis_psnp_lsp_entries,
		dissect_snp_lsp_entries
	},
	{
		ISIS_CLV_L2_PSNP_AUTHENTICATION,
		"Authentication",
		&ett_isis_psnp_authentication,
		dissect_l2_snp_authentication_clv
	},
	{
		ISIS_CLV_L2_PSNP_AUTHENTICATION_NS,
		"Authentication(non spec)",
		&ett_isis_psnp_authentication,
		dissect_l2_snp_authentication_clv
	},
	{
		0, "", NULL, NULL 
	}
};
/*
 * Name: dissect_snp_payload()
 *
 * Description:
 *	All the snp packets use a common payload format.  We have up
 *	to n entries (based on length), which are made of:
 *		2 : remaining life time
 *		8 : lsp id
 *		4 : sequence number
 *		2 : checksum
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	int : length of payload to decode.
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
static void 
dissect_snp_lsp_entries(const u_char *pd, int offset, guint length, 
		frame_data *fd, proto_tree *tree ) {
	isis_snp_t *ps;

	ps = (isis_snp_t *) &pd[offset];
	while ( length > 0 ) {
		if ( length < sizeof(isis_psnp_t) ) {
			isis_dissect_unknown(offset, length, tree, fd,
				"Short SNP header entry (%d vs %d)", length,
				sizeof(isis_psnp_t) );
			return;
		}
		
		proto_tree_add_text(tree, offset, 2, "Remaining life: %d",
			pntohs(&ps->isis_snp_remaining_lifetime));
		isis_lsp_decode_lsp_id( "LSP ID", tree, offset + 2,
			&ps->isis_snp_lsp_id );
		proto_tree_add_text(tree, offset+10, 4, 
			"LSP Sequence Number: 0x%04x",
			pntohl(&ps->isis_snp_sequence_number));
		proto_tree_add_text(tree, offset+14, 2, 
			"LSP checksum: 0x%02x",
			pntohl(&ps->isis_snp_checksum));
		length -= sizeof ( isis_snp_t );
		offset += sizeof ( isis_snp_t );
		ps++;
	}

}

/*
 * Name: isis_dissect_isis_csnp()
 *
 * Description:
 *	Tear apart a L1 or L2 CSNP header and then call into payload dissect
 *	to pull apart the lsp id payload.
 *
 * Input:
 *	int : type (l1 csnp, l2 csnp)
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
void 
isis_dissect_isis_csnp(int type, int header_length, const u_char *pd, 
		int offset, frame_data *fd, proto_tree *tree){
	isis_csnp_t	*ilp;
	proto_item	*ti;
	proto_tree	*csnp_tree = NULL;
	int		hlen;
	int 		len;

	hlen = sizeof(*ilp);

	if (fd->cap_len < (offset + hlen)) {
		isis_dissect_unknown(offset, hlen, tree, fd,
			"not enough capture data for header (%d vs %d)",
			 hlen, offset - fd->cap_len);
		return;
	}
	
	ilp = (isis_csnp_t *) &pd[offset];

	if (tree) {
		ti = proto_tree_add_item(tree, proto_isis_csnp,
			offset, fd->cap_len - offset, NULL);
		csnp_tree = proto_item_add_subtree(ti, ett_isis_csnp);
		proto_tree_add_item(csnp_tree, hf_isis_csnp_pdu_length,
			offset, 2, pntohs(&ilp->isis_csnp_pdu_length));
		proto_tree_add_text(csnp_tree, offset + 2, 7, 
			"Source id: %02x%02x.%02x%02x.%02x%02x.%02x",
				ilp->isis_csnp_source_id[0],
				ilp->isis_csnp_source_id[1],
				ilp->isis_csnp_source_id[2],
				ilp->isis_csnp_source_id[3],
				ilp->isis_csnp_source_id[4],
				ilp->isis_csnp_source_id[5],
				ilp->isis_csnp_source_id[6] );
		isis_lsp_decode_lsp_id( "Start LSP id", csnp_tree, offset + 9,
			&ilp->isis_csnp_start_lsp_id );
		isis_lsp_decode_lsp_id( "End LSP id", csnp_tree, offset + 17,
			&ilp->isis_csnp_start_lsp_id );
	}

	offset += hlen;
	len = pntohs(&ilp->isis_csnp_pdu_length);
	len -= header_length;
	if (len < 0) {
		return;
	}
	/* Call into payload dissector */
	if (type == ISIS_TYPE_L1_CSNP ) {
		isis_dissect_clvs ( clv_l1_csnp_opts, len, pd, offset, fd,
			csnp_tree, ett_isis_csnp_clv_unknown );
	} else {
		isis_dissect_clvs ( clv_l2_csnp_opts, len, pd, offset, fd,
			csnp_tree, ett_isis_csnp_clv_unknown );
	}
}

/*
 * Name: isis_dissect_isis_psnp()
 *
 * Description:
 *	Tear apart a L1 or L2 PSNP header and then call into payload dissect
 *	to pull apart the lsp id payload.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
void 
isis_dissect_isis_psnp(int type, int header_length, const u_char *pd, 
		int offset, frame_data *fd, proto_tree *tree){
	isis_psnp_t	*ilp;
	proto_item	*ti;
	proto_tree	*psnp_tree = NULL;
	int		hlen;
	int 		len;

	hlen = sizeof(*ilp);

	if (fd->cap_len < (offset + hlen)) {
		isis_dissect_unknown(offset, hlen, tree, fd,
			"not enough capture data for header (%d vs %d)",
			 hlen, offset - fd->cap_len);
		return;
	}
	
	ilp = (isis_psnp_t *) &pd[offset];

	if (tree) {
		ti = proto_tree_add_item(tree, proto_isis_psnp,
			offset, fd->cap_len - offset, NULL);
		psnp_tree = proto_item_add_subtree(ti, ett_isis_psnp);
		proto_tree_add_item(psnp_tree, hf_isis_psnp_pdu_length,
			offset, 2, pntohs(&ilp->isis_psnp_pdu_length));
		proto_tree_add_text(psnp_tree, offset + 2, 7, 
			"Source id: %02x%02x.%02x%02x.%02x%02x.%02x",
				ilp->isis_psnp_source_id[0],
				ilp->isis_psnp_source_id[1],
				ilp->isis_psnp_source_id[2],
				ilp->isis_psnp_source_id[3],
				ilp->isis_psnp_source_id[4],
				ilp->isis_psnp_source_id[5],
				ilp->isis_psnp_source_id[6] );
	}

	offset += hlen;
	len = pntohs(&ilp->isis_psnp_pdu_length);
	len -= header_length;
	if (len < 0) {
		isis_dissect_unknown(offset, header_length, tree, fd,
			"packet header length %d went beyond packet",
			header_length );
		return;
	}
	/* Call into payload dissector */
	if (type == ISIS_TYPE_L1_CSNP ) {
		isis_dissect_clvs ( clv_l1_csnp_opts, len, pd, offset, fd,
			psnp_tree, ett_isis_psnp_clv_unknown );
	} else {
		isis_dissect_clvs ( clv_l2_csnp_opts, len, pd, offset, fd,
			psnp_tree, ett_isis_psnp_clv_unknown );
	}
}

/*
 * Name: dissect_L1_snp_authentication_clv()
 *
 * Description:
 *	Decode for a lsp packets authenticaion clv.  Calls into the
 *	clv common one.  An auth inside a L1 SNP is a per area password
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_l1_snp_authentication_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
		"Per area authentication" );
}

/*
 * Name: dissect_l2_authentication_clv()
 *
 * Description:
 *	Decode for a lsp packets authenticaion clv.  Calls into the
 *	clv common one.  An auth inside a L2 LSP is a per domain password
 *
 * Input:
 *	u_char * : packet data
 *	int : current offset into packet data
 *	guint : length of this clv
 *	frame_data * : frame data
 *	proto_tree * : proto tree to build on (may be null)
 *
 * Output:
 *	void, will modify proto_tree if not null.
 */
static void 
dissect_l2_snp_authentication_clv(const u_char *pd, int offset, 
		guint length, frame_data *fd, proto_tree *tree) {
	isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
		"Per domain authentication" );
}

/*
 * Name: proto_register_isis_csnp()
 *
 * Description: 
 *	Register our protocol sub-sets with protocol manager.
 *	NOTE: this procedure is autolinked by the makefile process that
 *		builds register.c
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
void 
proto_register_isis_csnp(void) {
	static hf_register_info hf[] = {
		{ &hf_isis_csnp_pdu_length,
		{ "PDU length",		"isis_csnp.pdu_length", FT_UINT16, 
		  BASE_DEC, NULL, 0x0, "" }},
	};
	static gint *ett[] = {
		&ett_isis_csnp,
		&ett_isis_csnp_lsp_entries,
		&ett_isis_csnp_authentication,
		&ett_isis_csnp_clv_unknown,
	};

	proto_isis_csnp = proto_register_protocol("ISIS csnp", "ISIS-csnp");
	proto_register_field_array(proto_isis_csnp, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));
}


/*
 * Name: proto_register_isis_psnp()
 *
 * Description: 
 *	Register our protocol sub-sets with protocol manager.
 *	NOTE: this procedure is autolinked by the makefile process that
 *		builds register.c
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet data where we are.
 *	guint : length of clv we are decoding
 *	frame_data * : frame data (complete frame)
 *	proto_tree * : protocol display tree to fill out.  May be NULL
 *
 * Output:
 *      void, but we will add to proto tree if !NULL.
 */
void 
proto_register_isis_psnp(void) {
	static hf_register_info hf[] = {
		{ &hf_isis_psnp_pdu_length,
		{ "PDU length",		"isis_psnp.pdu_length", FT_UINT16, 
		  BASE_DEC, NULL, 0x0, "" }},
	};
	static gint *ett[] = {
		&ett_isis_psnp,
		&ett_isis_psnp_lsp_entries,
		&ett_isis_psnp_authentication,
		&ett_isis_psnp_clv_unknown,
	};

	proto_isis_psnp = proto_register_protocol("ISIS psnp", "ISIS-psnp");
	proto_register_field_array(proto_isis_psnp, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));
}

/* packet-isis-snp.h
 * Defines and such for CSNP, PSNP, and their payloads
 *
 * $Id: packet-osi.c,v 1.12 1999/11/16 11:42:44 guy Exp $
 * Stuart Stanley <stuarts@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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.
 *
 *
 */

#ifndef _PACKET_ISIS_SNP_H
#define _PACKET_ISIS_SNP_H

/*
 * Note, the spec say 133 for authentication, but everyone seems to use 10. 
 * Any clue on why this is would be appreciated!
 */

/*
 * detail cvls information for L1 CSNP packets
 */
#define ISIS_CLV_L1_CSNP_LSP_ENTRIES		9
#define ISIS_CLV_L1_CSNP_AUTHENTICATION_NS	10
#define ISIS_CLV_L1_CSNP_AUTHENTICATION		133

/*
 * detail cvls information for L2 CSNP packets
 */
#define ISIS_CLV_L2_CSNP_LSP_ENTRIES		9
#define ISIS_CLV_L2_CSNP_AUTHENTICATION_NS	10
#define ISIS_CLV_L2_CSNP_AUTHENTICATION		133

/*
 * detail cvls information for L1 PSNP packets
 */
#define ISIS_CLV_L1_PSNP_LSP_ENTRIES		9
#define ISIS_CLV_L1_PSNP_AUTHENTICATION_NS	10
#define ISIS_CLV_L1_PSNP_AUTHENTICATION		133

/*
 * detail cvls information for L2 PSNP packets
 */
#define ISIS_CLV_L2_PSNP_LSP_ENTRIES		9
#define ISIS_CLV_L2_PSNP_AUTHENTICATION_NS	10
#define ISIS_CLV_L2_PSNP_AUTHENTICATION		133

/*
 * Declare L1/L2 CSNP header
 */
typedef struct {
	guint8	isis_csnp_pdu_length[2];	/* pdu length including hdr */
	guint8	isis_csnp_source_id[7];		/* source sysid */
	isis_lsp_id_t isis_csnp_start_lsp_id;		/* start LSP id */
	isis_lsp_id_t isis_csnp_end_lsp_id;		/* end LSP id */
} isis_csnp_t;

/*
 * Declare L1/L2 PSNP header
 */
typedef struct {
	guint8	isis_psnp_pdu_length[2];	/* pdu length including hdr */
	guint8	isis_psnp_source_id[7];		/* source sysid */
} isis_psnp_t;

/*
 * Declare SNP payload element
 */
typedef struct {
	guint8	isis_snp_remaining_lifetime[2];	/* lifetime of LSP */
	isis_lsp_id_t isis_snp_lsp_id;		/* target LSP id */
	guint8	isis_snp_sequence_number[4];	/* sequence number of LSP */
	guint8	isis_snp_checksum[2];		/* checksum of LSP */
} isis_snp_t;

/*
 * Published API functions.  NOTE, this are "local" API functions and
 * are only valid from with isis decodes.
 */
extern void isis_dissect_isis_csnp(int type, int header_length,
        const u_char *pd, int offset, frame_data *fd, proto_tree *tree);
extern void isis_dissect_isis_psnp(int type, int header_length,
        const u_char *pd, int offset, frame_data *fd, proto_tree *tree);

#endif /* _PACKET_ISIS_CSNP_H */
/* packet-isis-core.c
 * Routines for ISO/OSI network and transport protocol packet disassembly, core
 * bits.
 *
 * $Id: packet-osi.c,v 1.12 1999/11/16 11:42:44 guy Exp $
 * Stuart Stanley <stuarts@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "packet.h"
#include "packet-isis.h"
#include "packet-isis-lsp.h"
#include "packet-isis-hello.h"
#include "packet-isis-snp.h"

/* isis base header */
static int proto_isis = -1;

static int hf_isis_irpd = -1;
static int hf_isis_header_length = -1;
static int hf_isis_version = -1;
static int hf_isis_reserved = -1;
static int hf_isis_type = -1;
static int hf_isis_version2 = -1;
static int hf_isis_eco = -1;
static int hf_isis_user_eco = -1;

static gint ett_isis = -1;

static const value_string irpd_vals[] = {
	{ ISIS_IRPD, "correct(0x83)" },
	{ 0,		NULL} };

static const value_string isis_vals[] = {
	{ ISIS_TYPE_L1_HELLO,	"L1 HELLO"},
	{ ISIS_TYPE_L2_HELLO,	"L2 HELLO"},
	{ ISIS_TYPE_PTP_HELLO,	"P2P HELLO"},
	{ ISIS_TYPE_L1_LSP,	"L1 LSP"},
	{ ISIS_TYPE_L2_LSP,	"L2 LSP"},
	{ ISIS_TYPE_L1_CSNP,	"L1 CSNP"},
	{ ISIS_TYPE_L2_CSNP,	"L2 CSNP"},
	{ ISIS_TYPE_L1_PSNP,	"L1 PSNP"},
	{ ISIS_TYPE_L2_PSNP,	"L2 PSNP"},
	{ 0,		NULL} };


/*
 * Name: dissect_isis_unknown()
 *
 * Description:
 *	There was some error in the protocol and we are in unknown space
 *	here.  Add a tree item to cover the error and go on.  Note
 *	that we make sure we don't go off the end of the bleedin packet here!
 *
 * Input
 * 	unt offset : Current offset into packet data.
 * 	int len : length of to dump.
 *	proto_tree * : tree of display data.  May be NULL.
 *	frame_data * fd : frame data
 *	char * : format text
 *
 * Output:
 *	void (may modify proto tree)
 */
void
isis_dissect_unknown(int offset,guint length,proto_tree *tree,frame_data *fd,
		char *fmat, ...){
	va_list	ap;

	if ( offset > fd->cap_len ) {
		/* 
		 * big oops   They were off the end of the packet already.
		 * Just ignore this one.
		 */
		return;
	}
	if ( (offset + length) > fd->cap_len ) {
		/* 
		 * length will take us past eop.  Truncate length.
		 */
		length = offset - fd->cap_len;
	}

	va_start(ap, fmat);
	proto_tree_add_text(tree, offset, length, fmat, ap);
	va_end(ap);
}

/*
 * Name: isis_address_to_string()
 *
 * Description:
 *	Function for taking a byte string and turn it into a "0000.0000...."
 *	format ISIS address.
 *
 * Input:
 *	u_char * : Packet data
 * 	unt offset : Current offset into packet data.
 * 	int len : length of to dump.
 *
 * Output:
 *	static char * : print string
 */
char 
*isis_address_to_string ( const u_char *pd, int offset, int len ) {
	static char sbuf[768];
	char *s;

	sbuf[0] = 0;
	s = sbuf;
	while ( len > 0 ) {
		/* special case: len is 1, put ending on it */
		if ( len == 1 ) {
			s += sprintf ( s, "%02x", pd[offset++] );
			len--;
		} else {
			/* general case, just add 2 bytes */
			s+= sprintf ( s, "%02x%02x", pd[offset++],
				pd[offset++] );
			len -= 2;
		}
		if ( len > 0 ) {
			s += sprintf ( s, "." );
		}
	}
	return sbuf;
}

/*
 * Name: dissect_isis()
 * 
 * Description:
 *	Main entry area for isis de-mangling.  This will build the
 *	main isis tree data and call the sub-protocols as needed.
 *
 * Input:
 *	u_char * : packet data
 *	int : offset into packet where we are (packet_data[offset]== start
 *		of what we care about)
 *	frame_data * : frame data (whole packet with extra info)
 *	proto_tree * : tree of display data.  May be NULL.
 *
 * Output:
 *	void, but we will add to the proto_tree if it is not NULL.
 */
void
dissect_isis(const u_char *pd, int offset, frame_data *fd, 
		proto_tree *tree) {
	isis_hdr_t *ihdr;
	proto_item *ti;
	proto_tree *isis_tree = NULL;

	if (fd->cap_len < offset + sizeof(*ihdr)) {
		isis_dissect_unknown(offset, sizeof(*ihdr), tree, fd,
			"not enough capture data for header (%d vs %d)",
			sizeof(*ihdr), offset - fd->cap_len);
		return;
	}

	ihdr = (isis_hdr_t *) &pd[offset];

	if (ihdr->isis_version != ISIS_REQUIRED_VERSION){
		isis_dissect_unknown(offset, fd->cap_len, tree, fd,
			"Unknown ISIS version (%d vs %d)",
			ihdr->isis_version, ISIS_REQUIRED_VERSION );
		return;
	}
	
	
	if (tree) {
		ti = proto_tree_add_item(tree, proto_isis, offset, 
			fd->cap_len - offset, NULL );
		isis_tree = proto_item_add_subtree(ti, ett_isis);
		proto_tree_add_item_format(isis_tree, hf_isis_irpd, offset, 1,
			ihdr->isis_irpd, 
			"Intradomain Routing Protocol Discrimintator: 0x%02x",
			ihdr->isis_irpd );
		proto_tree_add_item(isis_tree, hf_isis_header_length,
			offset + 1, 1, ihdr->isis_header_length );
		proto_tree_add_item(isis_tree, hf_isis_version,
			offset + 2, 1, ihdr->isis_version );
		proto_tree_add_item(isis_tree, hf_isis_reserved,
			offset + 3, 1, ihdr->isis_reserved );
		proto_tree_add_item_format(isis_tree, hf_isis_type,
			offset + 4, 1, ihdr->isis_type,
			"Type: %s (R:%s%s%s)",
			val_to_str(ihdr->isis_type & ISIS_TYPE_MASK, isis_vals,
				"Unknown (0x%x)"),
			(ihdr->isis_type & ISIS_R8_MASK) ? "1" : "0",
			(ihdr->isis_type & ISIS_R7_MASK) ? "1" : "0",
			(ihdr->isis_type & ISIS_R6_MASK) ? "1" : "0");
		proto_tree_add_item(isis_tree, hf_isis_version2,
			offset + 5, 1, ihdr->isis_version2 );
		proto_tree_add_item(isis_tree, hf_isis_eco,
			offset + 6, 1, ihdr->isis_eco );
		proto_tree_add_item(isis_tree, hf_isis_user_eco,
			offset + 7, 1, ihdr->isis_user_eco );
	}


	/*
	 * Let us make sure we use the same names for all our decodes
	 * here.  First, dump the name into info column, and THEN
	 * dispatch the sub-type.
	 */
	if (check_col(fd, COL_INFO)) {
		col_add_str(fd, COL_INFO, val_to_str ( 
			ihdr->isis_type&ISIS_TYPE_MASK, isis_vals,
			"Unknown (0x%x)" ) );
	}

	/*
	 * Advance offset (we are past the header).
	 */
	offset += sizeof(*ihdr);
	switch (ihdr->isis_type) {
	case ISIS_TYPE_L1_HELLO:
		isis_dissect_isis_hello(ISIS_TYPE_L1_HELLO, 
			ihdr->isis_header_length, pd, offset, fd, isis_tree);
		break;
	case ISIS_TYPE_L2_HELLO:
		isis_dissect_isis_hello(ISIS_TYPE_L2_HELLO, 
			ihdr->isis_header_length, pd, offset, fd, isis_tree);
		break;
	case ISIS_TYPE_PTP_HELLO:
		isis_dissect_isis_hello(ISIS_TYPE_PTP_HELLO, 
			ihdr->isis_header_length, pd, offset, fd, isis_tree);
		break;
	case ISIS_TYPE_L1_LSP:
		isis_dissect_isis_lsp(ISIS_TYPE_L1_LSP, ihdr->isis_header_length,
			pd, offset, fd, isis_tree);
		break;
	case ISIS_TYPE_L2_LSP:
		isis_dissect_isis_lsp(ISIS_TYPE_L2_LSP, ihdr->isis_header_length,
			pd, offset, fd, isis_tree);
		break;
	case ISIS_TYPE_L1_CSNP:
		isis_dissect_isis_csnp(ISIS_TYPE_L1_CSNP, 
			ihdr->isis_header_length, pd, offset, fd, isis_tree);
		break;
	case ISIS_TYPE_L2_CSNP:
		isis_dissect_isis_csnp(ISIS_TYPE_L2_CSNP,
			ihdr->isis_header_length, pd, offset, fd, isis_tree);
		break;
	case ISIS_TYPE_L1_PSNP:
		isis_dissect_isis_psnp(ISIS_TYPE_L1_PSNP, 
			ihdr->isis_header_length, pd, offset, fd, isis_tree);
		break;
	case ISIS_TYPE_L2_PSNP:
		isis_dissect_isis_psnp(ISIS_TYPE_L2_PSNP,
			ihdr->isis_header_length, pd, offset, fd, isis_tree);
		break;
	default:
		isis_dissect_unknown(offset, offset - fd->cap_len, tree, fd,
			"unknown ISIS packet type" );
	}
} /* dissect_isis */


/*
 * Name: proto_register_isis()
 *
 * Description:
 *	main register for isis protocol set.  We register some display
 *	formats and the protocol module variables.
 *
 * 	NOTE: this procedure to autolinked by the makefile process that
 *	builds register.c
 *
 * Input: 
 *	void
 *
 * Output:
 *	void
 */
void 
proto_register_isis(void) {
	static hf_register_info hf[] = {
		{ &hf_isis_irpd,
		{ "Intradomain Routing Protocol Discriminator",	"isis.irpd",	
		  FT_UINT8, BASE_DEC, VALS(irpd_vals), 0xff, "" }},

		{ &hf_isis_header_length,
		{ "HDR Length",		"isis.hdr_len",	FT_UINT8, BASE_DEC, 
		  NULL, 0x0, "" }},

		{ &hf_isis_version,
		{ "Version (==1)",		"isis.version", FT_UINT8, 
		  BASE_DEC, NULL, 0x0, "" }},

		{ &hf_isis_reserved,
		{ "Reserved(==0)",			"isis.reserved",	
		  FT_UINT8, BASE_DEC, NULL, 0x0, "" }},

		{ &hf_isis_type,
		{ "Type code",            "isis.type",	FT_UINT8, BASE_DEC, 
		  VALS(isis_vals), 0xff, "" }},

		{ &hf_isis_version2,
		{ "Version2(==1)",   "isis.version2", FT_UINT8, BASE_DEC, NULL, 
		   0x0, "" }},

		{ &hf_isis_eco,
		{ "ECO (==0)",		"isis.eco",FT_UINT8, BASE_DEC, NULL, 
		  0x0, "" }},

		{ &hf_isis_user_eco,
		{ "User ECO (==0)", "isis.user_eco", FT_UINT8, BASE_DEC, NULL, 
		  0x0, "" }},

	};
	/*
	 * Note, we pull in the unknown CLV handler here, since it
	 * is used by all ISIS packet types.
	 */
	static gint *ett[] = {
		&ett_isis,
	};

	proto_isis = proto_register_protocol("clnp ISIS", "ISIS");
	proto_register_field_array(proto_isis, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));
}
/* packet-isis.h
 * Defines and such for core isis protcol decode.
 *
 * $Id: packet-osi.c,v 1.12 1999/11/16 11:42:44 guy Exp $
 * Stuart Stanley <stuarts@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * 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.
 *
 *
 */

#ifndef _PACKET_ISIS_H
#define _PACKET_ISIS_H

/* 
 * the IntraDomain Routing Protocol Descriminator is an achitectueral constant
 * set to 0x83 for all packets.
 */
#define ISIS_IRPD	0x83

/*
 * The version we support is 1
 */
#define ISIS_REQUIRED_VERSION 1

/*
 * ISIS type field values
 */
#define ISIS_TYPE_L1_HELLO		15
#define ISIS_TYPE_L2_HELLO		16
#define ISIS_TYPE_PTP_HELLO		17
#define ISIS_TYPE_L1_LSP		18
#define ISIS_TYPE_L2_LSP		20
#define ISIS_TYPE_L1_CSNP		24
#define ISIS_TYPE_L2_CSNP		25
#define ISIS_TYPE_L1_PSNP		26
#define ISIS_TYPE_L2_PSNP		27

/*
 * The common first 8 octets of the ISIS protocol header.
 */
typedef struct {
	guint8	isis_irpd;		/* Intradomain Routing Protocol Descriminator.  Must be 0x83 */
	guint8	isis_header_length;	/* header length in octets */
	guint8	isis_version;		/* isis version, must be 0x01 */
	guint8	isis_reserved;		/* res byte, must be 0 */
	guint8	isis_type_reserved;	/* packet type & reserved */
#define ISIS_TYPE_MASK 	0x1f
#define ISIS_R8_MASK	0x80
#define ISIS_R7_MASK	0x40
#define ISIS_R6_MASK	0x20
	guint8	isis_version2;		/* another version(?!), must be 0x01 */

	guint8	isis_eco;		/* ECO, must be 0 */
	guint8	isis_user_eco;		/* user ECO, must be 0 */
} isis_hdr_t;

#define isis_type isis_type_reserved&ISIS_TYPE_MASK
#define isis_r8 isis_type_reserved&ISIS_R8_MASK
#define isis_r7 isis_type_reserved&ISIS_R7_MASK
#define isis_r6 isis_type_reserved&ISIS_R6_MASK

/*
 * published API functions
 */
extern char *isis_address_to_string ( const u_char *pd, int offset, int len );
extern void dissect_isis(const u_char *pd, int offset, frame_data *fd, 
		proto_tree *tree);
extern void proto_register_isis(void);
extern void isis_dissect_unknown(int offset,guint length,proto_tree *tree,frame_data *fd,
                char *fmat, ...);

#endif /* _PACKET_ISIS_H */
? ethereal/packet-isis-clv.c
? ethereal/packet-isis-hello.c
? ethereal/packet-isis-lsp.c
? ethereal/packet-isis-snp.c
? ethereal/packet-isis.c
? ethereal/packet-isis-clv.h
? ethereal/packet-isis-hello.h
? ethereal/packet-isis-lsp.h
? ethereal/packet-isis-snp.h
? ethereal/packet-isis.h
Index: ethereal/AUTHORS
===================================================================
RCS file: /cvsroot/ethereal/AUTHORS,v
retrieving revision 1.74
diff -u -r1.74 AUTHORS
--- AUTHORS	1999/12/12 22:39:29	1.74
+++ AUTHORS	1999/12/14 20:34:14
@@ -211,6 +211,9 @@
 	V.120
 }
 
+Stuart Stanley <stuarts@xxxxxxxxxx> {
+	ISIS on CLNP support
+}
 
 Alain Magloire <alainm@xxxxxxxxxxxxxxxxxx> was kind enough to
 give his permission to use his version of snprintf.c.
Index: ethereal/Makefile.am
===================================================================
RCS file: /cvsroot/ethereal/Makefile.am,v
retrieving revision 1.134
diff -u -r1.134 Makefile.am
--- Makefile.am	1999/12/12 22:39:29	1.134
+++ Makefile.am	1999/12/14 20:34:15
@@ -74,6 +74,16 @@
 	packet-ipx.h   \
 	packet-irc.c   \
 	packet-isakmp.c\
+	packet-isis.h  \
+	packet-isis.c  \
+	packet-isis-clv.h \
+	packet-isis-clv.c \
+	packet-isis-hello.h \
+	packet-isis-hello.c \
+	packet-isis-lsp.h \
+	packet-isis-lsp.c \
+	packet-isis-snp.h \
+	packet-isis-snp.c \
 	packet-lapb.c  \
 	packet-lapd.c  \
 	packet-ldap.c  \
Index: ethereal/packet-osi.c
===================================================================
RCS file: /cvsroot/ethereal/packet-osi.c,v
retrieving revision 1.12
diff -u -r1.12 packet-osi.c
--- packet-osi.c	1999/11/16 11:42:44	1.12
+++ packet-osi.c	1999/12/14 20:34:15
@@ -1618,7 +1618,7 @@
       if (check_col(fd, COL_PROTOCOL)) {
 	col_add_str(fd, COL_PROTOCOL, "ISIS");
       }
-      dissect_data(pd, offset, fd, tree);
+      dissect_isis(pd, offset, fd, tree);
       break;
     default:
       if (check_col(fd, COL_PROTOCOL)) {