2 * Routines for NetWare Core Protocol
3 * Gilbert Ramirez <gram@alumni.rice.edu>
4 * Modified to allow NCP over TCP/IP decodes by James Coe <jammer@cin.net>
6 * $Id: packet-ncp.c,v 1.55 2002/01/24 09:20:49 guy Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 2000 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
35 #ifdef HAVE_NETINET_IN_H
36 # include <netinet/in.h>
40 #include <epan/packet.h>
41 #include <epan/conversation.h>
43 #include "packet-ipx.h"
44 #include "packet-ncp-int.h"
47 static int hf_ncp_ip_ver = -1;
48 static int hf_ncp_ip_length = -1;
49 static int hf_ncp_ip_rplybufsize = -1;
50 static int hf_ncp_ip_sig = -1;
51 static int hf_ncp_type = -1;
52 static int hf_ncp_seq = -1;
53 static int hf_ncp_connection = -1;
54 static int hf_ncp_task = -1;
56 static gint ett_ncp = -1;
58 #define TCP_PORT_NCP 524
59 #define UDP_PORT_NCP 524
61 #define NCP_RQST_HDR_LENGTH 7
62 #define NCP_RPLY_HDR_LENGTH 8
65 gint ncp_equal (gconstpointer v, gconstpointer v2);
66 guint ncp_hash (gconstpointer v);
68 static guint ncp_packet_init_count = 200;
70 /* These are the header structures to handle NCP over IP */
71 #define NCPIP_RQST 0x446d6454 /* "DmdT" */
72 #define NCPIP_RPLY 0x744e6350 /* "tNcP" */
74 struct ncp_ip_header {
79 /* This header only appears on NCP over IP request packets */
85 static const value_string ncp_ip_signature[] = {
86 { NCPIP_RQST, "Demand Transport (Request)" },
87 { NCPIP_RPLY, "Transport is NCP (Reply)" },
91 /* The information in this module comes from:
92 NetWare LAN Analysis, Second Edition
93 Laura A. Chappell and Dan E. Hakes
95 Novell Press, San Jose.
98 And from the ncpfs source code by Volker Lendecke
101 Programmer's Guide to the NetWare Core Protocol
102 Steve Conner & Diane Conner
103 (c) 1996 by Steve Conner & Diane Conner
104 Published by Annabooks, San Diego, California
109 /* Every NCP packet has this common header */
110 struct ncp_common_header {
115 guint8 conn_high; /* type=0x5555 doesn't have this */
119 static value_string ncp_type_vals[] = {
120 { 0x1111, "Create a service connection" },
121 { 0x2222, "Service request" },
122 { 0x3333, "Service reply" },
123 { 0x5555, "Destroy service connection" },
124 { 0x7777, "Burst mode transfer" },
125 { 0x9999, "Request being processed" },
130 /* NCP packets come in request/reply pairs. The request packets tell the type
131 * of NCP request and give a sequence ID. The response, unfortunately, only
132 * identifies itself via the sequence ID; you have to know what type of NCP
133 * request the request packet contained in order to successfully parse the NCP
134 * response. A global method for doing this does not exist in ethereal yet
135 * (NFS also requires it), so for now the NCP section will keep its own hash
136 * table keeping track of NCP packet types.
138 * We construct a conversation specified by the client and server
139 * addresses and the connection number; the key representing the unique
140 * NCP request then is composed of the pointer to the conversation
141 * structure, cast to a "guint" (which may throw away the upper 32
142 * bits of the pointer on a P64 platform, but the low-order 32 bits
143 * are more likely to differ between conversations than the upper 32 bits),
144 * and the sequence number.
146 * The value stored in the hash table is the ncp_request_val pointer. This
147 * struct tells us the NCP type and gives the ncp2222_record pointer, if
148 * ncp_type == 0x2222.
151 conversation_t *conversation;
156 static GHashTable *ncp_request_hash = NULL;
157 static GMemChunk *ncp_request_keys = NULL;
160 gint ncp_equal (gconstpointer v, gconstpointer v2)
162 ncp_request_key *val1 = (ncp_request_key*)v;
163 ncp_request_key *val2 = (ncp_request_key*)v2;
165 if (val1->conversation == val2->conversation &&
166 val1->nw_sequence == val2->nw_sequence ) {
172 guint ncp_hash (gconstpointer v)
174 ncp_request_key *ncp_key = (ncp_request_key*)v;
175 return GPOINTER_TO_UINT(ncp_key->conversation) + ncp_key->nw_sequence;
178 /* Initializes the hash table and the mem_chunk area each time a new
179 * file is loaded or re-loaded in ethereal */
181 ncp_init_protocol(void)
183 if (ncp_request_hash)
184 g_hash_table_destroy(ncp_request_hash);
185 if (ncp_request_keys)
186 g_mem_chunk_destroy(ncp_request_keys);
188 ncp_request_hash = g_hash_table_new(ncp_hash, ncp_equal);
189 ncp_request_keys = g_mem_chunk_new("ncp_request_keys",
190 sizeof(ncp_request_key),
191 ncp_packet_init_count * sizeof(ncp_request_key), G_ALLOC_AND_FREE);
194 /* After the sequential run, we don't need the ncp_request hash and keys
195 * anymore; the lookups have already been done and the vital info
196 * saved in the reply-packets' private_data in the frame_data struct. */
198 ncp_postseq_cleanup(void)
200 if (ncp_request_hash) {
201 g_hash_table_destroy(ncp_request_hash);
202 ncp_request_hash = NULL;
204 if (ncp_request_keys) {
205 g_mem_chunk_destroy(ncp_request_keys);
206 ncp_request_keys = NULL;
211 ncp_hash_insert(conversation_t *conversation, guint8 nw_sequence,
212 const ncp_record *ncp_rec)
214 ncp_request_key *request_key;
216 /* Now remember the request, so we can find it if we later
218 request_key = g_mem_chunk_alloc(ncp_request_keys);
219 request_key->conversation = conversation;
220 request_key->nw_sequence = nw_sequence;
222 g_hash_table_insert(ncp_request_hash, request_key, (void*)ncp_rec);
225 /* Returns the ncp_rec*, or NULL if not found. */
227 ncp_hash_lookup(conversation_t *conversation, guint8 nw_sequence)
229 ncp_request_key request_key;
231 request_key.conversation = conversation;
232 request_key.nw_sequence = nw_sequence;
234 return g_hash_table_lookup(ncp_request_hash, &request_key);
238 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
240 proto_tree *ncp_tree = NULL;
242 struct ncp_ip_header ncpiph;
243 struct ncp_ip_rqhdr ncpiphrq;
244 struct ncp_common_header header;
245 guint16 nw_connection;
250 if (check_col(pinfo->cinfo, COL_PROTOCOL))
251 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
252 if (check_col(pinfo->cinfo, COL_INFO))
253 col_clear(pinfo->cinfo, COL_INFO);
255 if ( pinfo->ptype == PT_TCP || pinfo->ptype == PT_UDP ) {
256 ncpiph.signature = tvb_get_ntohl(tvb, 0);
257 ncpiph.length = tvb_get_ntohl(tvb, 4);
259 if ( ncpiph.signature == NCPIP_RQST ) {
260 ncpiphrq.version = tvb_get_ntohl(tvb, hdr_offset);
262 ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, hdr_offset);
267 /* Record the offset where the NCP common header starts */
268 commhdr = hdr_offset;
270 header.type = tvb_get_ntohs(tvb, commhdr);
271 header.sequence = tvb_get_guint8(tvb, commhdr+2);
272 header.conn_low = tvb_get_guint8(tvb, commhdr+3);
273 header.conn_high = tvb_get_guint8(tvb, commhdr+5);
275 nw_connection = (header.conn_high << 16) + header.conn_low;
278 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE);
279 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
281 if ( pinfo->ptype == PT_TCP || pinfo->ptype == PT_UDP ) {
282 proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature);
283 proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length);
284 if ( ncpiph.signature == NCPIP_RQST ) {
285 proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version);
286 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize);
289 proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr + 0, 2, header.type);
290 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
291 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
292 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
296 if (header.type == 0x1111 || header.type == 0x2222) {
297 next_tvb = tvb_new_subset( tvb, hdr_offset, -1, -1 );
298 dissect_ncp_request(next_tvb, pinfo, nw_connection,
299 header.sequence, header.type, ncp_tree, tree);
301 else if (header.type == 0x3333) {
302 next_tvb = tvb_new_subset( tvb, hdr_offset, -1, -1 );
303 dissect_ncp_reply(next_tvb, pinfo, nw_connection,
304 header.sequence, ncp_tree, tree);
306 else if ( header.type == 0x5555 ||
307 header.type == 0x7777 ||
308 header.type == 0x9999 ) {
310 if (check_col(pinfo->cinfo, COL_INFO)) {
311 col_add_fstr(pinfo->cinfo, COL_INFO, "Type 0x%04x", header.type);
315 proto_tree_add_text(ncp_tree, tvb, commhdr + 0, 2, "Type 0x%04x not supported yet", header.type);
321 /* The value_string for hf_ncp_type already indicates that this type is unknown.
322 * Just return and do no more parsing. */
330 proto_register_ncp(void)
333 static hf_register_info hf[] = {
335 { "NCP over IP signature", "ncp.ip.signature",
336 FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
339 { "NCP over IP length", "ncp.ip.length",
340 FT_UINT32, BASE_HEX, NULL, 0x0,
343 { "NCP over IP Version", "ncp.ip.version",
344 FT_UINT32, BASE_DEC, NULL, 0x0,
346 { &hf_ncp_ip_rplybufsize,
347 { "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize",
348 FT_UINT32, BASE_DEC, NULL, 0x0,
351 { "Type", "ncp.type",
352 FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
353 "NCP message type", HFILL }},
355 { "Sequence Number", "ncp.seq",
356 FT_UINT8, BASE_DEC, NULL, 0x0,
358 { &hf_ncp_connection,
359 { "Connection Number", "ncp.connection",
360 FT_UINT16, BASE_DEC, NULL, 0x0,
363 { "Task Number", "ncp.task",
364 FT_UINT8, BASE_DEC, NULL, 0x0,
367 static gint *ett[] = {
370 module_t *ncp_module;
372 proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
373 proto_register_field_array(proto_ncp, hf, array_length(hf));
374 proto_register_subtree_array(ett, array_length(ett));
375 register_init_routine(&ncp_init_protocol);
376 register_postseq_cleanup_routine(&ncp_postseq_cleanup);
378 /* Register a configuration option for initial size of NCP hash */
379 ncp_module = prefs_register_protocol(proto_ncp, NULL);
380 prefs_register_uint_preference(ncp_module, "initial_hash_size",
382 "Number of entries initially allocated for NCP hash",
383 10, &ncp_packet_init_count);
387 proto_reg_handoff_ncp(void)
389 dissector_handle_t ncp_handle;
391 ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
392 dissector_add("tcp.port", TCP_PORT_NCP, ncp_handle);
393 dissector_add("udp.port", UDP_PORT_NCP, ncp_handle);
394 dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
395 dissector_add("ipx.socket", IPX_SOCKET_NCP, ncp_handle);