1998-09-23 05:25:12 +00:00
|
|
|
/* packet-ncp.c
|
|
|
|
* Routines for NetWare Core Protocol
|
2001-11-13 23:55:44 +00:00
|
|
|
* Gilbert Ramirez <gram@alumni.rice.edu>
|
1999-12-07 06:13:19 +00:00
|
|
|
* Modified to allow NCP over TCP/IP decodes by James Coe <jammer@cin.net>
|
2004-02-18 06:01:47 +00:00
|
|
|
* Modified to decode server op-lock, packet signature,
|
2002-08-23 17:47:31 +00:00
|
|
|
* & NDS packets by Greg Morris <gmorris@novell.com>
|
1998-09-23 05:25:12 +00:00
|
|
|
*
|
2003-08-25 22:14:07 +00:00
|
|
|
* Portions Copyright (c) by Gilbert Ramirez 2000-2002
|
|
|
|
* Portions Copyright (c) by James Coe 2000-2002
|
|
|
|
* Portions Copyright (c) Novell, Inc. 2000-2003
|
|
|
|
*
|
2004-07-18 00:24:25 +00:00
|
|
|
* $Id$
|
1998-09-23 05:25:12 +00:00
|
|
|
*
|
|
|
|
* Ethereal - Network traffic analyzer
|
2001-12-03 04:00:26 +00:00
|
|
|
* By Gerald Combs <gerald@ethereal.com>
|
2000-07-28 20:03:59 +00:00
|
|
|
* Copyright 2000 Gerald Combs
|
2002-08-28 21:04:11 +00:00
|
|
|
*
|
1998-09-23 05:25:12 +00:00
|
|
|
* 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.
|
2002-08-28 21:04:11 +00:00
|
|
|
*
|
1998-09-23 05:25:12 +00:00
|
|
|
* 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.
|
2002-08-28 21:04:11 +00:00
|
|
|
*
|
1998-09-23 05:25:12 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2002-08-28 21:04:11 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
1998-09-23 05:25:12 +00:00
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2002-08-23 17:47:31 +00:00
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
|
|
# include <sys/types.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_NETINET_IN_H
|
|
|
|
# include <netinet/in.h>
|
|
|
|
#endif
|
|
|
|
|
2002-05-15 06:50:33 +00:00
|
|
|
#include <string.h>
|
1999-03-23 03:14:46 +00:00
|
|
|
#include <glib.h>
|
2002-01-21 07:37:49 +00:00
|
|
|
#include <epan/packet.h>
|
2000-07-28 20:03:59 +00:00
|
|
|
#include "prefs.h"
|
1998-10-15 21:12:17 +00:00
|
|
|
#include "packet-ipx.h"
|
2002-05-25 01:05:56 +00:00
|
|
|
#include "packet-tcp.h"
|
2000-07-28 20:03:59 +00:00
|
|
|
#include "packet-ncp-int.h"
|
2003-08-25 22:14:07 +00:00
|
|
|
#include "reassemble.h"
|
2004-02-18 06:01:47 +00:00
|
|
|
#include <epan/conversation.h>
|
1998-09-23 05:25:12 +00:00
|
|
|
|
2000-07-28 20:03:59 +00:00
|
|
|
int proto_ncp = -1;
|
1999-12-07 06:13:19 +00:00
|
|
|
static int hf_ncp_ip_ver = -1;
|
2000-07-28 20:03:59 +00:00
|
|
|
static int hf_ncp_ip_length = -1;
|
|
|
|
static int hf_ncp_ip_rplybufsize = -1;
|
1999-12-07 06:13:19 +00:00
|
|
|
static int hf_ncp_ip_sig = -1;
|
2002-05-24 03:03:49 +00:00
|
|
|
static int hf_ncp_ip_packetsig = -1;
|
1999-10-17 14:09:35 +00:00
|
|
|
static int hf_ncp_type = -1;
|
|
|
|
static int hf_ncp_seq = -1;
|
|
|
|
static int hf_ncp_connection = -1;
|
|
|
|
static int hf_ncp_task = -1;
|
2002-05-15 06:50:33 +00:00
|
|
|
static int hf_ncp_stream_type = -1;
|
|
|
|
static int hf_ncp_system_flags = -1;
|
|
|
|
static int hf_ncp_system_flags_abt = -1;
|
|
|
|
static int hf_ncp_system_flags_eob = -1;
|
|
|
|
static int hf_ncp_system_flags_sys = -1;
|
2004-06-15 09:30:54 +00:00
|
|
|
static int hf_ncp_system_flags_bsy = -1;
|
|
|
|
static int hf_ncp_system_flags_lst = -1;
|
2002-05-15 06:50:33 +00:00
|
|
|
static int hf_ncp_src_connection = -1;
|
|
|
|
static int hf_ncp_dst_connection = -1;
|
|
|
|
static int hf_ncp_packet_seqno = -1;
|
|
|
|
static int hf_ncp_delay_time = -1;
|
|
|
|
static int hf_ncp_burst_seqno = -1;
|
|
|
|
static int hf_ncp_ack_seqno = -1;
|
|
|
|
static int hf_ncp_burst_len = -1;
|
|
|
|
static int hf_ncp_data_offset = -1;
|
|
|
|
static int hf_ncp_data_bytes = -1;
|
|
|
|
static int hf_ncp_missing_fraglist_count = -1;
|
|
|
|
static int hf_ncp_missing_data_offset = -1;
|
|
|
|
static int hf_ncp_missing_data_count = -1;
|
2002-08-23 17:47:31 +00:00
|
|
|
static int hf_ncp_oplock_flag = -1;
|
|
|
|
static int hf_ncp_oplock_handle = -1;
|
2002-05-15 21:17:21 +00:00
|
|
|
static int hf_ncp_completion_code = -1;
|
|
|
|
static int hf_ncp_connection_status = -1;
|
|
|
|
static int hf_ncp_slot = -1;
|
|
|
|
static int hf_ncp_control_code = -1;
|
2002-08-23 17:47:31 +00:00
|
|
|
static int hf_ncp_fragment_handle = -1;
|
|
|
|
static int hf_lip_echo = -1;
|
2004-06-15 09:30:54 +00:00
|
|
|
static int hf_ncp_burst_command = -1;
|
|
|
|
static int hf_ncp_burst_file_handle = -1;
|
|
|
|
static int hf_ncp_burst_reserved = -1;
|
1999-07-29 05:47:07 +00:00
|
|
|
|
2002-05-09 23:50:34 +00:00
|
|
|
gint ett_ncp = -1;
|
2002-09-22 15:46:42 +00:00
|
|
|
gint ett_nds = -1;
|
2003-08-25 22:14:07 +00:00
|
|
|
gint ett_nds_segments = -1;
|
|
|
|
gint ett_nds_segment = -1;
|
2002-05-15 06:50:33 +00:00
|
|
|
static gint ett_ncp_system_flags = -1;
|
1999-11-16 11:44:20 +00:00
|
|
|
|
2003-08-25 22:14:07 +00:00
|
|
|
|
|
|
|
/* Tables for reassembly of fragments. */
|
|
|
|
GHashTable *nds_fragment_table = NULL;
|
|
|
|
GHashTable *nds_reassembled_table = NULL;
|
|
|
|
dissector_handle_t nds_data_handle;
|
|
|
|
|
2002-05-25 01:05:56 +00:00
|
|
|
/* desegmentation of NCP over TCP */
|
|
|
|
static gboolean ncp_desegment = TRUE;
|
|
|
|
|
2002-05-15 21:17:21 +00:00
|
|
|
static dissector_handle_t data_handle;
|
|
|
|
|
2000-04-18 04:46:07 +00:00
|
|
|
#define TCP_PORT_NCP 524
|
|
|
|
#define UDP_PORT_NCP 524
|
2000-04-08 07:07:42 +00:00
|
|
|
|
2000-07-28 20:03:59 +00:00
|
|
|
#define NCP_RQST_HDR_LENGTH 7
|
|
|
|
#define NCP_RPLY_HDR_LENGTH 8
|
1999-03-20 04:38:57 +00:00
|
|
|
|
2002-09-22 15:46:42 +00:00
|
|
|
|
1999-03-20 04:38:57 +00:00
|
|
|
/* Hash functions */
|
1999-07-07 22:52:57 +00:00
|
|
|
gint ncp_equal (gconstpointer v, gconstpointer v2);
|
|
|
|
guint ncp_hash (gconstpointer v);
|
1999-03-20 04:38:57 +00:00
|
|
|
|
1999-12-07 06:13:19 +00:00
|
|
|
/* These are the header structures to handle NCP over IP */
|
2000-01-01 21:05:02 +00:00
|
|
|
#define NCPIP_RQST 0x446d6454 /* "DmdT" */
|
|
|
|
#define NCPIP_RPLY 0x744e6350 /* "tNcP" */
|
1999-12-07 06:13:19 +00:00
|
|
|
|
|
|
|
struct ncp_ip_header {
|
|
|
|
guint32 signature;
|
|
|
|
guint32 length;
|
|
|
|
};
|
|
|
|
|
2004-02-18 06:01:47 +00:00
|
|
|
|
1999-12-07 06:13:19 +00:00
|
|
|
/* This header only appears on NCP over IP request packets */
|
|
|
|
struct ncp_ip_rqhdr {
|
|
|
|
guint32 version;
|
|
|
|
guint32 rplybufsize;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const value_string ncp_ip_signature[] = {
|
|
|
|
{ NCPIP_RQST, "Demand Transport (Request)" },
|
|
|
|
{ NCPIP_RPLY, "Transport is NCP (Reply)" },
|
2001-01-03 16:41:08 +00:00
|
|
|
{ 0, NULL },
|
1999-12-07 06:13:19 +00:00
|
|
|
};
|
|
|
|
|
2004-06-15 09:30:54 +00:00
|
|
|
static const value_string burst_command[] = {
|
|
|
|
{ 0x01000000, "Burst Read" },
|
|
|
|
{ 0x02000000, "Burst Write" },
|
|
|
|
{ 0, NULL },
|
|
|
|
};
|
|
|
|
|
1998-09-23 05:25:12 +00:00
|
|
|
/* The information in this module comes from:
|
|
|
|
NetWare LAN Analysis, Second Edition
|
|
|
|
Laura A. Chappell and Dan E. Hakes
|
|
|
|
(c) 1994 Novell, Inc.
|
|
|
|
Novell Press, San Jose.
|
|
|
|
ISBN: 0-7821-1362-1
|
|
|
|
|
|
|
|
And from the ncpfs source code by Volker Lendecke
|
1999-03-20 04:38:57 +00:00
|
|
|
|
|
|
|
And:
|
|
|
|
Programmer's Guide to the NetWare Core Protocol
|
|
|
|
Steve Conner & Diane Conner
|
|
|
|
(c) 1996 by Steve Conner & Diane Conner
|
|
|
|
Published by Annabooks, San Diego, California
|
|
|
|
ISBN: 0-929392-31-0
|
2002-09-22 15:46:42 +00:00
|
|
|
|
|
|
|
And:
|
|
|
|
http:developer.novell.com
|
|
|
|
NCP documentation
|
1999-03-20 04:38:57 +00:00
|
|
|
|
1998-09-23 05:25:12 +00:00
|
|
|
*/
|
|
|
|
|
2002-05-15 06:50:33 +00:00
|
|
|
/*
|
|
|
|
* Every NCP packet has this common header (except for burst packets).
|
|
|
|
*/
|
1999-03-20 04:38:57 +00:00
|
|
|
struct ncp_common_header {
|
|
|
|
guint16 type;
|
|
|
|
guint8 sequence;
|
|
|
|
guint8 conn_low;
|
|
|
|
guint8 task;
|
2000-07-28 20:03:59 +00:00
|
|
|
guint8 conn_high; /* type=0x5555 doesn't have this */
|
2002-08-28 21:04:11 +00:00
|
|
|
};
|
1998-09-23 05:25:12 +00:00
|
|
|
|
|
|
|
|
2000-07-28 20:03:59 +00:00
|
|
|
static value_string ncp_type_vals[] = {
|
2002-05-15 21:17:21 +00:00
|
|
|
{ NCP_ALLOCATE_SLOT, "Create a service connection" },
|
|
|
|
{ NCP_SERVICE_REQUEST, "Service request" },
|
|
|
|
{ NCP_SERVICE_REPLY, "Service reply" },
|
|
|
|
{ NCP_WATCHDOG, "Watchdog" },
|
|
|
|
{ NCP_DEALLOCATE_SLOT, "Destroy service connection" },
|
2003-10-23 07:52:56 +00:00
|
|
|
{ NCP_BROADCAST_SLOT, "Server Broadcast" },
|
2002-05-15 21:17:21 +00:00
|
|
|
{ NCP_BURST_MODE_XFER, "Burst mode transfer" },
|
|
|
|
{ NCP_POSITIVE_ACK, "Request being processed" },
|
2003-10-23 07:52:56 +00:00
|
|
|
{ NCP_LIP_ECHO, "Large Internet Packet Echo" },
|
2002-05-15 21:17:21 +00:00
|
|
|
{ 0, NULL }
|
1998-10-22 04:50:21 +00:00
|
|
|
};
|
1998-09-23 05:25:12 +00:00
|
|
|
|
2004-02-18 06:01:47 +00:00
|
|
|
/* Conversation Struct so we can store whether the conversation is using Packet Signature */
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
conversation_t *conversation;
|
|
|
|
} mncp_rhash_key;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
gboolean packet_signature;
|
|
|
|
} mncp_rhash_value;
|
|
|
|
|
|
|
|
static GHashTable *mncp_rhash = NULL;
|
|
|
|
static GMemChunk *mncp_rhash_keys = NULL;
|
|
|
|
static GMemChunk *mncp_rhash_values = NULL;
|
|
|
|
|
|
|
|
/* Hash Functions */
|
|
|
|
gint
|
|
|
|
mncp_equal(gconstpointer v, gconstpointer v2)
|
|
|
|
{
|
|
|
|
const mncp_rhash_key *val1 = (const mncp_rhash_key*)v;
|
|
|
|
const mncp_rhash_key *val2 = (const mncp_rhash_key*)v2;
|
|
|
|
|
|
|
|
if (val1->conversation == val2->conversation ) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
guint
|
|
|
|
mncp_hash(gconstpointer v)
|
|
|
|
{
|
|
|
|
const mncp_rhash_key *mncp_key = (const mncp_rhash_key*)v;
|
|
|
|
return GPOINTER_TO_UINT(mncp_key->conversation);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initializes the hash table and the mem_chunk area each time a new
|
|
|
|
* file is loaded or re-loaded in ethereal */
|
|
|
|
static void
|
|
|
|
mncp_init_protocol(void)
|
|
|
|
{
|
|
|
|
if (mncp_rhash)
|
|
|
|
g_hash_table_destroy(mncp_rhash);
|
|
|
|
if (mncp_rhash_keys)
|
|
|
|
g_mem_chunk_destroy(mncp_rhash_keys);
|
|
|
|
if (mncp_rhash_values)
|
|
|
|
g_mem_chunk_destroy(mncp_rhash_values);
|
|
|
|
|
|
|
|
mncp_rhash = g_hash_table_new(mncp_hash, mncp_equal);
|
|
|
|
mncp_rhash_keys = g_mem_chunk_new("mncp_rhash_keys",
|
|
|
|
sizeof(mncp_rhash_key),
|
|
|
|
200 * sizeof(mncp_rhash_key),
|
|
|
|
G_ALLOC_ONLY);
|
|
|
|
mncp_rhash_values = g_mem_chunk_new("mncp_rhash_values",
|
|
|
|
sizeof(mncp_rhash_value),
|
|
|
|
200 * sizeof(mncp_rhash_value),
|
|
|
|
G_ALLOC_ONLY);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* After the sequential run, we don't need the ncp_request hash and keys
|
|
|
|
* anymore; the lookups have already been done and the vital info
|
|
|
|
* saved in the reply-packets' private_data in the frame_data struct. */
|
|
|
|
static void
|
|
|
|
mncp_postseq_cleanup(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
mncp_rhash_value*
|
|
|
|
mncp_hash_insert(conversation_t *conversation)
|
|
|
|
{
|
|
|
|
mncp_rhash_key *key;
|
|
|
|
mncp_rhash_value *value;
|
|
|
|
|
|
|
|
/* Now remember the request, so we can find it if we later
|
|
|
|
a reply to it. */
|
|
|
|
key = g_mem_chunk_alloc(mncp_rhash_keys);
|
|
|
|
key->conversation = conversation;
|
|
|
|
|
|
|
|
value = g_mem_chunk_alloc(mncp_rhash_values);
|
|
|
|
value->packet_signature = FALSE;
|
|
|
|
|
|
|
|
g_hash_table_insert(mncp_rhash, key, value);
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns the ncp_rec*, or NULL if not found. */
|
|
|
|
mncp_rhash_value*
|
|
|
|
mncp_hash_lookup(conversation_t *conversation)
|
|
|
|
{
|
|
|
|
mncp_rhash_key key;
|
|
|
|
|
|
|
|
key.conversation = conversation;
|
|
|
|
|
|
|
|
return g_hash_table_lookup(mncp_rhash, &key);
|
|
|
|
}
|
1999-05-14 21:30:13 +00:00
|
|
|
|
2002-05-15 06:50:33 +00:00
|
|
|
/*
|
|
|
|
* Burst packet system flags.
|
|
|
|
*/
|
|
|
|
#define ABT 0x04 /* Abort request */
|
2004-06-15 09:30:54 +00:00
|
|
|
#define BSY 0x08 /* Server Busy */
|
2002-05-15 06:50:33 +00:00
|
|
|
#define EOB 0x10 /* End of burst */
|
2004-06-15 09:30:54 +00:00
|
|
|
#define LST 0x40 /* Include Fragment List */
|
2002-05-15 06:50:33 +00:00
|
|
|
#define SYS 0x80 /* System packet */
|
|
|
|
|
Allow either old-style (pre-tvbuff) or new-style (tvbuffified)
dissectors to be registered as dissectors for particular ports,
registered as heuristic dissectors, and registered as dissectors for
conversations, and have routines to be used both by old-style and
new-style dissectors to call registered dissectors.
Have the code that calls those dissectors translate the arguments as
necessary. (For conversation dissectors, replace
"find_conversation_dissector()", which just returns a pointer to the
dissector, with "old_try_conversation_dissector()" and
"try_conversation_dissector()", which actually call the dissector, so
that there's a single place at which we can do that translation. Also
make "dissector_lookup()" static and, instead of calling it and, if it
returns a non-null pointer, calling that dissector, just use
"old_dissector_try_port()" or "dissector_try_port()", for the same
reason.)
This allows some dissectors that took old-style arguments and
immediately translated them to new-style arguments to just take
new-style arguments; make them do so. It also allows some new-style
dissectors not to have to translate arguments before calling routines to
look up and call dissectors; make them not do so.
Get rid of checks for too-short frames in new-style dissectors - the
tvbuff code does those checks for you.
Give the routines to register old-style dissectors, and to call
dissectors from old-style dissectors, names beginning with "old_", with
the routines for new-style dissectors not having the "old_". Update the
dissectors that use those routines appropriately.
Rename "dissect_data()" to "old_dissect_data()", and
"dissect_data_tvb()" to "dissect_data()".
svn path=/trunk/; revision=2218
2000-08-07 03:21:25 +00:00
|
|
|
static void
|
2002-05-25 01:05:56 +00:00
|
|
|
dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
|
|
|
gboolean is_tcp)
|
2000-07-28 20:03:59 +00:00
|
|
|
{
|
|
|
|
proto_tree *ncp_tree = NULL;
|
|
|
|
proto_item *ti;
|
1999-12-07 06:13:19 +00:00
|
|
|
struct ncp_ip_header ncpiph;
|
|
|
|
struct ncp_ip_rqhdr ncpiphrq;
|
1998-10-15 21:12:17 +00:00
|
|
|
struct ncp_common_header header;
|
2004-06-15 09:30:54 +00:00
|
|
|
guint16 nw_connection, ncp_burst_seqno, ncp_ack_seqno;
|
2002-05-15 21:17:21 +00:00
|
|
|
guint16 flags = 0;
|
2002-05-15 06:50:33 +00:00
|
|
|
char flags_str[1+3+1+3+1+3+1+1];
|
|
|
|
char *sep;
|
|
|
|
proto_tree *flags_tree = NULL;
|
2002-05-15 21:17:21 +00:00
|
|
|
guint16 data_len = 0;
|
|
|
|
guint16 missing_fraglist_count = 0;
|
2000-07-28 20:03:59 +00:00
|
|
|
int hdr_offset = 0;
|
|
|
|
int commhdr;
|
2002-05-15 06:50:33 +00:00
|
|
|
int offset;
|
2002-05-15 21:17:21 +00:00
|
|
|
gint length_remaining;
|
2001-07-12 01:48:05 +00:00
|
|
|
tvbuff_t *next_tvb;
|
2004-06-15 09:30:54 +00:00
|
|
|
guint32 testvar = 0, ncp_burst_command, burst_len, burst_off, burst_file;
|
2002-10-10 03:03:30 +00:00
|
|
|
guint8 subfunction;
|
2004-07-28 08:23:52 +00:00
|
|
|
mncp_rhash_value *request_value = NULL;
|
|
|
|
conversation_t *conversation;
|
|
|
|
char *burst_command_name;
|
2000-07-28 20:03:59 +00:00
|
|
|
|
2001-12-10 00:26:21 +00:00
|
|
|
if (check_col(pinfo->cinfo, COL_PROTOCOL))
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
|
|
|
|
if (check_col(pinfo->cinfo, COL_INFO))
|
|
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
1999-03-20 04:38:57 +00:00
|
|
|
|
2003-10-23 07:52:56 +00:00
|
|
|
hdr_offset = 0;
|
2003-08-25 22:14:07 +00:00
|
|
|
|
2004-07-28 08:23:52 +00:00
|
|
|
if (is_tcp) {
|
|
|
|
if (tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RQST && tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RPLY)
|
2003-10-23 07:52:56 +00:00
|
|
|
hdr_offset += 1;
|
2003-08-25 22:14:07 +00:00
|
|
|
ncpiph.signature = tvb_get_ntohl(tvb, hdr_offset);
|
|
|
|
ncpiph.length = tvb_get_ntohl(tvb, hdr_offset+4);
|
2000-07-28 20:03:59 +00:00
|
|
|
hdr_offset += 8;
|
2004-07-28 08:23:52 +00:00
|
|
|
if (ncpiph.signature == NCPIP_RQST) {
|
2000-07-28 20:03:59 +00:00
|
|
|
ncpiphrq.version = tvb_get_ntohl(tvb, hdr_offset);
|
|
|
|
hdr_offset += 4;
|
|
|
|
ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, hdr_offset);
|
|
|
|
hdr_offset += 4;
|
2002-05-24 03:03:49 +00:00
|
|
|
}
|
2004-07-28 08:23:52 +00:00
|
|
|
/* Ok, we need to track the conversation so that we can
|
|
|
|
* determine if packet signature is occuring for this
|
|
|
|
* connection. We will store the conversation the first
|
|
|
|
* time and that state of packet signature will be stored
|
|
|
|
* later in our logic. This way when we dissect reply
|
|
|
|
* packets we will be able to determine if we need
|
|
|
|
* to also dissect with a signature.
|
|
|
|
*/
|
|
|
|
conversation = find_conversation(&pinfo->src, &pinfo->dst,
|
|
|
|
PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport,
|
|
|
|
0);
|
|
|
|
if ((ncpiph.length & 0x80000000) ||
|
|
|
|
ncpiph.signature == NCPIP_RPLY) {
|
|
|
|
/* First time through we will store packet signature
|
|
|
|
* state
|
|
|
|
*/
|
|
|
|
if (!pinfo->fd->flags.visited) {
|
|
|
|
if (conversation != NULL) {
|
|
|
|
/* find the record telling us the
|
|
|
|
* request made that caused this
|
|
|
|
* reply
|
|
|
|
*/
|
|
|
|
request_value =
|
|
|
|
mncp_hash_lookup(conversation);
|
|
|
|
/* if for some reason we have no
|
|
|
|
* conversation in our hash, create
|
|
|
|
* one */
|
|
|
|
if (request_value == NULL) {
|
|
|
|
request_value =
|
|
|
|
mncp_hash_insert(conversation);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* It's not part of any conversation
|
|
|
|
* - create a new one.
|
|
|
|
*/
|
|
|
|
conversation = conversation_new(&pinfo->src,
|
|
|
|
&pinfo->dst, PT_NCP,
|
|
|
|
(guint32) pinfo->srcport,
|
|
|
|
(guint32) pinfo->destport, 0);
|
|
|
|
request_value =
|
|
|
|
mncp_hash_insert(conversation);
|
|
|
|
}
|
|
|
|
/* If this is a request packet then we know
|
|
|
|
* that we have a signature
|
|
|
|
*/
|
|
|
|
if (ncpiph.signature == NCPIP_RQST) {
|
2003-10-23 07:52:56 +00:00
|
|
|
hdr_offset += 8;
|
|
|
|
ncpiph.length &= 0x7fffffff;
|
2004-07-28 08:23:52 +00:00
|
|
|
request_value->packet_signature=TRUE;
|
|
|
|
} else {
|
|
|
|
/* Now on reply packets we have to
|
|
|
|
* use the state of the original
|
|
|
|
* request packet, so look up the
|
|
|
|
* request value and check the state
|
|
|
|
* of packet signature
|
|
|
|
*/
|
|
|
|
request_value =
|
|
|
|
mncp_hash_lookup(conversation);
|
|
|
|
if (request_value->packet_signature) {
|
2003-10-23 07:52:56 +00:00
|
|
|
hdr_offset += 8;
|
|
|
|
ncpiph.length &= 0x7fffffff;
|
2004-07-28 08:23:52 +00:00
|
|
|
/* XXX - it already *is* TRUE */
|
|
|
|
request_value->packet_signature=TRUE;
|
|
|
|
} else {
|
|
|
|
/* XXX - it already *is* FALSE */
|
|
|
|
request_value->packet_signature=FALSE;
|
|
|
|
}
|
2003-10-23 07:52:56 +00:00
|
|
|
}
|
2004-07-28 08:23:52 +00:00
|
|
|
} else {
|
|
|
|
/* Get request value data */
|
|
|
|
request_value = mncp_hash_lookup(conversation);
|
|
|
|
if (request_value->packet_signature) {
|
2003-10-23 07:52:56 +00:00
|
|
|
hdr_offset += 8;
|
|
|
|
ncpiph.length &= 0x7fffffff;
|
|
|
|
}
|
|
|
|
}
|
2004-07-28 08:23:52 +00:00
|
|
|
} else {
|
|
|
|
if (!pinfo->fd->flags.visited) {
|
|
|
|
if (conversation != NULL) {
|
|
|
|
/* find the record telling us the
|
|
|
|
* request made that caused this
|
|
|
|
* reply
|
|
|
|
*/
|
|
|
|
request_value =
|
|
|
|
mncp_hash_lookup(conversation);
|
|
|
|
/* if for some reason we have no
|
|
|
|
* conversation in our hash, create
|
|
|
|
* one */
|
|
|
|
if (request_value == NULL) {
|
|
|
|
request_value =
|
|
|
|
mncp_hash_insert(conversation);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* It's not part of any conversation
|
|
|
|
* - create a new one.
|
|
|
|
*/
|
|
|
|
conversation = conversation_new(&pinfo->src,
|
|
|
|
&pinfo->dst, PT_NCP,
|
|
|
|
(guint32) pinfo->srcport,
|
|
|
|
(guint32) pinfo->destport, 0);
|
|
|
|
request_value =
|
|
|
|
mncp_hash_insert(conversation);
|
|
|
|
}
|
|
|
|
/* find the record telling us the request
|
|
|
|
* made that caused this reply
|
|
|
|
*/
|
|
|
|
request_value->packet_signature=FALSE;
|
|
|
|
} else {
|
|
|
|
request_value = mncp_hash_lookup(conversation);
|
|
|
|
}
|
|
|
|
}
|
2002-05-24 03:03:49 +00:00
|
|
|
}
|
1999-12-15 04:20:46 +00:00
|
|
|
|
2000-07-28 20:03:59 +00:00
|
|
|
/* Record the offset where the NCP common header starts */
|
|
|
|
commhdr = hdr_offset;
|
1998-09-23 05:25:12 +00:00
|
|
|
|
2003-10-23 07:52:56 +00:00
|
|
|
header.type = tvb_get_ntohs(tvb, commhdr);
|
2000-07-28 20:03:59 +00:00
|
|
|
header.sequence = tvb_get_guint8(tvb, commhdr+2);
|
|
|
|
header.conn_low = tvb_get_guint8(tvb, commhdr+3);
|
|
|
|
header.conn_high = tvb_get_guint8(tvb, commhdr+5);
|
1999-05-13 16:42:43 +00:00
|
|
|
|
2002-05-15 06:50:33 +00:00
|
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
2002-09-22 15:46:42 +00:00
|
|
|
col_add_fstr(pinfo->cinfo, COL_INFO,
|
2002-05-15 06:50:33 +00:00
|
|
|
"%s",
|
|
|
|
val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
|
|
|
|
}
|
|
|
|
|
1999-03-20 04:38:57 +00:00
|
|
|
nw_connection = (header.conn_high << 16) + header.conn_low;
|
1998-10-15 21:12:17 +00:00
|
|
|
|
1998-09-23 05:25:12 +00:00
|
|
|
if (tree) {
|
2002-01-24 09:20:54 +00:00
|
|
|
ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE);
|
1999-11-16 11:44:20 +00:00
|
|
|
ncp_tree = proto_item_add_subtree(ti, ett_ncp);
|
1998-09-23 05:25:12 +00:00
|
|
|
|
2002-05-25 01:05:56 +00:00
|
|
|
if (is_tcp) {
|
2000-07-28 20:03:59 +00:00
|
|
|
proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature);
|
|
|
|
proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length);
|
2002-05-15 21:17:21 +00:00
|
|
|
if (ncpiph.signature == NCPIP_RQST) {
|
2000-07-28 20:03:59 +00:00
|
|
|
proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version);
|
|
|
|
proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize);
|
2004-02-18 06:01:47 +00:00
|
|
|
if (request_value->packet_signature==TRUE)
|
2003-10-23 07:52:56 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 16, 8, FALSE);
|
|
|
|
} else {
|
2004-02-18 06:01:47 +00:00
|
|
|
if (request_value->packet_signature==TRUE)
|
2003-10-23 07:52:56 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 8, 8, FALSE);
|
2002-05-15 21:17:21 +00:00
|
|
|
}
|
|
|
|
}
|
2000-07-28 20:03:59 +00:00
|
|
|
proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr + 0, 2, header.type);
|
1999-03-20 04:38:57 +00:00
|
|
|
}
|
1998-09-23 05:25:12 +00:00
|
|
|
|
|
|
|
|
2002-05-15 21:17:21 +00:00
|
|
|
/*
|
|
|
|
* Process the packet-type-specific header.
|
|
|
|
*/
|
2002-05-15 06:50:33 +00:00
|
|
|
switch (header.type) {
|
|
|
|
|
2002-10-10 03:03:30 +00:00
|
|
|
case NCP_BROADCAST_SLOT: /* Server Broadcast */
|
|
|
|
proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
|
2002-05-15 06:50:33 +00:00
|
|
|
proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
|
2002-08-23 17:47:31 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, FALSE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, FALSE);
|
2002-10-10 03:03:30 +00:00
|
|
|
break;
|
2002-05-15 06:50:33 +00:00
|
|
|
|
2002-10-10 03:03:30 +00:00
|
|
|
case NCP_LIP_ECHO: /* Lip Echo Packet */
|
2003-08-25 22:14:07 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 13, FALSE);
|
2002-10-10 03:03:30 +00:00
|
|
|
break;
|
2002-08-23 17:47:31 +00:00
|
|
|
|
2002-10-10 03:03:30 +00:00
|
|
|
case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
|
2002-05-15 06:50:33 +00:00
|
|
|
/*
|
|
|
|
* XXX - we should keep track of whether there's a burst
|
|
|
|
* outstanding on a connection and, if not, treat the
|
|
|
|
* beginning of the data as a burst header.
|
|
|
|
*
|
|
|
|
* The burst header contains:
|
|
|
|
*
|
|
|
|
* 4 bytes of little-endian function number:
|
|
|
|
* 1 = read, 2 = write;
|
|
|
|
*
|
|
|
|
* 4 bytes of file handle;
|
|
|
|
*
|
|
|
|
* 8 reserved bytes;
|
|
|
|
*
|
|
|
|
* 4 bytes of big-endian file offset;
|
|
|
|
*
|
|
|
|
* 4 bytes of big-endian byte count.
|
|
|
|
*
|
|
|
|
* The data follows for a burst write operation.
|
|
|
|
*
|
|
|
|
* The first packet of a burst read reply contains:
|
|
|
|
*
|
|
|
|
* 4 bytes of little-endian result code:
|
|
|
|
* 0: No error
|
|
|
|
* 1: Initial error
|
|
|
|
* 2: I/O error
|
|
|
|
* 3: No data read;
|
|
|
|
*
|
|
|
|
* 4 bytes of returned byte count (big-endian?).
|
|
|
|
*
|
|
|
|
* The data follows.
|
|
|
|
*
|
|
|
|
* Each burst of a write request is responded to with a
|
|
|
|
* burst packet with a 2-byte little-endian result code:
|
|
|
|
*
|
|
|
|
* 0: Write successful
|
|
|
|
* 4: Write error
|
|
|
|
*/
|
|
|
|
flags = tvb_get_guint8(tvb, commhdr + 2);
|
|
|
|
strcpy(flags_str, "");
|
|
|
|
sep = " (";
|
|
|
|
if (flags & ABT) {
|
|
|
|
strcat(flags_str, sep);
|
|
|
|
strcat(flags_str, "ABT");
|
|
|
|
sep = ",";
|
|
|
|
}
|
2004-06-15 09:30:54 +00:00
|
|
|
if (flags & BSY) {
|
|
|
|
strcat(flags_str, sep);
|
|
|
|
strcat(flags_str, "BSY");
|
|
|
|
sep = ",";
|
|
|
|
}
|
2002-05-15 06:50:33 +00:00
|
|
|
if (flags & EOB) {
|
|
|
|
strcat(flags_str, sep);
|
|
|
|
strcat(flags_str, "EOB");
|
|
|
|
sep = ",";
|
|
|
|
}
|
2004-06-15 09:30:54 +00:00
|
|
|
if (flags & LST) {
|
|
|
|
strcat(flags_str, sep);
|
|
|
|
strcat(flags_str, "LST");
|
|
|
|
sep = ",";
|
|
|
|
}
|
2002-05-15 06:50:33 +00:00
|
|
|
if (flags & SYS) {
|
|
|
|
strcat(flags_str, sep);
|
|
|
|
strcat(flags_str, "SYS");
|
|
|
|
}
|
|
|
|
if (flags_str[0] != '\0')
|
|
|
|
strcat(flags_str, ")");
|
|
|
|
ti = proto_tree_add_uint_format(ncp_tree, hf_ncp_system_flags,
|
|
|
|
tvb, commhdr + 2, 1, flags, "Flags: 0x%04x%s", flags,
|
|
|
|
flags_str);
|
|
|
|
flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
|
|
|
|
proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
|
|
|
|
tvb, commhdr + 2, 1, FALSE);
|
2004-06-15 09:30:54 +00:00
|
|
|
proto_tree_add_item(flags_tree, hf_ncp_system_flags_bsy,
|
|
|
|
tvb, commhdr + 2, 1, FALSE);
|
2002-05-15 06:50:33 +00:00
|
|
|
proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
|
|
|
|
tvb, commhdr + 2, 1, FALSE);
|
2004-06-15 09:30:54 +00:00
|
|
|
proto_tree_add_item(flags_tree, hf_ncp_system_flags_lst,
|
|
|
|
tvb, commhdr + 2, 1, FALSE);
|
2002-05-15 06:50:33 +00:00
|
|
|
proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
|
|
|
|
tvb, commhdr + 2, 1, FALSE);
|
|
|
|
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
|
|
|
|
tvb, commhdr + 3, 1, FALSE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
|
|
|
|
tvb, commhdr + 4, 4, FALSE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
|
|
|
|
tvb, commhdr + 8, 4, FALSE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
|
|
|
|
tvb, commhdr + 12, 4, FALSE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
|
|
|
|
tvb, commhdr + 16, 4, FALSE);
|
2004-07-28 08:23:52 +00:00
|
|
|
ncp_burst_seqno = tvb_get_ntohs(tvb, commhdr+20);
|
2002-05-15 06:50:33 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
|
|
|
|
tvb, commhdr + 20, 2, FALSE);
|
2004-07-28 08:23:52 +00:00
|
|
|
ncp_ack_seqno = tvb_get_ntohs(tvb, commhdr+22);
|
2002-05-15 06:50:33 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
|
|
|
|
tvb, commhdr + 22, 2, FALSE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
|
|
|
|
tvb, commhdr + 24, 4, FALSE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_data_offset,
|
|
|
|
tvb, commhdr + 28, 4, FALSE);
|
|
|
|
data_len = tvb_get_ntohs(tvb, commhdr + 32);
|
|
|
|
proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
|
|
|
|
tvb, commhdr + 32, 2, data_len);
|
|
|
|
missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
|
|
|
|
tvb, commhdr + 34, 2, FALSE);
|
2004-07-28 08:23:52 +00:00
|
|
|
if (ncp_burst_seqno == ncp_ack_seqno) {
|
|
|
|
ncp_burst_command = tvb_get_ntohl(tvb, commhdr+36);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_burst_command,
|
|
|
|
tvb, commhdr + 36, 4, FALSE);
|
|
|
|
burst_file = tvb_get_ntohl(tvb, commhdr+40);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_burst_file_handle,
|
|
|
|
tvb, commhdr + 40, 4, FALSE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_burst_reserved,
|
|
|
|
tvb, commhdr + 44, 8, FALSE);
|
|
|
|
burst_off = tvb_get_ntohl(tvb, commhdr+52);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_data_offset,
|
|
|
|
tvb, commhdr + 52, 4, FALSE);
|
|
|
|
burst_len = tvb_get_ntohl(tvb, commhdr+56);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
|
|
|
|
tvb, commhdr + 56, 4, FALSE);
|
|
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
|
|
|
burst_command_name =
|
|
|
|
match_strval(ncp_burst_command,
|
|
|
|
burst_command);
|
|
|
|
if (burst_command_name != NULL) {
|
|
|
|
col_add_fstr(pinfo->cinfo, COL_INFO,
|
|
|
|
"%s %d bytes starting at offset %d in file 0x%08x",
|
|
|
|
burst_command_name, burst_len,
|
|
|
|
burst_off, burst_file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (tvb_get_guint8(tvb, commhdr + 2) & 0x10) {
|
|
|
|
if (check_col(pinfo->cinfo, COL_INFO)) {
|
|
|
|
col_set_str(pinfo->cinfo, COL_INFO,
|
|
|
|
"End of Burst");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-05-15 21:17:21 +00:00
|
|
|
break;
|
2002-08-23 17:47:31 +00:00
|
|
|
|
|
|
|
case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
|
2002-10-10 03:03:30 +00:00
|
|
|
length_remaining = tvb_length_remaining(tvb, commhdr + 4);
|
|
|
|
if (length_remaining > 4) {
|
|
|
|
testvar = tvb_get_ntohl(tvb, commhdr+4);
|
|
|
|
if (testvar == 0x4c495020) {
|
|
|
|
proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr+4, 13, FALSE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* otherwise fall through */
|
2002-09-25 00:37:01 +00:00
|
|
|
|
|
|
|
case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
|
2002-10-10 03:03:30 +00:00
|
|
|
case NCP_SERVICE_REQUEST: /* Server NCP Request */
|
|
|
|
case NCP_SERVICE_REPLY: /* Server NCP Reply */
|
|
|
|
case NCP_WATCHDOG: /* Watchdog Packet */
|
2002-08-23 17:47:31 +00:00
|
|
|
case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
|
|
|
|
default:
|
|
|
|
proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
|
|
|
|
proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
|
|
|
|
break;
|
2002-05-15 21:17:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process the packet body.
|
|
|
|
*/
|
|
|
|
switch (header.type) {
|
|
|
|
|
2002-10-10 03:03:30 +00:00
|
|
|
case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
|
|
|
|
length_remaining = tvb_length_remaining(tvb, commhdr + 4);
|
|
|
|
if (length_remaining > 4) {
|
|
|
|
testvar = tvb_get_ntohl(tvb, commhdr+4);
|
|
|
|
if (testvar == 0x4c495020) {
|
|
|
|
proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
|
|
|
|
"Lip Echo Packet");
|
|
|
|
/*break;*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case NCP_SERVICE_REQUEST: /* Server NCP Request */
|
2003-10-23 07:52:56 +00:00
|
|
|
case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
|
2002-10-10 03:03:30 +00:00
|
|
|
case NCP_BROADCAST_SLOT: /* Server Broadcast Packet */
|
2002-05-15 21:17:21 +00:00
|
|
|
next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
|
2002-10-10 03:03:30 +00:00
|
|
|
if (tvb_get_guint8(tvb, commhdr+6) == 0x68) {
|
|
|
|
subfunction = tvb_get_guint8(tvb, commhdr+7);
|
|
|
|
switch (subfunction) {
|
|
|
|
|
|
|
|
case 0x02: /* NDS Frag Packet to decode */
|
|
|
|
dissect_nds_request(next_tvb, pinfo,
|
|
|
|
nw_connection, header.sequence,
|
|
|
|
header.type, ncp_tree);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x01: /* NDS Ping */
|
|
|
|
dissect_ping_req(next_tvb, pinfo,
|
|
|
|
nw_connection, header.sequence,
|
|
|
|
header.type, ncp_tree);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
dissect_ncp_request(next_tvb, pinfo,
|
|
|
|
nw_connection, header.sequence,
|
|
|
|
header.type, ncp_tree);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dissect_ncp_request(next_tvb, pinfo, nw_connection,
|
|
|
|
header.sequence, header.type, ncp_tree);
|
|
|
|
}
|
2002-05-15 21:17:21 +00:00
|
|
|
break;
|
|
|
|
|
2002-10-10 03:03:30 +00:00
|
|
|
case NCP_SERVICE_REPLY: /* Server NCP Reply */
|
2003-12-22 02:04:18 +00:00
|
|
|
next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
|
|
|
|
nds_defrag(next_tvb, pinfo, nw_connection, header.sequence,
|
|
|
|
header.type, ncp_tree);
|
|
|
|
break;
|
|
|
|
|
2002-05-16 09:59:52 +00:00
|
|
|
case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
|
2003-12-22 02:04:18 +00:00
|
|
|
/*
|
|
|
|
* XXX - this used to call "nds_defrag()", which would
|
|
|
|
* clear out "frags". Was that the right thing to
|
|
|
|
* do?
|
|
|
|
*/
|
2002-05-15 21:17:21 +00:00
|
|
|
next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
|
2003-12-22 02:04:18 +00:00
|
|
|
dissect_ncp_reply(next_tvb, pinfo, nw_connection,
|
|
|
|
header.sequence, header.type, ncp_tree);
|
2002-05-15 21:17:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NCP_WATCHDOG: /* Watchdog Packet */
|
2002-05-16 09:59:52 +00:00
|
|
|
/*
|
|
|
|
* XXX - should the completion code be interpreted as
|
|
|
|
* it is in "packet-ncp2222.inc"? If so, this
|
|
|
|
* packet should be handled by "dissect_ncp_reply()".
|
|
|
|
*/
|
2002-05-15 21:17:21 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_completion_code,
|
|
|
|
tvb, commhdr + 6, 1, TRUE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_connection_status,
|
|
|
|
tvb, commhdr + 7, 1, TRUE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_slot,
|
|
|
|
tvb, commhdr + 8, 1, TRUE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_control_code,
|
|
|
|
tvb, commhdr + 9, 1, TRUE);
|
|
|
|
/*
|
|
|
|
* Display the rest of the packet as data.
|
|
|
|
*/
|
|
|
|
if (tvb_offset_exists(tvb, commhdr + 10)) {
|
|
|
|
call_dissector(data_handle,
|
|
|
|
tvb_new_subset(tvb, commhdr + 10, -1, -1),
|
|
|
|
pinfo, ncp_tree);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
|
2002-05-15 06:50:33 +00:00
|
|
|
if (flags & SYS) {
|
|
|
|
/*
|
|
|
|
* System packet; show missing fragments if there
|
|
|
|
* are any.
|
|
|
|
*/
|
|
|
|
offset = commhdr + 36;
|
|
|
|
while (missing_fraglist_count != 0) {
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
|
|
|
|
tvb, offset, 4, FALSE);
|
|
|
|
proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
|
|
|
|
tvb, offset, 2, FALSE);
|
|
|
|
missing_fraglist_count--;
|
|
|
|
}
|
|
|
|
} else {
|
2002-05-15 21:17:21 +00:00
|
|
|
/*
|
|
|
|
* XXX - do this by using -1 and -1 as the length
|
|
|
|
* arguments to "tvb_new_subset()" and then calling
|
|
|
|
* "tvb_set_reported_length()"? That'll throw an
|
|
|
|
* exception if "data_len" goes past the reported
|
|
|
|
* length of the packet, but that's arguably a
|
|
|
|
* feature in this case.
|
|
|
|
*/
|
|
|
|
length_remaining = tvb_length_remaining(tvb, commhdr + 36);
|
|
|
|
if (length_remaining > data_len)
|
|
|
|
length_remaining = data_len;
|
2002-05-15 06:50:33 +00:00
|
|
|
if (data_len != 0) {
|
2002-05-15 21:17:21 +00:00
|
|
|
call_dissector(data_handle,
|
|
|
|
tvb_new_subset(tvb, commhdr + 36,
|
|
|
|
length_remaining, data_len),
|
|
|
|
pinfo, ncp_tree);
|
2002-05-15 06:50:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2002-10-10 03:03:30 +00:00
|
|
|
|
|
|
|
case NCP_LIP_ECHO: /* LIP Echo Packet */
|
|
|
|
proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
|
|
|
|
"Lip Echo Packet");
|
|
|
|
break;
|
|
|
|
|
2002-05-15 06:50:33 +00:00
|
|
|
default:
|
2002-05-15 21:17:21 +00:00
|
|
|
if (tree) {
|
2002-09-22 15:46:42 +00:00
|
|
|
proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1,
|
2002-05-15 21:17:21 +00:00
|
|
|
"%s packets not supported yet",
|
|
|
|
val_to_str(header.type, ncp_type_vals,
|
|
|
|
"Unknown type (0x%04x)"));
|
|
|
|
}
|
2002-05-15 06:50:33 +00:00
|
|
|
break;
|
2000-07-28 20:03:59 +00:00
|
|
|
}
|
1999-05-13 16:42:43 +00:00
|
|
|
}
|
1999-05-14 21:30:13 +00:00
|
|
|
|
2002-05-25 01:05:56 +00:00
|
|
|
static void
|
|
|
|
dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
|
|
{
|
|
|
|
dissect_ncp_common(tvb, pinfo, tree, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static guint
|
|
|
|
get_ncp_pdu_len(tvbuff_t *tvb, int offset)
|
|
|
|
{
|
2002-05-25 12:44:06 +00:00
|
|
|
guint32 signature;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the NCP-over-TCP header signature, to make sure it's there.
|
|
|
|
* If it's not there, we cannot trust the next 4 bytes to be a
|
|
|
|
* packet length+"has signature" flag, so we just say the length is
|
|
|
|
* "what remains in the packet".
|
|
|
|
*/
|
2003-08-25 22:14:07 +00:00
|
|
|
/*if (tvb_get_guint8(tvb, offset)==0xff)
|
|
|
|
{
|
|
|
|
offset += 1;
|
|
|
|
}*/
|
2002-05-25 12:44:06 +00:00
|
|
|
signature = tvb_get_ntohl(tvb, offset);
|
|
|
|
if (signature != NCPIP_RQST && signature != NCPIP_RPLY)
|
|
|
|
return tvb_length_remaining(tvb, offset);
|
2002-08-28 21:04:11 +00:00
|
|
|
|
2002-05-25 01:05:56 +00:00
|
|
|
/*
|
|
|
|
* Get the length of the NCP-over-TCP packet. Strip off the "has
|
|
|
|
* signature" flag.
|
|
|
|
*/
|
2002-09-22 15:46:42 +00:00
|
|
|
|
2002-05-25 01:05:56 +00:00
|
|
|
return tvb_get_ntohl(tvb, offset + 4) & 0x7fffffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dissect_ncp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
|
|
{
|
|
|
|
dissect_ncp_common(tvb, pinfo, tree, TRUE);
|
|
|
|
}
|
1999-05-14 21:30:13 +00:00
|
|
|
|
2002-05-25 01:05:56 +00:00
|
|
|
static void
|
|
|
|
dissect_ncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
|
|
{
|
|
|
|
tcp_dissect_pdus(tvb, pinfo, tree, ncp_desegment, 8, get_ncp_pdu_len,
|
|
|
|
dissect_ncp_tcp_pdu);
|
|
|
|
}
|
1999-07-29 05:47:07 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
proto_register_ncp(void)
|
|
|
|
{
|
|
|
|
|
1999-10-17 14:09:35 +00:00
|
|
|
static hf_register_info hf[] = {
|
1999-12-07 06:13:19 +00:00
|
|
|
{ &hf_ncp_ip_sig,
|
2002-05-24 03:03:49 +00:00
|
|
|
{ "NCP over IP signature", "ncp.ip.signature",
|
1999-12-07 06:13:19 +00:00
|
|
|
FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
|
2001-06-18 02:18:27 +00:00
|
|
|
"", HFILL }},
|
2000-07-28 20:03:59 +00:00
|
|
|
{ &hf_ncp_ip_length,
|
|
|
|
{ "NCP over IP length", "ncp.ip.length",
|
2002-05-24 03:03:49 +00:00
|
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
2001-06-18 02:18:27 +00:00
|
|
|
"", HFILL }},
|
1999-12-07 06:13:19 +00:00
|
|
|
{ &hf_ncp_ip_ver,
|
2000-07-28 20:03:59 +00:00
|
|
|
{ "NCP over IP Version", "ncp.ip.version",
|
1999-12-07 06:13:19 +00:00
|
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
2001-06-18 02:18:27 +00:00
|
|
|
"", HFILL }},
|
2000-07-28 20:03:59 +00:00
|
|
|
{ &hf_ncp_ip_rplybufsize,
|
|
|
|
{ "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize",
|
|
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
2001-06-18 02:18:27 +00:00
|
|
|
"", HFILL }},
|
2002-05-24 03:03:49 +00:00
|
|
|
{ &hf_ncp_ip_packetsig,
|
|
|
|
{ "NCP over IP Packet Signature", "ncp.ip.packetsig",
|
|
|
|
FT_BYTES, BASE_NONE, NULL, 0x0,
|
|
|
|
"", HFILL }},
|
1999-10-17 14:09:35 +00:00
|
|
|
{ &hf_ncp_type,
|
|
|
|
{ "Type", "ncp.type",
|
2000-07-28 20:03:59 +00:00
|
|
|
FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
|
2001-06-18 02:18:27 +00:00
|
|
|
"NCP message type", HFILL }},
|
1999-10-17 14:09:35 +00:00
|
|
|
{ &hf_ncp_seq,
|
|
|
|
{ "Sequence Number", "ncp.seq",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
2001-06-18 02:18:27 +00:00
|
|
|
"", HFILL }},
|
1999-10-17 14:09:35 +00:00
|
|
|
{ &hf_ncp_connection,
|
|
|
|
{ "Connection Number", "ncp.connection",
|
|
|
|
FT_UINT16, BASE_DEC, NULL, 0x0,
|
2001-06-18 02:18:27 +00:00
|
|
|
"", HFILL }},
|
1999-10-17 14:09:35 +00:00
|
|
|
{ &hf_ncp_task,
|
|
|
|
{ "Task Number", "ncp.task",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
2002-05-15 06:50:33 +00:00
|
|
|
"", HFILL }},
|
2002-08-23 17:47:31 +00:00
|
|
|
{ &hf_ncp_oplock_flag,
|
|
|
|
{ "Oplock Flag", "ncp.oplock_flag",
|
|
|
|
FT_UINT8, BASE_HEX, NULL, 0x0,
|
|
|
|
"", HFILL }},
|
|
|
|
{ &hf_ncp_oplock_handle,
|
|
|
|
{ "File Handle", "ncp.oplock_handle",
|
|
|
|
FT_UINT16, BASE_HEX, NULL, 0x0,
|
|
|
|
"", HFILL }},
|
2002-05-15 06:50:33 +00:00
|
|
|
{ &hf_ncp_stream_type,
|
|
|
|
{ "Stream Type", "ncp.stream_type",
|
|
|
|
FT_UINT8, BASE_HEX, NULL, 0x0,
|
|
|
|
"Type of burst", HFILL }},
|
|
|
|
{ &hf_ncp_system_flags,
|
|
|
|
{ "System Flags", "ncp.system_flags",
|
|
|
|
FT_UINT8, BASE_HEX, NULL, 0x0,
|
|
|
|
"", HFILL }},
|
|
|
|
{ &hf_ncp_system_flags_abt,
|
|
|
|
{ "ABT", "ncp.system_flags.abt",
|
|
|
|
FT_BOOLEAN, 8, NULL, ABT,
|
|
|
|
"Is this an abort request?", HFILL }},
|
|
|
|
{ &hf_ncp_system_flags_eob,
|
|
|
|
{ "EOB", "ncp.system_flags.eob",
|
|
|
|
FT_BOOLEAN, 8, NULL, EOB,
|
|
|
|
"Is this the last packet of the burst?", HFILL }},
|
|
|
|
{ &hf_ncp_system_flags_sys,
|
|
|
|
{ "SYS", "ncp.system_flags.sys",
|
|
|
|
FT_BOOLEAN, 8, NULL, SYS,
|
|
|
|
"Is this a system packet?", HFILL }},
|
2004-06-15 09:30:54 +00:00
|
|
|
{ &hf_ncp_system_flags_bsy,
|
|
|
|
{ "BSY", "ncp.system_flags.bsy",
|
|
|
|
FT_BOOLEAN, 8, NULL, BSY,
|
|
|
|
"Is the server busy?", HFILL }},
|
|
|
|
{ &hf_ncp_system_flags_lst,
|
|
|
|
{ "LST", "ncp.system_flags.lst",
|
|
|
|
FT_BOOLEAN, 8, NULL, LST,
|
|
|
|
"Return Fragment List?", HFILL }},
|
2002-05-15 06:50:33 +00:00
|
|
|
{ &hf_ncp_src_connection,
|
|
|
|
{ "Source Connection ID", "ncp.src_connection",
|
|
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
|
|
|
"The workstation's connection identification number", HFILL }},
|
|
|
|
{ &hf_ncp_dst_connection,
|
|
|
|
{ "Destination Connection ID", "ncp.dst_connection",
|
|
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
|
|
|
"The server's connection identification number", HFILL }},
|
|
|
|
{ &hf_ncp_packet_seqno,
|
|
|
|
{ "Packet Sequence Number", "ncp.packet_seqno",
|
|
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
|
|
|
"Sequence number of this packet in a burst", HFILL }},
|
|
|
|
{ &hf_ncp_delay_time,
|
|
|
|
{ "Delay Time", "ncp.delay_time", /* in 100 us increments */
|
|
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
|
|
|
"Delay time between consecutive packet sends (100 us increments)", HFILL }},
|
|
|
|
{ &hf_ncp_burst_seqno,
|
|
|
|
{ "Burst Sequence Number", "ncp.burst_seqno",
|
|
|
|
FT_UINT16, BASE_DEC, NULL, 0x0,
|
|
|
|
"Sequence number of this packet in the burst", HFILL }},
|
|
|
|
{ &hf_ncp_ack_seqno,
|
|
|
|
{ "ACK Sequence Number", "ncp.ack_seqno",
|
|
|
|
FT_UINT16, BASE_DEC, NULL, 0x0,
|
|
|
|
"Next expected burst sequence number", HFILL }},
|
|
|
|
{ &hf_ncp_burst_len,
|
|
|
|
{ "Burst Length", "ncp.burst_len",
|
|
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
|
|
|
"Total length of data in this burst", HFILL }},
|
|
|
|
{ &hf_ncp_data_offset,
|
|
|
|
{ "Data Offset", "ncp.data_offset",
|
|
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
|
|
|
"Offset of this packet in the burst", HFILL }},
|
|
|
|
{ &hf_ncp_data_bytes,
|
|
|
|
{ "Data Bytes", "ncp.data_bytes",
|
|
|
|
FT_UINT16, BASE_DEC, NULL, 0x0,
|
|
|
|
"Number of data bytes in this packet", HFILL }},
|
|
|
|
{ &hf_ncp_missing_fraglist_count,
|
|
|
|
{ "Missing Fragment List Count", "ncp.missing_fraglist_count",
|
|
|
|
FT_UINT16, BASE_DEC, NULL, 0x0,
|
|
|
|
"Number of missing fragments reported", HFILL }},
|
|
|
|
{ &hf_ncp_missing_data_offset,
|
|
|
|
{ "Missing Data Offset", "ncp.missing_data_offset",
|
|
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
|
|
|
"Offset of beginning of missing data", HFILL }},
|
|
|
|
{ &hf_ncp_missing_data_count,
|
|
|
|
{ "Missing Data Count", "ncp.missing_data_count",
|
|
|
|
FT_UINT16, BASE_DEC, NULL, 0x0,
|
|
|
|
"Number of bytes of missing data", HFILL }},
|
2002-05-15 21:17:21 +00:00
|
|
|
{ &hf_ncp_completion_code,
|
|
|
|
{ "Completion Code", "ncp.completion_code",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
|
|
"", HFILL }},
|
|
|
|
{ &hf_ncp_connection_status,
|
|
|
|
{ "Connection Status", "ncp.connection_status",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
|
|
"", HFILL }},
|
|
|
|
{ &hf_ncp_slot,
|
|
|
|
{ "Slot", "ncp.slot",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
|
|
"", HFILL }},
|
|
|
|
{ &hf_ncp_control_code,
|
|
|
|
{ "Control Code", "ncp.control_code",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
|
|
"", HFILL }},
|
2002-08-23 17:47:31 +00:00
|
|
|
{ &hf_ncp_fragment_handle,
|
|
|
|
{ "Fragment Handle", "ncp.fragger_hndl",
|
|
|
|
FT_UINT16, BASE_HEX, NULL, 0x0,
|
|
|
|
"", HFILL }},
|
|
|
|
{ &hf_lip_echo,
|
|
|
|
{ "Large Internet Packet Echo", "ncp.lip_echo",
|
|
|
|
FT_STRING, BASE_NONE, NULL, 0x0,
|
|
|
|
"", HFILL }},
|
2004-06-15 09:30:54 +00:00
|
|
|
{ &hf_ncp_burst_command,
|
|
|
|
{ "Burst Command", "ncp.burst_command",
|
|
|
|
FT_UINT32, BASE_HEX, VALS(burst_command), 0x0,
|
|
|
|
"Packet Burst Command", HFILL }},
|
|
|
|
{ &hf_ncp_burst_file_handle,
|
|
|
|
{ "Burst File Handle", "ncp.file_handle",
|
|
|
|
FT_UINT32, BASE_HEX, NULL, 0x0,
|
|
|
|
"Packet Burst File Handle", HFILL }},
|
|
|
|
{ &hf_ncp_burst_reserved,
|
|
|
|
{ "Reserved", "ncp.burst_reserved",
|
|
|
|
FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
|
2002-09-22 15:46:42 +00:00
|
|
|
|
1999-10-17 14:09:35 +00:00
|
|
|
};
|
1999-11-16 11:44:20 +00:00
|
|
|
static gint *ett[] = {
|
|
|
|
&ett_ncp,
|
2002-05-15 06:50:33 +00:00
|
|
|
&ett_ncp_system_flags,
|
2002-09-22 15:46:42 +00:00
|
|
|
&ett_nds,
|
2003-08-25 22:14:07 +00:00
|
|
|
&ett_nds_segments,
|
|
|
|
&ett_nds_segment,
|
1999-11-16 11:44:20 +00:00
|
|
|
};
|
2002-05-11 18:58:02 +00:00
|
|
|
module_t *ncp_module;
|
1999-10-17 14:09:35 +00:00
|
|
|
|
2001-01-03 06:56:03 +00:00
|
|
|
proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
|
1999-10-17 14:09:35 +00:00
|
|
|
proto_register_field_array(proto_ncp, hf, array_length(hf));
|
1999-11-16 11:44:20 +00:00
|
|
|
proto_register_subtree_array(ett, array_length(ett));
|
2002-05-11 18:58:02 +00:00
|
|
|
|
2002-05-25 01:05:56 +00:00
|
|
|
ncp_module = prefs_register_protocol(proto_ncp, NULL);
|
2002-05-11 18:58:02 +00:00
|
|
|
prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
|
2002-05-25 01:05:56 +00:00
|
|
|
prefs_register_bool_preference(ncp_module, "desegment",
|
2004-08-21 09:02:52 +00:00
|
|
|
"Reassemble NCP-over-TCP messages spanning multiple TCP segments",
|
|
|
|
"Whether the NCP dissector should reassemble messages spanning multiple TCP segments."
|
|
|
|
" To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
|
2002-05-25 01:05:56 +00:00
|
|
|
&ncp_desegment);
|
2003-08-25 22:14:07 +00:00
|
|
|
prefs_register_bool_preference(ncp_module, "defragment_nds",
|
2004-08-21 09:02:52 +00:00
|
|
|
"Reassemble fragmented NDS messages spanning multiple packets",
|
|
|
|
"Whether the NCP dissector should defragment NDS messages spanning multiple packets.",
|
2003-08-25 22:14:07 +00:00
|
|
|
&nds_defragment);
|
2004-02-18 06:01:47 +00:00
|
|
|
register_init_routine(&mncp_init_protocol);
|
|
|
|
register_postseq_cleanup_routine(&mncp_postseq_cleanup);
|
1999-07-29 05:47:07 +00:00
|
|
|
}
|
2000-04-08 07:07:42 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
proto_reg_handoff_ncp(void)
|
|
|
|
{
|
2001-12-03 04:00:26 +00:00
|
|
|
dissector_handle_t ncp_handle;
|
2002-05-25 01:05:56 +00:00
|
|
|
dissector_handle_t ncp_tcp_handle;
|
2001-12-03 04:00:26 +00:00
|
|
|
|
|
|
|
ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
|
2002-05-25 01:05:56 +00:00
|
|
|
ncp_tcp_handle = create_dissector_handle(dissect_ncp_tcp, proto_ncp);
|
|
|
|
dissector_add("tcp.port", TCP_PORT_NCP, ncp_tcp_handle);
|
2001-12-03 04:00:26 +00:00
|
|
|
dissector_add("udp.port", UDP_PORT_NCP, ncp_handle);
|
|
|
|
dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
|
|
|
|
dissector_add("ipx.socket", IPX_SOCKET_NCP, ncp_handle);
|
2002-05-15 21:17:21 +00:00
|
|
|
|
|
|
|
data_handle = find_dissector("data");
|
2000-04-08 07:07:42 +00:00
|
|
|
}
|