Ethereal-dev: Re: [Ethereal-dev] LAT Protocol specs

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

From: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Thu, 12 Oct 2000 00:46:59 -0700
On Wed, Oct 11, 2000 at 11:49:21PM +0900, Richard Sharpe wrote:
> I am there fore motivated to start a LAT dissector for Ethereal. Can anyone
> point me to the protocol specs?

They're probably locked up in some building in Massachusetts or New
Hampshire in the northeastern US.

I.e., LAT is a DEC-proprietary protocol; DEC have never published a
spec.

However, at

	http://linux-decnet.sourceforge.net/

is the Linux DECNET project page; if you go to

	http://sourceforge.net/projects/linux-decnet/

there's a link for latd 1.0, a LAT daemon.

I downloaded an older version of latd and started working on a LAT
dissector; I've attached what I have so far.  It compiles (or it did
last time I tried it, which wasn't too long ago, I think), and it
dissects some LAT stuff, but not all of it.  It probably should be
changed to use the new string stuff Gilbert stuck in - as I remember,
there are some counted strings in the protocol.
/* packet-lat.c
 * Routines for the disassembly of DEC's LAT protocol
 *
 * $Id$
 *
 * 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.
 */
 
#include "config.h"

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

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

#include <glib.h>
#include "packet.h"
#include "etypes.h"

/*
 * Information on LAT taken from the Linux "latd".
 */

static int proto_lat = -1;
static int hf_lat_cmd = -1;
static int hf_lat_num_slots = -1;
static int hf_lat_remote_connid = -1;
static int hf_lat_local_connid = -1;
static int hf_lat_seq_number = -1;
static int hf_lat_ack_number = -1;
static int hf_lat_slotcmd_local_session = -1;
static int hf_lat_slotcmd_remote_session = -1;
static int hf_lat_slotcmd_length = -1;
static int hf_lat_slotcmd_command = -1;
static int hf_lat_circuit_timer = -1;
static int hf_lat_hiver = -1;
static int hf_lat_lover = -1;
static int hf_lat_latver = -1;
static int hf_lat_latver_minor = -1;
static int hf_lat_incarnation = -1;
static int hf_lat_change_flags = -1;
static int hf_lat_mtu = -1;
static int hf_lat_multicast_timer = -1;
static int hf_lat_node_status = -1;
static int hf_lat_group_length = -1;
static int hf_lat_nodename = -1;
static int hf_lat_greeting = -1;
static int hf_lat_num_services = -1;
static int hf_lat_service_rating = -1;
static int hf_lat_service_name = -1;
static int hf_lat_service_ident = -1;

static gint ett_lat = -1;

/* LAT commands. */
#define LAT_CCMD_SREPLY		0x00 /* From Host */
#define LAT_CCMD_SDATA		0x01 /* From Host: Response required */
#define LAT_CCMD_SESSION	0x02 /* To Host */
#define LAT_CCMD_CONNECT	0x06
#define LAT_CCMD_CONREF		0x08 /* Connection Refused (I think) */
#define LAT_CCMD_CONACK		0x04
#define LAT_CCMD_DISCON		0x0A
#define LAT_CCMD_SERVICE	0x28
#define LAT_CCMD_ENQUIRE	0x38
#define LAT_CCMD_ENQREPLY	0x3C

static const value_string command_vals[] = {
	{ LAT_CCMD_SREPLY,   "Session reply" },
	{ LAT_CCMD_SDATA,    "Session data" },
	{ LAT_CCMD_SESSION,  "Session" },
	{ LAT_CCMD_CONNECT,  "Connect" },
	{ LAT_CCMD_CONREF,   "Connection refused" },
	{ LAT_CCMD_CONACK,   "Connection ACK" },
	{ LAT_CCMD_DISCON,   "Disconnect" },
	{ LAT_CCMD_SERVICE,  "Service" },
	{ LAT_CCMD_ENQUIRE,  "Enquire" },
	{ LAT_CCMD_ENQREPLY, "Enquire reply" },
	{ 0,                 NULL },
};

