summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2001-05-24 20:25:25 +0000
committerGuy Harris <guy@alum.mit.edu>2001-05-24 20:25:25 +0000
commit8743489efacaa7e038152972826ed0921b559bf3 (patch)
tree5be466ac575ceeb646996edc76a7c1bd0f452771
parentd3fbbef9c07827e0015eaeaebefaee421686eb86 (diff)
downloadwireshark-8743489efacaa7e038152972826ed0921b559bf3.tar.gz
Appletalk Data Stream Interface (used by AFP-over-TCP) support, from
Randy McEoin. svn path=/trunk/; revision=3446
-rw-r--r--AUTHORS4
-rw-r--r--Makefile.am3
-rw-r--r--Makefile.nmake3
-rw-r--r--doc/ethereal.pod.template1
-rw-r--r--packet-dsi.c489
5 files changed, 498 insertions, 2 deletions
diff --git a/AUTHORS b/AUTHORS
index c4adb2e0e2..9e693b94b2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -645,6 +645,10 @@ Andy Hood <ahood@westpac.com.au> {
inadequacies of function declarations in X11 headers
}
+Randy McEoin <rmceoin@pe.net> {
+ Appletalk Data Stream Interface (used by AFP-over-TCP) support
+}
+
Alain Magloire <alainm@rcsm.ece.mcgill.ca> was kind enough to
give his permission to use his version of snprintf.c.
diff --git a/Makefile.am b/Makefile.am
index 70fc1ee91f..73dce5c3bc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.322 2001/05/24 08:13:56 guy Exp $
+# $Id: Makefile.am,v 1.323 2001/05/24 20:25:24 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@zing.org>
@@ -99,6 +99,7 @@ DISSECTOR_SRC = \
packet-dec-bpdu.c \
packet-diameter.c \
packet-dns.c \
+ packet-dsi.c \
packet-eigrp.c \
packet-esis.c \
packet-eth.c \
diff --git a/Makefile.nmake b/Makefile.nmake
index 0ecea411d0..43b3f2d1c5 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -1,7 +1,7 @@
## Makefile for building ethereal.exe with Microsoft C and nmake
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
#
-# $Id: Makefile.nmake,v 1.109 2001/05/24 08:13:56 guy Exp $
+# $Id: Makefile.nmake,v 1.110 2001/05/24 20:25:24 guy Exp $
include config.nmake
include <win32.mak>
@@ -52,6 +52,7 @@ DISSECTOR_SRC = \
packet-dec-bpdu.c \
packet-diameter.c \
packet-dns.c \
+ packet-dsi.c \
packet-eigrp.c \
packet-esis.c \
packet-eth.c \
diff --git a/doc/ethereal.pod.template b/doc/ethereal.pod.template
index ec21afbe51..f015b9d73d 100644
--- a/doc/ethereal.pod.template
+++ b/doc/ethereal.pod.template
@@ -1106,6 +1106,7 @@ B<http://www.ethereal.com>.
Jian Yu <bgp4news@yahoo.com>
Eran Mann <emann@opticalaccess.com>
Andy Hood <ahood@westpac.com.au>
+ Randy McEoin <rmceoin@pe.net>
Alain Magloire <alainm@rcsm.ece.mcgill.ca> was kind enough to give his
permission to use his version of snprintf.c.
diff --git a/packet-dsi.c b/packet-dsi.c
new file mode 100644
index 0000000000..4335d0b82f
--- /dev/null
+++ b/packet-dsi.c
@@ -0,0 +1,489 @@
+/* packet-dsi.c
+ * Routines for dsi packet dissection
+ * Copyright 2001, Randy McEoin <rmceoin@pe.com>
+ *
+ * $Id: packet-dsi.c,v 1.1 2001/05/24 20:25:24 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@zing.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from packet-pop.c
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <string.h>
+#include <glib.h>
+#include "packet.h"
+#include "strutil.h"
+#include "conversation.h"
+
+/* The information in this module (DSI) comes from:
+
+ AFP 2.1 & 2.2.pdf contained in AppleShare_IP_6.3_SDK
+ available from http://www.apple.com
+
+ The netatalk source code by Wesley Craig & Adrian Sun
+
+ * What a Data Stream Interface packet looks like:
+ * 0 32
+ * |-------------------------------|
+ * |flags |command| requestID |
+ * |-------------------------------|
+ * |error code/enclosed data offset|
+ * |-------------------------------|
+ * |total data length |
+ * |-------------------------------|
+ * |reserved field |
+ * |-------------------------------|
+*/
+
+static int proto_dsi = -1;
+static int hf_dsi_flags = -1;
+static int hf_dsi_command = -1;
+static int hf_dsi_requestid = -1;
+static int hf_dsi_code = -1;
+static int hf_dsi_length = -1;
+static int hf_dsi_reserved = -1;
+
+static gint ett_dsi = -1;
+
+#define TCP_PORT_DSI 548
+
+/* DSI flags */
+#define DSIFL_REQUEST 0x00
+#define DSIFL_REPLY 0x01
+#define DSIFL_MAX 0x01
+
+/* DSI Commands */
+#define DSIFUNC_CLOSE 1 /* DSICloseSession */
+#define DSIFUNC_CMD 2 /* DSICommand */
+#define DSIFUNC_STAT 3 /* DSIGetStatus */
+#define DSIFUNC_OPEN 4 /* DSIOpenSession */
+#define DSIFUNC_TICKLE 5 /* DSITickle */
+#define DSIFUNC_WRITE 6 /* DSIWrite */
+#define DSIFUNC_ATTN 8 /* DSIAttention */
+#define DSIFUNC_MAX 8 /* largest command */
+
+static const value_string flag_vals[] = {
+ {DSIFL_REQUEST, "Request" },
+ {DSIFL_REPLY, "Reply" },
+ {0, NULL } };
+
+static const value_string func_vals[] = {
+ {DSIFUNC_CLOSE, "CloseSession" },
+ {DSIFUNC_CMD, "Command" },
+ {DSIFUNC_STAT, "GetStatus" },
+ {DSIFUNC_OPEN, "OpenSession" },
+ {DSIFUNC_TICKLE, "Tickle" },
+ {DSIFUNC_WRITE, "Write" },
+ {DSIFUNC_ATTN, "Attention" },
+ {0, NULL } };
+
+
+static GMemChunk *vals = NULL;
+
+typedef struct {
+ int state;
+ guint8 flags,command;
+ guint16 requestid;
+ guint32 code;
+ guint32 length; /* total length of this DSI request/reply */
+ guint32 reserved;
+ guint32 seen; /* bytes seen so far */
+}hash_entry_t;
+
+enum {NONE,FIRSTDATA,MOREDATA,DONE};
+
+#define hash_init_count 20
+#define hash_val_length (sizeof(hash_entry_t))
+
+static guint32 last_abs_sec = 0;
+static guint32 last_abs_usec= 0;
+static guint32 highest_num = 0;
+
+/* Hash functions */
+gint dsi_equal (gconstpointer v, gconstpointer v2);
+guint dsi_hash (gconstpointer v);
+
+static guint dsi_packet_init_count = 200;
+
+typedef struct {
+ guint32 packetnum;
+} dsi_request_key;
+
+typedef struct {
+ guint8 flags;
+ guint8 command;
+ guint16 requestid;
+ guint32 length;
+ guint32 seen; /* bytes seen so far, including this packet */
+} dsi_request_val;
+
+static GHashTable *dsi_request_hash = NULL;
+static GMemChunk *dsi_request_keys = NULL;
+static GMemChunk *dsi_request_records = NULL;
+
+/* Hash Functions */
+gint dsi_equal (gconstpointer v, gconstpointer v2)
+{
+ dsi_request_key *val1 = (dsi_request_key*)v;
+ dsi_request_key *val2 = (dsi_request_key*)v2;
+
+ if (val1->packetnum == val2->packetnum) {
+ return 1;
+ }
+ return 0;
+}
+
+guint dsi_hash (gconstpointer v)
+{
+ dsi_request_key *dsi_key = (dsi_request_key*)v;
+ return GPOINTER_TO_UINT(dsi_key->packetnum);
+}
+
+void
+dsi_hash_insert(guint32 packetnum, guint8 flags, guint8 command,
+ guint16 requestid, guint32 length, guint32 seen)
+{
+ dsi_request_val *request_val;
+ dsi_request_key *request_key;
+
+ /* Now remember info about this continuation packet */
+
+ request_key = g_mem_chunk_alloc(dsi_request_keys);
+ request_key->packetnum = packetnum;
+
+ request_val = g_mem_chunk_alloc(dsi_request_records);
+ request_val->flags = flags;
+ request_val->command = command;
+ request_val->requestid = requestid;
+ request_val->length = length;
+ request_val->seen = seen;
+
+ g_hash_table_insert(dsi_request_hash, request_key, request_val);
+}
+
+/* Returns TRUE or FALSE. If TRUE, the record was found */
+
+gboolean
+dsi_hash_lookup(guint32 packetnum, guint8 *flags, guint8 *command,
+ guint16 *requestid, guint32 *length, guint32 *seen)
+{
+ dsi_request_val *request_val;
+ dsi_request_key request_key;
+
+ request_key.packetnum = packetnum;
+
+ request_val = (dsi_request_val*)
+ g_hash_table_lookup(dsi_request_hash, &request_key);
+
+ if (request_val) {
+ *flags = request_val->flags;
+ *command = request_val->command;
+ *requestid = request_val->requestid;
+ *length = request_val->length;
+ *seen = request_val->seen;
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+/* The state_machine remembers information about continuation packets */
+/* returns TRUE if it found a previously known continuation packet */
+gboolean
+dsi_state_machine( hash_entry_t *hash_info, tvbuff_t *tvb, packet_info *pinfo,
+ int offset)
+{
+ frame_data *fd;
+ guint32 data_here;
+ guint8 flags,command;
+ guint16 requestid;
+ guint32 length;
+ guint32 seen;
+ gboolean found_hash;
+
+ fd=pinfo->fd;
+
+ found_hash=dsi_hash_lookup(fd->num, &flags, &command, &requestid,
+ &length, &seen);
+ if (found_hash==TRUE)
+ {
+ hash_info->flags = flags;
+ hash_info->command = command;
+ hash_info->requestid = requestid;
+ hash_info->length = length;
+ hash_info->seen = seen;
+ return TRUE;
+ }
+
+ /* is this sequentially the next packet? */
+ if (highest_num > fd->num)
+ {
+ hash_info->state = NONE;
+ return FALSE;
+ }
+
+ highest_num = fd->num;
+
+ if ((hash_info->state == NONE) || (hash_info->state == DONE))
+ {
+ hash_info->state = NONE;
+ hash_info->length = tvb_get_ntohl(tvb, offset+8);
+ data_here = tvb_length_remaining(tvb, offset+16);
+ if (data_here < hash_info->length)
+ {
+ hash_info->flags = tvb_get_guint8(tvb, offset);
+ hash_info->command = tvb_get_guint8(tvb, offset+1);
+ hash_info->requestid = tvb_get_ntohs(tvb, offset+2);
+ hash_info->code = tvb_get_ntohl(tvb, offset+4);
+ hash_info->reserved = tvb_get_ntohl(tvb, offset+12);
+ hash_info->seen = data_here;
+ hash_info->state = FIRSTDATA;
+ }
+ return FALSE;
+ }
+
+
+ if (hash_info->state == FIRSTDATA)
+ hash_info->state = MOREDATA;
+
+ /* we must be receiving more data */
+ data_here = tvb_length_remaining(tvb, offset);
+ hash_info->seen += data_here;
+ if (hash_info->seen >= hash_info->length)
+ hash_info->state = DONE;
+
+ dsi_hash_insert(fd->num, hash_info->flags,
+ hash_info->command, hash_info->requestid,
+ hash_info->length,hash_info->seen);
+
+ return FALSE;
+}
+
+static void
+dissect_dsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *dsi_tree;
+ proto_item *ti;
+ conversation_t *conversation;
+ hash_entry_t *hash_info;
+ gint offset = 0;
+ gboolean prev_cont; /* TRUE if a previously known
+ * continuation packet */
+ char cont_str[256];
+
+ gchar *flag_str;
+ gchar *func_str;
+ guint8 dsi_flags,dsi_command;
+ guint16 dsi_requestid;
+ guint32 dsi_code;
+ guint32 dsi_length;
+ guint32 dsi_reserved;
+
+ if (check_col(pinfo->fd, COL_PROTOCOL))
+ col_set_str(pinfo->fd, COL_PROTOCOL, "DSI");
+ if (check_col(pinfo->fd, COL_INFO))
+ col_clear(pinfo->fd, COL_INFO);
+
+ conversation = find_conversation(&pinfo->src, &pinfo->dst, PT_TCP,
+ pinfo->srcport, pinfo->destport, 0);
+ if (conversation == NULL) {
+ hash_info = g_mem_chunk_alloc(vals);
+ hash_info->state = NONE;
+ conversation = conversation_new(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport, pinfo->destport,
+ hash_info, 0);
+
+ conversation_set_dissector(conversation, dissect_dsi);
+ }else
+ {
+ hash_info = conversation->data;
+ }
+
+ prev_cont=dsi_state_machine( hash_info, tvb, pinfo, offset);
+
+ if ((hash_info->state == NONE) && (prev_cont!=TRUE))
+ {
+ dsi_flags = tvb_get_guint8(tvb, offset);
+ dsi_command = tvb_get_guint8(tvb, offset+1);
+ dsi_requestid = tvb_get_ntohs(tvb, offset+2);
+ dsi_code = tvb_get_ntohl(tvb, offset+4);
+ dsi_length = tvb_get_ntohl(tvb, offset+8);
+ dsi_reserved = tvb_get_ntohl(tvb, offset+12);
+ }else
+ {
+ dsi_flags = hash_info->flags;
+ dsi_command = hash_info->command;
+ dsi_requestid = hash_info->requestid;
+ dsi_code = hash_info->code;
+ dsi_length = hash_info->length;
+ dsi_reserved = hash_info->reserved;
+ }
+
+ if (check_col(pinfo->fd, COL_INFO)) {
+ if ((func_str = match_strval(dsi_command, func_vals)))
+ {
+ flag_str = match_strval(dsi_flags, flag_vals);
+ if ((hash_info->state == MOREDATA) ||
+ (hash_info->state == DONE) ||
+ (prev_cont == TRUE))
+ {
+ sprintf(cont_str,"Continued: %d/%d",
+ hash_info->seen,hash_info->length);
+ }else
+ {
+ cont_str[0]=0;
+ }
+ col_add_fstr(pinfo->fd, COL_INFO, "%s %s (%d) %s",
+ flag_str,func_str,dsi_requestid,
+ cont_str);
+ }
+ }
+
+
+ if (tree)
+ {
+ ti = proto_tree_add_item(tree, proto_dsi, tvb, offset,
+ tvb_length_remaining(tvb, offset), FALSE);
+ dsi_tree = proto_item_add_subtree(ti, ett_dsi);
+
+ if (prev_cont == TRUE)
+ {
+ proto_tree_add_uint(dsi_tree, hf_dsi_requestid, tvb,
+ 0, 0, dsi_requestid);
+ dissect_data(tvb, 0, pinfo, dsi_tree);
+ }else
+ {
+ proto_tree_add_uint(dsi_tree, hf_dsi_flags, tvb,
+ offset, 1, dsi_flags);
+ proto_tree_add_uint(dsi_tree, hf_dsi_command, tvb,
+ offset+1, 1, dsi_command);
+ proto_tree_add_uint(dsi_tree, hf_dsi_requestid, tvb,
+ offset+2, 2, dsi_requestid);
+ proto_tree_add_uint(dsi_tree, hf_dsi_code, tvb,
+ offset+4, 4, dsi_code);
+ proto_tree_add_uint_format(dsi_tree, hf_dsi_length, tvb,
+ offset+8, 4, dsi_length,
+ "Length: %d bytes", dsi_length);
+ proto_tree_add_uint(dsi_tree, hf_dsi_reserved, tvb,
+ offset+12, 4, dsi_reserved);
+ dissect_data(tvb, 16, pinfo, dsi_tree);
+ }
+
+ }
+}
+
+static void dsi_reinit( void){
+
+ last_abs_sec = 0;
+ last_abs_usec= 0;
+ highest_num = 0;
+
+ if (vals)
+ g_mem_chunk_destroy(vals);
+ if (dsi_request_hash)
+ g_hash_table_destroy(dsi_request_hash);
+ if (dsi_request_keys)
+ g_mem_chunk_destroy(dsi_request_keys);
+ if (dsi_request_records)
+ g_mem_chunk_destroy(dsi_request_records);
+
+ dsi_request_hash = g_hash_table_new(dsi_hash, dsi_equal);
+
+ dsi_request_keys = g_mem_chunk_new("dsi_request_keys",
+ sizeof(dsi_request_key),
+ dsi_packet_init_count * sizeof(dsi_request_key),
+ G_ALLOC_AND_FREE);
+ dsi_request_records = g_mem_chunk_new("dsi_request_records",
+ sizeof(dsi_request_val),
+ dsi_packet_init_count * sizeof(dsi_request_val),
+ G_ALLOC_AND_FREE);
+
+ vals = g_mem_chunk_new("dsi_vals", hash_val_length,
+ hash_init_count * hash_val_length,
+ G_ALLOC_AND_FREE);
+}
+
+void
+proto_register_dsi(void)
+{
+
+ static hf_register_info hf[] = {
+ { &hf_dsi_flags,
+ { "Flags", "dsi.flags",
+ FT_UINT8, BASE_HEX, VALS(flag_vals), 0x0,
+ "Indicates request or reply." }},
+
+ { &hf_dsi_command,
+ { "Command", "dsi.command",
+ FT_UINT8, BASE_DEC, VALS(func_vals), 0x0,
+ "Represents a DSI command." }},
+
+ { &hf_dsi_requestid,
+ { "Request ID", "dsi.requestid",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Keeps track of which request this is. Replies must match a Request. IDs must be generated in sequential order." }},
+
+ { &hf_dsi_code,
+ { "Code", "dsi.code",
+ FT_UINT32, BASE_HEX, NULL, 0x0,
+ "In Reply packets this is an error code. In Request Write packets this is a data offset." }},
+
+ { &hf_dsi_length,
+ { "Length", "dsi.length",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Total length of the data that follows the DSI header." }},
+
+ { &hf_dsi_reserved,
+ { "Reserved", "dsi.reserved",
+ FT_UINT32, BASE_HEX, NULL, 0x0,
+ "Reserved for future use. Should be set to zero." }},
+
+ };
+ static gint *ett[] = {
+ &ett_dsi,
+ };
+
+ proto_dsi = proto_register_protocol("Data Stream Interface", "DSI", "dsi");
+ proto_register_field_array(proto_dsi, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ register_init_routine( &dsi_reinit);
+}
+
+void
+proto_reg_handoff_dsi(void)
+{
+ dissector_add("tcp.port", TCP_PORT_DSI, dissect_dsi, proto_dsi);
+}