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>
5 * Modified to decode server op-lock
6 * & NDS packets by Greg Morris <gmorris@novell.com>
8 * $Id: packet-ncp.c,v 1.72 2002/10/11 19:36:13 guy Exp $
10 * Ethereal - Network traffic analyzer
11 * By Gerald Combs <gerald@ethereal.com>
12 * Copyright 2000 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
37 #ifdef HAVE_NETINET_IN_H
38 # include <netinet/in.h>
43 #include <epan/packet.h>
44 #include <epan/conversation.h>
46 #include "packet-ipx.h"
47 #include "packet-tcp.h"
48 #include "packet-ncp-int.h"
51 static int hf_ncp_ip_ver = -1;
52 static int hf_ncp_ip_length = -1;
53 static int hf_ncp_ip_rplybufsize = -1;
54 static int hf_ncp_ip_sig = -1;
55 static int hf_ncp_ip_packetsig = -1;
56 static int hf_ncp_type = -1;
57 static int hf_ncp_seq = -1;
58 static int hf_ncp_connection = -1;
59 static int hf_ncp_task = -1;
60 static int hf_ncp_stream_type = -1;
61 static int hf_ncp_system_flags = -1;
62 static int hf_ncp_system_flags_abt = -1;
63 static int hf_ncp_system_flags_eob = -1;
64 static int hf_ncp_system_flags_sys = -1;
65 static int hf_ncp_src_connection = -1;
66 static int hf_ncp_dst_connection = -1;
67 static int hf_ncp_packet_seqno = -1;
68 static int hf_ncp_delay_time = -1;
69 static int hf_ncp_burst_seqno = -1;
70 static int hf_ncp_ack_seqno = -1;
71 static int hf_ncp_burst_len = -1;
72 static int hf_ncp_data_offset = -1;
73 static int hf_ncp_data_bytes = -1;
74 static int hf_ncp_missing_fraglist_count = -1;
75 static int hf_ncp_missing_data_offset = -1;
76 static int hf_ncp_missing_data_count = -1;
77 static int hf_ncp_oplock_flag = -1;
78 static int hf_ncp_oplock_handle = -1;
79 static int hf_ncp_completion_code = -1;
80 static int hf_ncp_connection_status = -1;
81 static int hf_ncp_slot = -1;
82 static int hf_ncp_control_code = -1;
83 static int hf_ncp_fragment_handle = -1;
84 static int hf_lip_echo = -1;
85 /*static int hf_ping_version = -1;*/
89 static gint ett_ncp_system_flags = -1;
91 /* desegmentation of NCP over TCP */
92 static gboolean ncp_desegment = TRUE;
93 /*static int ncp_nds_true = FALSE;*/
95 static dissector_handle_t data_handle;
97 #define TCP_PORT_NCP 524
98 #define UDP_PORT_NCP 524
100 #define NCP_RQST_HDR_LENGTH 7
101 #define NCP_RPLY_HDR_LENGTH 8
105 gint ncp_equal (gconstpointer v, gconstpointer v2);
106 guint ncp_hash (gconstpointer v);
108 /* These are the header structures to handle NCP over IP */
109 #define NCPIP_RQST 0x446d6454 /* "DmdT" */
110 #define NCPIP_RPLY 0x744e6350 /* "tNcP" */
112 struct ncp_ip_header {
117 /* This header only appears on NCP over IP request packets */
118 struct ncp_ip_rqhdr {
123 static const value_string ncp_ip_signature[] = {
124 { NCPIP_RQST, "Demand Transport (Request)" },
125 { NCPIP_RPLY, "Transport is NCP (Reply)" },
129 /* The information in this module comes from:
130 NetWare LAN Analysis, Second Edition
131 Laura A. Chappell and Dan E. Hakes
132 (c) 1994 Novell, Inc.
133 Novell Press, San Jose.
136 And from the ncpfs source code by Volker Lendecke
139 Programmer's Guide to the NetWare Core Protocol
140 Steve Conner & Diane Conner
141 (c) 1996 by Steve Conner & Diane Conner
142 Published by Annabooks, San Diego, California
146 http:developer.novell.com
152 * Every NCP packet has this common header (except for burst packets).
154 struct ncp_common_header {
159 guint8 conn_high; /* type=0x5555 doesn't have this */
163 static value_string ncp_type_vals[] = {
164 { NCP_ALLOCATE_SLOT, "Create a service connection" },
165 { NCP_SERVICE_REQUEST, "Service request" },
166 { NCP_SERVICE_REPLY, "Service reply" },
167 { NCP_WATCHDOG, "Watchdog" },
168 { NCP_DEALLOCATE_SLOT, "Destroy service connection" },
169 { NCP_BROADCAST_SLOT, "Server Broadcast" },
170 { NCP_BURST_MODE_XFER, "Burst mode transfer" },
171 { NCP_POSITIVE_ACK, "Request being processed" },
172 { NCP_LIP_ECHO, "Large Internet Packet Echo" },
178 * Burst packet system flags.
180 #define ABT 0x04 /* Abort request */
181 #define EOB 0x10 /* End of burst */
182 #define SYS 0x80 /* System packet */
185 dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
188 proto_tree *ncp_tree = NULL;
190 struct ncp_ip_header ncpiph;
191 struct ncp_ip_rqhdr ncpiphrq;
192 gboolean is_signed = FALSE;
193 struct ncp_common_header header;
194 guint16 nw_connection;
196 char flags_str[1+3+1+3+1+3+1+1];
198 proto_tree *flags_tree = NULL;
199 guint16 data_len = 0;
200 guint16 missing_fraglist_count = 0;
204 gint length_remaining;
209 if (check_col(pinfo->cinfo, COL_PROTOCOL))
210 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
211 if (check_col(pinfo->cinfo, COL_INFO))
212 col_clear(pinfo->cinfo, COL_INFO);
215 ncpiph.signature = tvb_get_ntohl(tvb, 0);
216 ncpiph.length = tvb_get_ntohl(tvb, 4);
218 if ( ncpiph.signature == NCPIP_RQST ) {
219 ncpiphrq.version = tvb_get_ntohl(tvb, hdr_offset);
221 ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, hdr_offset);
224 if (ncpiph.length & 0x80000000) {
226 * This appears to indicate that this packet
227 * is signed; the signature is 8 bytes long.
229 * XXX - that bit does *not* appear to be set
230 * in signed replies, and we can't dissect the
231 * reply enough to find the matching request
232 * without knowing whether the reply is
235 * XXX - what about NCP-over-IPX signed
240 ncpiph.length &= 0x7fffffff;
244 /* Record the offset where the NCP common header starts */
245 commhdr = hdr_offset;
247 header.type = tvb_get_ntohs(tvb, commhdr);
248 header.sequence = tvb_get_guint8(tvb, commhdr+2);
249 header.conn_low = tvb_get_guint8(tvb, commhdr+3);
250 header.conn_high = tvb_get_guint8(tvb, commhdr+5);
252 if (check_col(pinfo->cinfo, COL_INFO)) {
253 col_add_fstr(pinfo->cinfo, COL_INFO,
255 val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
259 nw_connection = (header.conn_high << 16) + header.conn_low;
262 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE);
263 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
266 proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature);
267 proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length);
268 if (ncpiph.signature == NCPIP_RQST) {
269 proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version);
270 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize);
273 proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 16, 8, FALSE);
275 proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr + 0, 2, header.type);
280 * Process the packet-type-specific header.
282 switch (header.type) {
284 case NCP_BROADCAST_SLOT: /* Server Broadcast */
285 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
286 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
287 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
288 proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, FALSE);
289 proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, FALSE);
292 case NCP_LIP_ECHO: /* Lip Echo Packet */
293 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 2, FALSE);
296 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
298 * XXX - we should keep track of whether there's a burst
299 * outstanding on a connection and, if not, treat the
300 * beginning of the data as a burst header.
302 * The burst header contains:
304 * 4 bytes of little-endian function number:
305 * 1 = read, 2 = write;
307 * 4 bytes of file handle;
311 * 4 bytes of big-endian file offset;
313 * 4 bytes of big-endian byte count.
315 * The data follows for a burst write operation.
317 * The first packet of a burst read reply contains:
319 * 4 bytes of little-endian result code:
325 * 4 bytes of returned byte count (big-endian?).
329 * Each burst of a write request is responded to with a
330 * burst packet with a 2-byte little-endian result code:
332 * 0: Write successful
335 flags = tvb_get_guint8(tvb, commhdr + 2);
336 strcpy(flags_str, "");
339 strcat(flags_str, sep);
340 strcat(flags_str, "ABT");
344 strcat(flags_str, sep);
345 strcat(flags_str, "EOB");
349 strcat(flags_str, sep);
350 strcat(flags_str, "SYS");
352 if (flags_str[0] != '\0')
353 strcat(flags_str, ")");
354 ti = proto_tree_add_uint_format(ncp_tree, hf_ncp_system_flags,
355 tvb, commhdr + 2, 1, flags, "Flags: 0x%04x%s", flags,
357 flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
358 proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
359 tvb, commhdr + 2, 1, FALSE);
360 proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
361 tvb, commhdr + 2, 1, FALSE);
362 proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
363 tvb, commhdr + 2, 1, FALSE);
365 proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
366 tvb, commhdr + 3, 1, FALSE);
367 proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
368 tvb, commhdr + 4, 4, FALSE);
369 proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
370 tvb, commhdr + 8, 4, FALSE);
371 proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
372 tvb, commhdr + 12, 4, FALSE);
373 proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
374 tvb, commhdr + 16, 4, FALSE);
375 proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
376 tvb, commhdr + 20, 2, FALSE);
377 proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
378 tvb, commhdr + 22, 2, FALSE);
379 proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
380 tvb, commhdr + 24, 4, FALSE);
381 proto_tree_add_item(ncp_tree, hf_ncp_data_offset,
382 tvb, commhdr + 28, 4, FALSE);
383 data_len = tvb_get_ntohs(tvb, commhdr + 32);
384 proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
385 tvb, commhdr + 32, 2, data_len);
386 missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
387 proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
388 tvb, commhdr + 34, 2, FALSE);
391 case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
392 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
393 if (length_remaining > 4) {
394 testvar = tvb_get_ntohl(tvb, commhdr+4);
395 if (testvar == 0x4c495020) {
396 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr+4, 13, FALSE);
400 /* otherwise fall through */
402 case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
403 case NCP_SERVICE_REQUEST: /* Server NCP Request */
404 case NCP_SERVICE_REPLY: /* Server NCP Reply */
405 case NCP_WATCHDOG: /* Watchdog Packet */
406 case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
408 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
409 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
410 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
415 * Process the packet body.
417 switch (header.type) {
419 case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
420 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
421 if (length_remaining > 4) {
422 testvar = tvb_get_ntohl(tvb, commhdr+4);
423 if (testvar == 0x4c495020) {
424 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
430 case NCP_SERVICE_REQUEST: /* Server NCP Request */
431 case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
432 case NCP_BROADCAST_SLOT: /* Server Broadcast Packet */
433 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
434 if (tvb_get_guint8(tvb, commhdr+6) == 0x68) {
435 subfunction = tvb_get_guint8(tvb, commhdr+7);
436 switch (subfunction) {
438 case 0x02: /* NDS Frag Packet to decode */
439 dissect_nds_request(next_tvb, pinfo,
440 nw_connection, header.sequence,
441 header.type, ncp_tree);
444 case 0x01: /* NDS Ping */
445 dissect_ping_req(next_tvb, pinfo,
446 nw_connection, header.sequence,
447 header.type, ncp_tree);
451 dissect_ncp_request(next_tvb, pinfo,
452 nw_connection, header.sequence,
453 header.type, ncp_tree);
457 dissect_ncp_request(next_tvb, pinfo, nw_connection,
458 header.sequence, header.type, ncp_tree);
462 case NCP_SERVICE_REPLY: /* Server NCP Reply */
463 case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
464 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
465 dissect_ncp_reply(next_tvb, pinfo, nw_connection,
466 header.sequence, header.type, ncp_tree);
469 case NCP_WATCHDOG: /* Watchdog Packet */
471 * XXX - should the completion code be interpreted as
472 * it is in "packet-ncp2222.inc"? If so, this
473 * packet should be handled by "dissect_ncp_reply()".
475 proto_tree_add_item(ncp_tree, hf_ncp_completion_code,
476 tvb, commhdr + 6, 1, TRUE);
477 proto_tree_add_item(ncp_tree, hf_ncp_connection_status,
478 tvb, commhdr + 7, 1, TRUE);
479 proto_tree_add_item(ncp_tree, hf_ncp_slot,
480 tvb, commhdr + 8, 1, TRUE);
481 proto_tree_add_item(ncp_tree, hf_ncp_control_code,
482 tvb, commhdr + 9, 1, TRUE);
484 * Display the rest of the packet as data.
486 if (tvb_offset_exists(tvb, commhdr + 10)) {
487 call_dissector(data_handle,
488 tvb_new_subset(tvb, commhdr + 10, -1, -1),
493 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
496 * System packet; show missing fragments if there
499 offset = commhdr + 36;
500 while (missing_fraglist_count != 0) {
501 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
502 tvb, offset, 4, FALSE);
503 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
504 tvb, offset, 2, FALSE);
505 missing_fraglist_count--;
509 * XXX - do this by using -1 and -1 as the length
510 * arguments to "tvb_new_subset()" and then calling
511 * "tvb_set_reported_length()"? That'll throw an
512 * exception if "data_len" goes past the reported
513 * length of the packet, but that's arguably a
514 * feature in this case.
516 length_remaining = tvb_length_remaining(tvb, commhdr + 36);
517 if (length_remaining > data_len)
518 length_remaining = data_len;
520 call_dissector(data_handle,
521 tvb_new_subset(tvb, commhdr + 36,
522 length_remaining, data_len),
528 case NCP_LIP_ECHO: /* LIP Echo Packet */
529 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
535 proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1,
536 "%s packets not supported yet",
537 val_to_str(header.type, ncp_type_vals,
538 "Unknown type (0x%04x)"));
545 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
547 dissect_ncp_common(tvb, pinfo, tree, FALSE);
551 get_ncp_pdu_len(tvbuff_t *tvb, int offset)
556 * Check the NCP-over-TCP header signature, to make sure it's there.
557 * If it's not there, we cannot trust the next 4 bytes to be a
558 * packet length+"has signature" flag, so we just say the length is
559 * "what remains in the packet".
561 signature = tvb_get_ntohl(tvb, offset);
562 if (signature != NCPIP_RQST && signature != NCPIP_RPLY)
563 return tvb_length_remaining(tvb, offset);
566 * Get the length of the NCP-over-TCP packet. Strip off the "has
570 return tvb_get_ntohl(tvb, offset + 4) & 0x7fffffff;
574 dissect_ncp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
576 dissect_ncp_common(tvb, pinfo, tree, TRUE);
580 dissect_ncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
582 tcp_dissect_pdus(tvb, pinfo, tree, ncp_desegment, 8, get_ncp_pdu_len,
583 dissect_ncp_tcp_pdu);
587 proto_register_ncp(void)
590 static hf_register_info hf[] = {
592 { "NCP over IP signature", "ncp.ip.signature",
593 FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
596 { "NCP over IP length", "ncp.ip.length",
597 FT_UINT32, BASE_DEC, NULL, 0x0,
600 { "NCP over IP Version", "ncp.ip.version",
601 FT_UINT32, BASE_DEC, NULL, 0x0,
603 { &hf_ncp_ip_rplybufsize,
604 { "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize",
605 FT_UINT32, BASE_DEC, NULL, 0x0,
607 { &hf_ncp_ip_packetsig,
608 { "NCP over IP Packet Signature", "ncp.ip.packetsig",
609 FT_BYTES, BASE_NONE, NULL, 0x0,
612 { "Type", "ncp.type",
613 FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
614 "NCP message type", HFILL }},
616 { "Sequence Number", "ncp.seq",
617 FT_UINT8, BASE_DEC, NULL, 0x0,
619 { &hf_ncp_connection,
620 { "Connection Number", "ncp.connection",
621 FT_UINT16, BASE_DEC, NULL, 0x0,
624 { "Task Number", "ncp.task",
625 FT_UINT8, BASE_DEC, NULL, 0x0,
627 { &hf_ncp_oplock_flag,
628 { "Oplock Flag", "ncp.oplock_flag",
629 FT_UINT8, BASE_HEX, NULL, 0x0,
631 { &hf_ncp_oplock_handle,
632 { "File Handle", "ncp.oplock_handle",
633 FT_UINT16, BASE_HEX, NULL, 0x0,
635 { &hf_ncp_stream_type,
636 { "Stream Type", "ncp.stream_type",
637 FT_UINT8, BASE_HEX, NULL, 0x0,
638 "Type of burst", HFILL }},
639 { &hf_ncp_system_flags,
640 { "System Flags", "ncp.system_flags",
641 FT_UINT8, BASE_HEX, NULL, 0x0,
643 { &hf_ncp_system_flags_abt,
644 { "ABT", "ncp.system_flags.abt",
645 FT_BOOLEAN, 8, NULL, ABT,
646 "Is this an abort request?", HFILL }},
647 { &hf_ncp_system_flags_eob,
648 { "EOB", "ncp.system_flags.eob",
649 FT_BOOLEAN, 8, NULL, EOB,
650 "Is this the last packet of the burst?", HFILL }},
651 { &hf_ncp_system_flags_sys,
652 { "SYS", "ncp.system_flags.sys",
653 FT_BOOLEAN, 8, NULL, SYS,
654 "Is this a system packet?", HFILL }},
655 { &hf_ncp_src_connection,
656 { "Source Connection ID", "ncp.src_connection",
657 FT_UINT32, BASE_DEC, NULL, 0x0,
658 "The workstation's connection identification number", HFILL }},
659 { &hf_ncp_dst_connection,
660 { "Destination Connection ID", "ncp.dst_connection",
661 FT_UINT32, BASE_DEC, NULL, 0x0,
662 "The server's connection identification number", HFILL }},
663 { &hf_ncp_packet_seqno,
664 { "Packet Sequence Number", "ncp.packet_seqno",
665 FT_UINT32, BASE_DEC, NULL, 0x0,
666 "Sequence number of this packet in a burst", HFILL }},
667 { &hf_ncp_delay_time,
668 { "Delay Time", "ncp.delay_time", /* in 100 us increments */
669 FT_UINT32, BASE_DEC, NULL, 0x0,
670 "Delay time between consecutive packet sends (100 us increments)", HFILL }},
671 { &hf_ncp_burst_seqno,
672 { "Burst Sequence Number", "ncp.burst_seqno",
673 FT_UINT16, BASE_DEC, NULL, 0x0,
674 "Sequence number of this packet in the burst", HFILL }},
676 { "ACK Sequence Number", "ncp.ack_seqno",
677 FT_UINT16, BASE_DEC, NULL, 0x0,
678 "Next expected burst sequence number", HFILL }},
680 { "Burst Length", "ncp.burst_len",
681 FT_UINT32, BASE_DEC, NULL, 0x0,
682 "Total length of data in this burst", HFILL }},
683 { &hf_ncp_data_offset,
684 { "Data Offset", "ncp.data_offset",
685 FT_UINT32, BASE_DEC, NULL, 0x0,
686 "Offset of this packet in the burst", HFILL }},
687 { &hf_ncp_data_bytes,
688 { "Data Bytes", "ncp.data_bytes",
689 FT_UINT16, BASE_DEC, NULL, 0x0,
690 "Number of data bytes in this packet", HFILL }},
691 { &hf_ncp_missing_fraglist_count,
692 { "Missing Fragment List Count", "ncp.missing_fraglist_count",
693 FT_UINT16, BASE_DEC, NULL, 0x0,
694 "Number of missing fragments reported", HFILL }},
695 { &hf_ncp_missing_data_offset,
696 { "Missing Data Offset", "ncp.missing_data_offset",
697 FT_UINT32, BASE_DEC, NULL, 0x0,
698 "Offset of beginning of missing data", HFILL }},
699 { &hf_ncp_missing_data_count,
700 { "Missing Data Count", "ncp.missing_data_count",
701 FT_UINT16, BASE_DEC, NULL, 0x0,
702 "Number of bytes of missing data", HFILL }},
703 { &hf_ncp_completion_code,
704 { "Completion Code", "ncp.completion_code",
705 FT_UINT8, BASE_DEC, NULL, 0x0,
707 { &hf_ncp_connection_status,
708 { "Connection Status", "ncp.connection_status",
709 FT_UINT8, BASE_DEC, NULL, 0x0,
712 { "Slot", "ncp.slot",
713 FT_UINT8, BASE_DEC, NULL, 0x0,
715 { &hf_ncp_control_code,
716 { "Control Code", "ncp.control_code",
717 FT_UINT8, BASE_DEC, NULL, 0x0,
719 { &hf_ncp_fragment_handle,
720 { "Fragment Handle", "ncp.fragger_hndl",
721 FT_UINT16, BASE_HEX, NULL, 0x0,
724 { "Large Internet Packet Echo", "ncp.lip_echo",
725 FT_STRING, BASE_NONE, NULL, 0x0,
729 static gint *ett[] = {
731 &ett_ncp_system_flags,
734 module_t *ncp_module;
736 proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
737 proto_register_field_array(proto_ncp, hf, array_length(hf));
738 proto_register_subtree_array(ett, array_length(ett));
740 ncp_module = prefs_register_protocol(proto_ncp, NULL);
741 prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
742 prefs_register_bool_preference(ncp_module, "desegment",
743 "Desegment all NCP-over-TCP messages spanning multiple segments",
744 "Whether the NCP dissector should desegment all messages spanning multiple TCP segments",
749 proto_reg_handoff_ncp(void)
751 dissector_handle_t ncp_handle;
752 dissector_handle_t ncp_tcp_handle;
754 ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
755 ncp_tcp_handle = create_dissector_handle(dissect_ncp_tcp, proto_ncp);
756 dissector_add("tcp.port", TCP_PORT_NCP, ncp_tcp_handle);
757 dissector_add("udp.port", UDP_PORT_NCP, ncp_handle);
758 dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
759 dissector_add("ipx.socket", IPX_SOCKET_NCP, ncp_handle);
761 data_handle = find_dissector("data");