static void dissect_lat_sreply(const u_char *pd, int offset, frame_data *fd,
    proto_tree *tree);

static void dissect_lat_service(const u_char *pd, int offset, frame_data *fd,
    proto_tree *tree);

static int dissect_lat_string(const u_char *pd, int offset, int hf,
    proto_tree *tree);

static guint dissect_lat_header(const u_char *pd, int offset, frame_data *fd,
    proto_tree *tree);

static void dissect_lat_slots(const u_char *pd, int offset, guint num_slots,
    proto_tree *tree);

static void 
dissect_lat(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
{
	proto_item *ti; 
	proto_tree *lat_tree = NULL;
	guint8 command;

	command = pd[offset];

	if (check_col(fd, COL_PROTOCOL))
		col_add_str(fd, COL_PROTOCOL, "LAT");
	if (check_col(fd, COL_INFO)) {
		col_add_fstr(fd, COL_INFO, "%s",
		    val_to_str(command, command_vals, "Unknown command (%02x)"));
	}

	if (tree) {
		ti = proto_tree_add_item(tree, proto_lat, NullTVB, offset,
		    END_OF_FRAME, NULL);
		lat_tree = proto_item_add_subtree(ti, ett_lat);

		/* LAT header */
		proto_tree_add_uint(lat_tree, hf_lat_cmd, NullTVB, offset, 1,
		    command);
		offset += 1;

		switch (command) {

		case LAT_CCMD_SREPLY:
			dissect_lat_sreply(pd, offset, fd, lat_tree);
			break;

#if 0
		case LAT_CCMD_SDATA:
			dissect_lat_header(pd, offset, fd, lat_tree);
			break;

		case LAT_CCMD_SESSION:
			dissect_lat_header(pd, offset, fd, lat_tree);
			break;

		case LAT_CCMD_CONNECT:
			dissect_lat_connect(pd, offset, fd, lat_tree);
			break;

		case LAT_CCMD_CONREF:
			dissect_lat_conref(pd, offset, fd, lat_tree);
			break;

		case LAT_CCMD_CONACK:
			dissect_lat_conack(pd, offset, fd, lat_tree);
			break;

		case LAT_CCMD_DISCON:
			dissect_lat_discon(pd, offset, fd, lat_tree);
			break;
#endif

		case LAT_CCMD_SERVICE:
			dissect_lat_service(pd, offset, fd, lat_tree);
			break;

#if 0
		case LAT_CCMD_ENQUIRE:
			dissect_lat_enquire(pd, offset, fd, lat_tree);
			break;

		case LAT_CCMD_ENQREPLY:
			dissect_lat_enqreply(pd, offset, fd, lat_tree);
			break;
#endif

		default:
			old_dissect_data(pd, offset, fd, lat_tree);
			break;
		}

	}
}

static void
dissect_lat_sreply(const u_char *pd, int offset, frame_data *fd,
    proto_tree *tree)
{
	guint8 num_slots;

	num_slots = dissect_lat_header(pd, offset, fd, tree);
	offset += 1 + 2 + 2 + 1 + 1;
	dissect_lat_slots(pd, offset, num_slots, tree);
}

static const value_string node_status_vals[] = {
	{ 2, "Accepting connections" },
	{ 3, "Not accepting connections" },
	{ 0, NULL },
};

static void
dissect_lat_service(const u_char *pd, int offset, frame_data *fd,
    proto_tree *tree)
{
	guint8 group_length;
	guint8 num_services;
	int i;

	proto_tree_add_uint_format(tree, hf_lat_circuit_timer, NullTVB,
	    offset, 1, pd[offset], "Circuit timer: %u milliseconds",
	    pd[offset]*10);
	offset += 1;

	proto_tree_add_uint(tree, hf_lat_hiver, NullTVB, offset, 1,
	    pd[offset]);
	offset += 1;

	proto_tree_add_uint(tree, hf_lat_lover, NullTVB, offset, 1,
	    pd[offset]);
	offset += 1;

	proto_tree_add_uint(tree, hf_lat_latver, NullTVB, offset, 1,
	    pd[offset]);
	offset += 1;

	proto_tree_add_uint(tree, hf_lat_latver_minor, NullTVB, offset, 1,
	    pd[offset]);
	offset += 1;

	proto_tree_add_uint(tree, hf_lat_incarnation, NullTVB, offset, 1,
	    pd[offset]);
	offset += 1;

	proto_tree_add_uint(tree, hf_lat_change_flags, NullTVB, offset, 1,
	    pd[offset]);
	offset += 1;

	proto_tree_add_uint(tree, hf_lat_mtu, NullTVB, offset, 2,
	    pletohs(&pd[offset]));
	offset += 2;

	proto_tree_add_uint_format(tree, hf_lat_multicast_timer, NullTVB,
	    offset, 1, pd[offset], "Multicast timer: %u seconds", pd[offset]);
	offset += 1;

	proto_tree_add_uint(tree, hf_lat_node_status, NullTVB, offset, 1,
	    pd[offset]);
	offset += 1;

	group_length = pd[offset];
	proto_tree_add_uint(tree, hf_lat_group_length, NullTVB, offset, 1,
	    group_length);
	offset += 1;

	/* XXX - what are these? */
	proto_tree_add_text(tree, NullTVB, offset, group_length, "Groups");
	offset += group_length;

	offset = dissect_lat_string(pd, offset, hf_lat_nodename, tree);

	offset = dissect_lat_string(pd, offset, hf_lat_greeting, tree);

	num_services = pd[offset];
	proto_tree_add_uint(tree, hf_lat_num_services, NullTVB, offset, 1,
	    num_services);
	offset += 1;

	for (i = 0; i < num_services; i++) {
		proto_tree_add_uint(tree, hf_lat_service_rating, NullTVB,
		    offset, 1, pd[offset]);
		offset += 1;
		offset = dissect_lat_string(pd, offset, hf_lat_service_name,
		    tree);
		offset = dissect_lat_string(pd, offset, hf_lat_service_ident,
		    tree);
	}
}

static int
dissect_lat_string(const u_char *pd, int offset, int hf, proto_tree *tree)
{
	guint8 string_len;
	char *stringptr;

	/* XXX - alas, FT_STRING is null-terminated, not counted, so
	   we have to copy the string to a buffer and null-terminate
	   it. */
	string_len = pd[offset];
	stringptr = g_malloc(string_len + 1);
	memcpy(stringptr, &pd[offset + 1], string_len);
	stringptr[string_len] = '\0';
	proto_tree_add_string(tree, hf, NullTVB, offset, 1 + string_len,
	    stringptr);
	g_free(stringptr);
	return offset + 1 + string_len;
}

static guint
dissect_lat_header(const u_char *pd, int offset, frame_data *fd,
    proto_tree *tree)
{
	guint8 num_slots;

	num_slots = pd[offset];
	proto_tree_add_uint(tree, hf_lat_num_slots, NullTVB, offset, 1,
	    num_slots);
	offset += 1;

	proto_tree_add_uint(tree, hf_lat_remote_connid, NullTVB, offset, 2,
	    pletohs(&pd[offset]));
	offset += 2;

	proto_tree_add_uint(tree, hf_lat_local_connid, NullTVB, offset, 2,
	    pletohs(&pd[offset]));
	offset += 2;

	proto_tree_add_uint(tree, hf_lat_seq_number, NullTVB, offset, 1,
	    pd[offset]);
	offset += 1;

	proto_tree_add_uint(tree, hf_lat_ack_number, NullTVB, offset, 1,
	    pd[offset]);
	offset += 1;

	return num_slots;
}

static void
dissect_lat_slots(const u_char *pd, int offset, guint num_slots,
    proto_tree *tree)
{
	int i;

	for (i = 0; i < num_slots; i++) {
		proto_tree_add_uint(tree, hf_lat_slotcmd_local_session,
		    NullTVB, offset, 1, pd[offset]);
		offset += 1;

		proto_tree_add_uint(tree, hf_lat_slotcmd_remote_session,
		    NullTVB, offset, 1, pd[offset]);
		offset += 1;

		proto_tree_add_uint(tree, hf_lat_slotcmd_length, NullTVB,
		    offset, 1, pd[offset]);
		offset += 1;

		proto_tree_add_uint(tree, hf_lat_slotcmd_command, NullTVB,
		    offset, 1, pd[offset]);
		offset += 1;
	}
}

void
proto_register_lat(void)
{
	static hf_register_info hf[] = {
	    { &hf_lat_cmd,
		{ "Command", "lat.command", FT_UINT8, BASE_HEX,
		  VALS(command_vals), 0x0,
		  "" }},

	    { &hf_lat_num_slots,
		{ "Number of slots", "lat.num_slots", FT_UINT8, BASE_DEC,
		  NULL, 0x0,
		  "" }},

	    { &hf_lat_remote_connid,
		{ "Remote connection ID", "lat.remote_connid", FT_UINT16,
		  BASE_HEX, NULL, 0x0,
		  "" }},

	    { &hf_lat_local_connid,
		{ "Local connection ID", "lat.local_connid", FT_UINT16,
		  BASE_HEX, NULL, 0x0,
		  "" }},

	    { &hf_lat_seq_number,
		{ "Sequence number", "lat.seq_number", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_ack_number,
		{ "Ack number", "lat.ack_number", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_slotcmd_local_session,
		{ "Local session", "lat.slotcmd.local_session", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_slotcmd_remote_session,
		{ "Remote session", "lat.slotcmd.remote_session", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_slotcmd_length,
		{ "Length", "lat.slotcmd.length", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_slotcmd_command,
		{ "Command", "lat.slotcmd.command", FT_UINT8,
		  BASE_HEX, NULL, 0x0,
		  "" }},

	    { &hf_lat_circuit_timer,
		{ "Circuit timer", "lat.circuit_timer", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_hiver,
		{ "Highest protocol version acceptable", "lat.hiver", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_lover,
		{ "Lowest protocol version acceptable", "lat.lover", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_latver,
		{ "LAT version number", "lat.latver", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_latver_minor,
		{ "LAT minor version number (?)", "lat.latver_minor", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_incarnation,
		{ "Message incarnation (?)", "lat.incarnation", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_change_flags,
		{ "Change flags (?)", "lat.change_flags", FT_UINT8,
		  BASE_HEX, NULL, 0x0,
		  "" }},

	    { &hf_lat_mtu,
		{ "MTU", "lat.mtu", FT_UINT16,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_multicast_timer,
		{ "Multicast timer", "lat.multicast_timer", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_node_status,
		{ "Node status", "lat.node_status", FT_UINT8,
		  BASE_DEC, VALS(node_status_vals), 0x0,
		  "" }},

	    { &hf_lat_group_length,
		{ "Group length", "lat.group_length", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_nodename,
		{ "Node name", "lat.nodename", FT_STRING,
		  0, NULL, 0x0,
		  "" }},

	    { &hf_lat_greeting,
		{ "Greeting", "lat.greeting", FT_STRING,
		  0, NULL, 0x0,
		  "" }},

	    { &hf_lat_num_services,
		{ "Number of services", "lat.num_services", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_service_rating,
		{ "Rating", "lat.service_rating", FT_UINT8,
		  BASE_DEC, NULL, 0x0,
		  "" }},

	    { &hf_lat_service_name,
		{ "Service name", "lat.service.name", FT_STRING,
		  0, NULL, 0x0,
		  "" }},

	    { &hf_lat_service_ident,
		{ "Service identification", "lat.service.ident", FT_STRING,
		  0, NULL, 0x0,
		  "" }},
        };
	static gint *ett[] = {
		&ett_lat,
	};

	proto_lat = proto_register_protocol("Local Area Transport", "lat");
	proto_register_field_array(proto_lat, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));
}

void
proto_reg_handoff_lat(void)
{
	old_dissector_add("ethertype", ETHERTYPE_LAT, dissect_lat);
}