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.58 2002/05/15 06:50:33 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>
41 #include <epan/packet.h>
42 #include <epan/conversation.h>
44 #include "packet-ipx.h"
45 #include "packet-ncp-int.h"
48 static int hf_ncp_ip_ver = -1;
49 static int hf_ncp_ip_length = -1;
50 static int hf_ncp_ip_rplybufsize = -1;
51 static int hf_ncp_ip_sig = -1;
52 static int hf_ncp_type = -1;
53 static int hf_ncp_seq = -1;
54 static int hf_ncp_connection = -1;
55 static int hf_ncp_task = -1;
56 static int hf_ncp_stream_type = -1;
57 static int hf_ncp_system_flags = -1;
58 static int hf_ncp_system_flags_abt = -1;
59 static int hf_ncp_system_flags_eob = -1;
60 static int hf_ncp_system_flags_sys = -1;
61 static int hf_ncp_src_connection = -1;
62 static int hf_ncp_dst_connection = -1;
63 static int hf_ncp_packet_seqno = -1;
64 static int hf_ncp_delay_time = -1;
65 static int hf_ncp_burst_seqno = -1;
66 static int hf_ncp_ack_seqno = -1;
67 static int hf_ncp_burst_len = -1;
68 static int hf_ncp_data_offset = -1;
69 static int hf_ncp_data_bytes = -1;
70 static int hf_ncp_missing_fraglist_count = -1;
71 static int hf_ncp_missing_data_offset = -1;
72 static int hf_ncp_missing_data_count = -1;
75 static gint ett_ncp_system_flags = -1;
77 #define TCP_PORT_NCP 524
78 #define UDP_PORT_NCP 524
80 #define NCP_RQST_HDR_LENGTH 7
81 #define NCP_RPLY_HDR_LENGTH 8
84 gint ncp_equal (gconstpointer v, gconstpointer v2);
85 guint ncp_hash (gconstpointer v);
87 /* These are the header structures to handle NCP over IP */
88 #define NCPIP_RQST 0x446d6454 /* "DmdT" */
89 #define NCPIP_RPLY 0x744e6350 /* "tNcP" */
91 struct ncp_ip_header {
96 /* This header only appears on NCP over IP request packets */
102 static const value_string ncp_ip_signature[] = {
103 { NCPIP_RQST, "Demand Transport (Request)" },
104 { NCPIP_RPLY, "Transport is NCP (Reply)" },
108 /* The information in this module comes from:
109 NetWare LAN Analysis, Second Edition
110 Laura A. Chappell and Dan E. Hakes
111 (c) 1994 Novell, Inc.
112 Novell Press, San Jose.
115 And from the ncpfs source code by Volker Lendecke
118 Programmer's Guide to the NetWare Core Protocol
119 Steve Conner & Diane Conner
120 (c) 1996 by Steve Conner & Diane Conner
121 Published by Annabooks, San Diego, California
127 * Every NCP packet has this common header (except for burst packets).
129 struct ncp_common_header {
134 guint8 conn_high; /* type=0x5555 doesn't have this */
138 static value_string ncp_type_vals[] = {
139 { 0x1111, "Create a service connection" },
140 { 0x2222, "Service request" },
141 { 0x3333, "Service reply" },
142 { 0x5555, "Destroy service connection" },
143 { 0x7777, "Burst mode transfer" },
144 { 0x9999, "Request being processed" },
150 * Burst packet system flags.
152 #define ABT 0x04 /* Abort request */
153 #define EOB 0x10 /* End of burst */
154 #define SYS 0x80 /* System packet */
157 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
159 proto_tree *ncp_tree = NULL;
161 struct ncp_ip_header ncpiph;
162 struct ncp_ip_rqhdr ncpiphrq;
163 struct ncp_common_header header;
164 guint16 nw_connection;
166 char flags_str[1+3+1+3+1+3+1+1];
168 proto_tree *flags_tree = NULL;
170 guint16 missing_fraglist_count;
176 if (check_col(pinfo->cinfo, COL_PROTOCOL))
177 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
178 if (check_col(pinfo->cinfo, COL_INFO))
179 col_clear(pinfo->cinfo, COL_INFO);
181 if ( pinfo->ptype == PT_TCP || pinfo->ptype == PT_UDP ) {
182 ncpiph.signature = tvb_get_ntohl(tvb, 0);
183 ncpiph.length = tvb_get_ntohl(tvb, 4);
185 if ( ncpiph.signature == NCPIP_RQST ) {
186 ncpiphrq.version = tvb_get_ntohl(tvb, hdr_offset);
188 ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, hdr_offset);
193 /* Record the offset where the NCP common header starts */
194 commhdr = hdr_offset;
196 header.type = tvb_get_ntohs(tvb, commhdr);
197 header.sequence = tvb_get_guint8(tvb, commhdr+2);
198 header.conn_low = tvb_get_guint8(tvb, commhdr+3);
199 header.conn_high = tvb_get_guint8(tvb, commhdr+5);
201 if (check_col(pinfo->cinfo, COL_INFO)) {
202 col_add_fstr(pinfo->cinfo, COL_INFO,
204 val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
207 nw_connection = (header.conn_high << 16) + header.conn_low;
210 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE);
211 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
213 if ( pinfo->ptype == PT_TCP || pinfo->ptype == PT_UDP ) {
214 proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature);
215 proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length);
216 if ( ncpiph.signature == NCPIP_RQST ) {
217 proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version);
218 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize);
221 proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr + 0, 2, header.type);
225 switch (header.type) {
227 case 0x1111: /* "Allocate Slot Request"? */
228 case 0x2222: /* Server NCP Request */
229 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
230 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
231 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
232 next_tvb = tvb_new_subset( tvb, hdr_offset, -1, -1 );
233 dissect_ncp_request(next_tvb, pinfo, nw_connection,
234 header.sequence, header.type, ncp_tree);
237 case 0x3333: /* Server NCP Reply */
238 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
239 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
240 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
241 next_tvb = tvb_new_subset( tvb, hdr_offset, -1, -1 );
242 dissect_ncp_reply(next_tvb, pinfo, nw_connection,
243 header.sequence, ncp_tree);
246 case 0x5555: /* Deallocate Slot Request */
247 case 0x9999: /* Positive Acknowledgement */
248 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
249 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
250 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
252 proto_tree_add_text(ncp_tree, tvb, commhdr + 0, 2, "Type 0x%04x not supported yet", header.type);
257 case 0x7777: /* Packet Burst Packet */
259 * XXX - we should keep track of whether there's a burst
260 * outstanding on a connection and, if not, treat the
261 * beginning of the data as a burst header.
263 * The burst header contains:
265 * 4 bytes of little-endian function number:
266 * 1 = read, 2 = write;
268 * 4 bytes of file handle;
272 * 4 bytes of big-endian file offset;
274 * 4 bytes of big-endian byte count.
276 * The data follows for a burst write operation.
278 * The first packet of a burst read reply contains:
280 * 4 bytes of little-endian result code:
286 * 4 bytes of returned byte count (big-endian?).
290 * Each burst of a write request is responded to with a
291 * burst packet with a 2-byte little-endian result code:
293 * 0: Write successful
296 flags = tvb_get_guint8(tvb, commhdr + 2);
297 strcpy(flags_str, "");
300 strcat(flags_str, sep);
301 strcat(flags_str, "ABT");
305 strcat(flags_str, sep);
306 strcat(flags_str, "EOB");
310 strcat(flags_str, sep);
311 strcat(flags_str, "SYS");
313 if (flags_str[0] != '\0')
314 strcat(flags_str, ")");
315 ti = proto_tree_add_uint_format(ncp_tree, hf_ncp_system_flags,
316 tvb, commhdr + 2, 1, flags, "Flags: 0x%04x%s", flags,
318 flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
319 proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
320 tvb, commhdr + 2, 1, FALSE);
321 proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
322 tvb, commhdr + 2, 1, FALSE);
323 proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
324 tvb, commhdr + 2, 1, FALSE);
326 proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
327 tvb, commhdr + 3, 1, FALSE);
328 proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
329 tvb, commhdr + 4, 4, FALSE);
330 proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
331 tvb, commhdr + 8, 4, FALSE);
332 proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
333 tvb, commhdr + 12, 4, FALSE);
334 proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
335 tvb, commhdr + 16, 4, FALSE);
336 proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
337 tvb, commhdr + 20, 2, FALSE);
338 proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
339 tvb, commhdr + 22, 2, FALSE);
340 proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
341 tvb, commhdr + 24, 4, FALSE);
342 proto_tree_add_item(ncp_tree, hf_ncp_data_offset,
343 tvb, commhdr + 28, 4, FALSE);
344 data_len = tvb_get_ntohs(tvb, commhdr + 32);
345 proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
346 tvb, commhdr + 32, 2, data_len);
347 missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
348 proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
349 tvb, commhdr + 34, 2, FALSE);
352 * System packet; show missing fragments if there
355 offset = commhdr + 36;
356 while (missing_fraglist_count != 0) {
357 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
358 tvb, offset, 4, FALSE);
359 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
360 tvb, offset, 2, FALSE);
361 missing_fraglist_count--;
365 proto_tree_add_text(ncp_tree, tvb, commhdr + 36,
372 /* The value_string for hf_ncp_type already indicates that this type is unknown.
373 * Just return and do no more parsing. */
374 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
375 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
376 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
384 proto_register_ncp(void)
387 static hf_register_info hf[] = {
389 { "NCP over IP signature", "ncp.ip.signature",
390 FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
393 { "NCP over IP length", "ncp.ip.length",
394 FT_UINT32, BASE_HEX, NULL, 0x0,
397 { "NCP over IP Version", "ncp.ip.version",
398 FT_UINT32, BASE_DEC, NULL, 0x0,
400 { &hf_ncp_ip_rplybufsize,
401 { "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize",
402 FT_UINT32, BASE_DEC, NULL, 0x0,
405 { "Type", "ncp.type",
406 FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
407 "NCP message type", HFILL }},
409 { "Sequence Number", "ncp.seq",
410 FT_UINT8, BASE_DEC, NULL, 0x0,
412 { &hf_ncp_connection,
413 { "Connection Number", "ncp.connection",
414 FT_UINT16, BASE_DEC, NULL, 0x0,
417 { "Task Number", "ncp.task",
418 FT_UINT8, BASE_DEC, NULL, 0x0,
420 { &hf_ncp_stream_type,
421 { "Stream Type", "ncp.stream_type",
422 FT_UINT8, BASE_HEX, NULL, 0x0,
423 "Type of burst", HFILL }},
424 { &hf_ncp_system_flags,
425 { "System Flags", "ncp.system_flags",
426 FT_UINT8, BASE_HEX, NULL, 0x0,
428 { &hf_ncp_system_flags_abt,
429 { "ABT", "ncp.system_flags.abt",
430 FT_BOOLEAN, 8, NULL, ABT,
431 "Is this an abort request?", HFILL }},
432 { &hf_ncp_system_flags_eob,
433 { "EOB", "ncp.system_flags.eob",
434 FT_BOOLEAN, 8, NULL, EOB,
435 "Is this the last packet of the burst?", HFILL }},
436 { &hf_ncp_system_flags_sys,
437 { "SYS", "ncp.system_flags.sys",
438 FT_BOOLEAN, 8, NULL, SYS,
439 "Is this a system packet?", HFILL }},
440 { &hf_ncp_src_connection,
441 { "Source Connection ID", "ncp.src_connection",
442 FT_UINT32, BASE_DEC, NULL, 0x0,
443 "The workstation's connection identification number", HFILL }},
444 { &hf_ncp_dst_connection,
445 { "Destination Connection ID", "ncp.dst_connection",
446 FT_UINT32, BASE_DEC, NULL, 0x0,
447 "The server's connection identification number", HFILL }},
448 { &hf_ncp_packet_seqno,
449 { "Packet Sequence Number", "ncp.packet_seqno",
450 FT_UINT32, BASE_DEC, NULL, 0x0,
451 "Sequence number of this packet in a burst", HFILL }},
452 { &hf_ncp_delay_time,
453 { "Delay Time", "ncp.delay_time", /* in 100 us increments */
454 FT_UINT32, BASE_DEC, NULL, 0x0,
455 "Delay time between consecutive packet sends (100 us increments)", HFILL }},
456 { &hf_ncp_burst_seqno,
457 { "Burst Sequence Number", "ncp.burst_seqno",
458 FT_UINT16, BASE_DEC, NULL, 0x0,
459 "Sequence number of this packet in the burst", HFILL }},
461 { "ACK Sequence Number", "ncp.ack_seqno",
462 FT_UINT16, BASE_DEC, NULL, 0x0,
463 "Next expected burst sequence number", HFILL }},
465 { "Burst Length", "ncp.burst_len",
466 FT_UINT32, BASE_DEC, NULL, 0x0,
467 "Total length of data in this burst", HFILL }},
468 { &hf_ncp_data_offset,
469 { "Data Offset", "ncp.data_offset",
470 FT_UINT32, BASE_DEC, NULL, 0x0,
471 "Offset of this packet in the burst", HFILL }},
472 { &hf_ncp_data_bytes,
473 { "Data Bytes", "ncp.data_bytes",
474 FT_UINT16, BASE_DEC, NULL, 0x0,
475 "Number of data bytes in this packet", HFILL }},
476 { &hf_ncp_missing_fraglist_count,
477 { "Missing Fragment List Count", "ncp.missing_fraglist_count",
478 FT_UINT16, BASE_DEC, NULL, 0x0,
479 "Number of missing fragments reported", HFILL }},
480 { &hf_ncp_missing_data_offset,
481 { "Missing Data Offset", "ncp.missing_data_offset",
482 FT_UINT32, BASE_DEC, NULL, 0x0,
483 "Offset of beginning of missing data", HFILL }},
484 { &hf_ncp_missing_data_count,
485 { "Missing Data Count", "ncp.missing_data_count",
486 FT_UINT16, BASE_DEC, NULL, 0x0,
487 "Number of bytes of missing data", HFILL }},
489 static gint *ett[] = {
491 &ett_ncp_system_flags,
493 module_t *ncp_module;
495 proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
496 proto_register_field_array(proto_ncp, hf, array_length(hf));
497 proto_register_subtree_array(ett, array_length(ett));
499 /* Register an obsolete configuration option for what used to be the
500 initial size of the NCP hash. */
501 ncp_module = prefs_register_protocol_obsolete(proto_ncp);
502 prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
506 proto_reg_handoff_ncp(void)
508 dissector_handle_t ncp_handle;
510 ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
511 dissector_add("tcp.port", TCP_PORT_NCP, ncp_handle);
512 dissector_add("udp.port", UDP_PORT_NCP, ncp_handle);
513 dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
514 dissector_add("ipx.socket", IPX_SOCKET_NCP, ncp_handle);