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.67 2002/08/23 21:54:30 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;
88 static gint ett_ncp_system_flags = -1;
90 /* desegmentation of NCP over TCP */
91 static gboolean ncp_desegment = TRUE;
93 static dissector_handle_t data_handle;
95 #define TCP_PORT_NCP 524
96 #define UDP_PORT_NCP 524
98 #define NCP_RQST_HDR_LENGTH 7
99 #define NCP_RPLY_HDR_LENGTH 8
102 gint ncp_equal (gconstpointer v, gconstpointer v2);
103 guint ncp_hash (gconstpointer v);
105 /* These are the header structures to handle NCP over IP */
106 #define NCPIP_RQST 0x446d6454 /* "DmdT" */
107 #define NCPIP_RPLY 0x744e6350 /* "tNcP" */
109 struct ncp_ip_header {
114 /* This header only appears on NCP over IP request packets */
115 struct ncp_ip_rqhdr {
120 static const value_string ncp_ip_signature[] = {
121 { NCPIP_RQST, "Demand Transport (Request)" },
122 { NCPIP_RPLY, "Transport is NCP (Reply)" },
126 /* The information in this module comes from:
127 NetWare LAN Analysis, Second Edition
128 Laura A. Chappell and Dan E. Hakes
129 (c) 1994 Novell, Inc.
130 Novell Press, San Jose.
133 And from the ncpfs source code by Volker Lendecke
136 Programmer's Guide to the NetWare Core Protocol
137 Steve Conner & Diane Conner
138 (c) 1996 by Steve Conner & Diane Conner
139 Published by Annabooks, San Diego, California
145 * Every NCP packet has this common header (except for burst packets).
147 struct ncp_common_header {
152 guint8 conn_high; /* type=0x5555 doesn't have this */
156 static value_string ncp_type_vals[] = {
157 { NCP_ALLOCATE_SLOT, "Create a service connection" },
158 { NCP_SERVICE_REQUEST, "Service request" },
159 { NCP_SERVICE_REPLY, "Service reply" },
160 { NCP_WATCHDOG, "Watchdog" },
161 { NCP_DEALLOCATE_SLOT, "Destroy service connection" },
162 { NCP_BROADCAST_SLOT, "Server Broadcast" },
163 { NCP_BURST_MODE_XFER, "Burst mode transfer" },
164 { NCP_POSITIVE_ACK, "Request being processed" },
165 { NCP_LIP_ECHO, "Large Internet Packet Echo" },
171 * Burst packet system flags.
173 #define ABT 0x04 /* Abort request */
174 #define EOB 0x10 /* End of burst */
175 #define SYS 0x80 /* System packet */
178 dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
181 proto_tree *ncp_tree = NULL;
183 struct ncp_ip_header ncpiph;
184 struct ncp_ip_rqhdr ncpiphrq;
185 gboolean is_signed = FALSE;
186 struct ncp_common_header header;
187 guint16 nw_connection;
189 char flags_str[1+3+1+3+1+3+1+1];
191 proto_tree *flags_tree = NULL;
192 guint16 data_len = 0;
193 guint16 missing_fraglist_count = 0;
194 guint16 ncp_nds_verb;
198 gint length_remaining;
201 if (check_col(pinfo->cinfo, COL_PROTOCOL))
202 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
203 if (check_col(pinfo->cinfo, COL_INFO))
204 col_clear(pinfo->cinfo, COL_INFO);
207 ncpiph.signature = tvb_get_ntohl(tvb, 0);
208 ncpiph.length = tvb_get_ntohl(tvb, 4);
210 if ( ncpiph.signature == NCPIP_RQST ) {
211 ncpiphrq.version = tvb_get_ntohl(tvb, hdr_offset);
213 ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, hdr_offset);
216 if (ncpiph.length & 0x80000000) {
218 * This appears to indicate that this packet
219 * is signed; the signature is 8 bytes long.
221 * XXX - that bit does *not* appear to be set
222 * in signed replies, and we can't dissect the
223 * reply enough to find the matching request
224 * without knowing whether the reply is
227 * XXX - what about NCP-over-IPX signed
232 ncpiph.length &= 0x7fffffff;
236 /* Record the offset where the NCP common header starts */
237 commhdr = hdr_offset;
239 header.type = tvb_get_ntohs(tvb, commhdr);
240 header.sequence = tvb_get_guint8(tvb, commhdr+2);
241 header.conn_low = tvb_get_guint8(tvb, commhdr+3);
242 header.conn_high = tvb_get_guint8(tvb, commhdr+5);
244 if (check_col(pinfo->cinfo, COL_INFO)) {
245 col_add_fstr(pinfo->cinfo, COL_INFO,
247 val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
250 nw_connection = (header.conn_high << 16) + header.conn_low;
253 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE);
254 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
257 proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature);
258 proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length);
259 if (ncpiph.signature == NCPIP_RQST) {
260 proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version);
261 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize);
264 proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 16, 8, FALSE);
266 proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr + 0, 2, header.type);
271 * Process the packet-type-specific header.
273 switch (header.type) {
275 case NCP_BROADCAST_SLOT: /* Server Broadcast */
276 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
277 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
278 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
279 proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, FALSE);
280 proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, FALSE);
283 case NCP_LIP_ECHO: /* Lip Echo Packet */
284 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 13, FALSE);
287 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
289 * XXX - we should keep track of whether there's a burst
290 * outstanding on a connection and, if not, treat the
291 * beginning of the data as a burst header.
293 * The burst header contains:
295 * 4 bytes of little-endian function number:
296 * 1 = read, 2 = write;
298 * 4 bytes of file handle;
302 * 4 bytes of big-endian file offset;
304 * 4 bytes of big-endian byte count.
306 * The data follows for a burst write operation.
308 * The first packet of a burst read reply contains:
310 * 4 bytes of little-endian result code:
316 * 4 bytes of returned byte count (big-endian?).
320 * Each burst of a write request is responded to with a
321 * burst packet with a 2-byte little-endian result code:
323 * 0: Write successful
326 flags = tvb_get_guint8(tvb, commhdr + 2);
327 strcpy(flags_str, "");
330 strcat(flags_str, sep);
331 strcat(flags_str, "ABT");
335 strcat(flags_str, sep);
336 strcat(flags_str, "EOB");
340 strcat(flags_str, sep);
341 strcat(flags_str, "SYS");
343 if (flags_str[0] != '\0')
344 strcat(flags_str, ")");
345 ti = proto_tree_add_uint_format(ncp_tree, hf_ncp_system_flags,
346 tvb, commhdr + 2, 1, flags, "Flags: 0x%04x%s", flags,
348 flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
349 proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
350 tvb, commhdr + 2, 1, FALSE);
351 proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
352 tvb, commhdr + 2, 1, FALSE);
353 proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
354 tvb, commhdr + 2, 1, FALSE);
356 proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
357 tvb, commhdr + 3, 1, FALSE);
358 proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
359 tvb, commhdr + 4, 4, FALSE);
360 proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
361 tvb, commhdr + 8, 4, FALSE);
362 proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
363 tvb, commhdr + 12, 4, FALSE);
364 proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
365 tvb, commhdr + 16, 4, FALSE);
366 proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
367 tvb, commhdr + 20, 2, FALSE);
368 proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
369 tvb, commhdr + 22, 2, FALSE);
370 proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
371 tvb, commhdr + 24, 4, FALSE);
372 proto_tree_add_item(ncp_tree, hf_ncp_data_offset,
373 tvb, commhdr + 28, 4, FALSE);
374 data_len = tvb_get_ntohs(tvb, commhdr + 32);
375 proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
376 tvb, commhdr + 32, 2, data_len);
377 missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
378 proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
379 tvb, commhdr + 34, 2, FALSE);
382 case NCP_SERVICE_REQUEST: /* Server NCP Request */
383 case NCP_SERVICE_REPLY: /* Server NCP Reply */
384 case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
385 case NCP_WATCHDOG: /* Watchdog Packet */
386 case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
387 case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
389 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
390 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
391 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
396 * Process the packet body.
398 switch (header.type) {
400 case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
401 case NCP_SERVICE_REQUEST: /* Server NCP Request */
402 case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
403 case NCP_BROADCAST_SLOT: /* Server Broadcast Packet */
404 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
405 if (tvb_get_guint8(tvb, commhdr+6) == 0x68) {
406 ncp_nds_verb = tvb_get_ntohl(tvb, commhdr+4);
407 if (tvb_get_guint8(tvb, commhdr+7) == 0x02) { /* NDS Packet to decode */
408 dissect_nds_request(next_tvb, pinfo, nw_connection,
409 header.sequence, header.type, ncp_tree);
411 dissect_ncp_request(next_tvb, pinfo, nw_connection,
412 header.sequence, header.type, ncp_tree);
415 dissect_ncp_request(next_tvb, pinfo, nw_connection,
416 header.sequence, header.type, ncp_tree);
420 case NCP_SERVICE_REPLY: /* Server NCP Reply */
421 case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
422 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
423 dissect_ncp_reply(next_tvb, pinfo, nw_connection,
424 header.sequence, header.type, ncp_tree);
427 case NCP_WATCHDOG: /* Watchdog Packet */
429 * XXX - should the completion code be interpreted as
430 * it is in "packet-ncp2222.inc"? If so, this
431 * packet should be handled by "dissect_ncp_reply()".
433 proto_tree_add_item(ncp_tree, hf_ncp_completion_code,
434 tvb, commhdr + 6, 1, TRUE);
435 proto_tree_add_item(ncp_tree, hf_ncp_connection_status,
436 tvb, commhdr + 7, 1, TRUE);
437 proto_tree_add_item(ncp_tree, hf_ncp_slot,
438 tvb, commhdr + 8, 1, TRUE);
439 proto_tree_add_item(ncp_tree, hf_ncp_control_code,
440 tvb, commhdr + 9, 1, TRUE);
442 * Display the rest of the packet as data.
444 if (tvb_offset_exists(tvb, commhdr + 10)) {
445 call_dissector(data_handle,
446 tvb_new_subset(tvb, commhdr + 10, -1, -1),
451 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
454 * System packet; show missing fragments if there
457 offset = commhdr + 36;
458 while (missing_fraglist_count != 0) {
459 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
460 tvb, offset, 4, FALSE);
461 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
462 tvb, offset, 2, FALSE);
463 missing_fraglist_count--;
467 * XXX - do this by using -1 and -1 as the length
468 * arguments to "tvb_new_subset()" and then calling
469 * "tvb_set_reported_length()"? That'll throw an
470 * exception if "data_len" goes past the reported
471 * length of the packet, but that's arguably a
472 * feature in this case.
474 length_remaining = tvb_length_remaining(tvb, commhdr + 36);
475 if (length_remaining > data_len)
476 length_remaining = data_len;
478 call_dissector(data_handle,
479 tvb_new_subset(tvb, commhdr + 36,
480 length_remaining, data_len),
486 case NCP_LIP_ECHO: /* LIP Echo Packet */
487 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
493 proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1,
494 "%s packets not supported yet",
495 val_to_str(header.type, ncp_type_vals,
496 "Unknown type (0x%04x)"));
503 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
505 dissect_ncp_common(tvb, pinfo, tree, FALSE);
509 get_ncp_pdu_len(tvbuff_t *tvb, int offset)
514 * Check the NCP-over-TCP header signature, to make sure it's there.
515 * If it's not there, we cannot trust the next 4 bytes to be a
516 * packet length+"has signature" flag, so we just say the length is
517 * "what remains in the packet".
519 signature = tvb_get_ntohl(tvb, offset);
520 if (signature != NCPIP_RQST && signature != NCPIP_RPLY)
521 return tvb_length_remaining(tvb, offset);
524 * Get the length of the NCP-over-TCP packet. Strip off the "has
527 return tvb_get_ntohl(tvb, offset + 4) & 0x7fffffff;
531 dissect_ncp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
533 dissect_ncp_common(tvb, pinfo, tree, TRUE);
537 dissect_ncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
539 tcp_dissect_pdus(tvb, pinfo, tree, ncp_desegment, 8, get_ncp_pdu_len,
540 dissect_ncp_tcp_pdu);
544 proto_register_ncp(void)
547 static hf_register_info hf[] = {
549 { "NCP over IP signature", "ncp.ip.signature",
550 FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
553 { "NCP over IP length", "ncp.ip.length",
554 FT_UINT32, BASE_DEC, NULL, 0x0,
557 { "NCP over IP Version", "ncp.ip.version",
558 FT_UINT32, BASE_DEC, NULL, 0x0,
560 { &hf_ncp_ip_rplybufsize,
561 { "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize",
562 FT_UINT32, BASE_DEC, NULL, 0x0,
564 { &hf_ncp_ip_packetsig,
565 { "NCP over IP Packet Signature", "ncp.ip.packetsig",
566 FT_BYTES, BASE_NONE, NULL, 0x0,
569 { "Type", "ncp.type",
570 FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
571 "NCP message type", HFILL }},
573 { "Sequence Number", "ncp.seq",
574 FT_UINT8, BASE_DEC, NULL, 0x0,
576 { &hf_ncp_connection,
577 { "Connection Number", "ncp.connection",
578 FT_UINT16, BASE_DEC, NULL, 0x0,
581 { "Task Number", "ncp.task",
582 FT_UINT8, BASE_DEC, NULL, 0x0,
584 { &hf_ncp_oplock_flag,
585 { "Oplock Flag", "ncp.oplock_flag",
586 FT_UINT8, BASE_HEX, NULL, 0x0,
588 { &hf_ncp_oplock_handle,
589 { "File Handle", "ncp.oplock_handle",
590 FT_UINT16, BASE_HEX, NULL, 0x0,
592 { &hf_ncp_stream_type,
593 { "Stream Type", "ncp.stream_type",
594 FT_UINT8, BASE_HEX, NULL, 0x0,
595 "Type of burst", HFILL }},
596 { &hf_ncp_system_flags,
597 { "System Flags", "ncp.system_flags",
598 FT_UINT8, BASE_HEX, NULL, 0x0,
600 { &hf_ncp_system_flags_abt,
601 { "ABT", "ncp.system_flags.abt",
602 FT_BOOLEAN, 8, NULL, ABT,
603 "Is this an abort request?", HFILL }},
604 { &hf_ncp_system_flags_eob,
605 { "EOB", "ncp.system_flags.eob",
606 FT_BOOLEAN, 8, NULL, EOB,
607 "Is this the last packet of the burst?", HFILL }},
608 { &hf_ncp_system_flags_sys,
609 { "SYS", "ncp.system_flags.sys",
610 FT_BOOLEAN, 8, NULL, SYS,
611 "Is this a system packet?", HFILL }},
612 { &hf_ncp_src_connection,
613 { "Source Connection ID", "ncp.src_connection",
614 FT_UINT32, BASE_DEC, NULL, 0x0,
615 "The workstation's connection identification number", HFILL }},
616 { &hf_ncp_dst_connection,
617 { "Destination Connection ID", "ncp.dst_connection",
618 FT_UINT32, BASE_DEC, NULL, 0x0,
619 "The server's connection identification number", HFILL }},
620 { &hf_ncp_packet_seqno,
621 { "Packet Sequence Number", "ncp.packet_seqno",
622 FT_UINT32, BASE_DEC, NULL, 0x0,
623 "Sequence number of this packet in a burst", HFILL }},
624 { &hf_ncp_delay_time,
625 { "Delay Time", "ncp.delay_time", /* in 100 us increments */
626 FT_UINT32, BASE_DEC, NULL, 0x0,
627 "Delay time between consecutive packet sends (100 us increments)", HFILL }},
628 { &hf_ncp_burst_seqno,
629 { "Burst Sequence Number", "ncp.burst_seqno",
630 FT_UINT16, BASE_DEC, NULL, 0x0,
631 "Sequence number of this packet in the burst", HFILL }},
633 { "ACK Sequence Number", "ncp.ack_seqno",
634 FT_UINT16, BASE_DEC, NULL, 0x0,
635 "Next expected burst sequence number", HFILL }},
637 { "Burst Length", "ncp.burst_len",
638 FT_UINT32, BASE_DEC, NULL, 0x0,
639 "Total length of data in this burst", HFILL }},
640 { &hf_ncp_data_offset,
641 { "Data Offset", "ncp.data_offset",
642 FT_UINT32, BASE_DEC, NULL, 0x0,
643 "Offset of this packet in the burst", HFILL }},
644 { &hf_ncp_data_bytes,
645 { "Data Bytes", "ncp.data_bytes",
646 FT_UINT16, BASE_DEC, NULL, 0x0,
647 "Number of data bytes in this packet", HFILL }},
648 { &hf_ncp_missing_fraglist_count,
649 { "Missing Fragment List Count", "ncp.missing_fraglist_count",
650 FT_UINT16, BASE_DEC, NULL, 0x0,
651 "Number of missing fragments reported", HFILL }},
652 { &hf_ncp_missing_data_offset,
653 { "Missing Data Offset", "ncp.missing_data_offset",
654 FT_UINT32, BASE_DEC, NULL, 0x0,
655 "Offset of beginning of missing data", HFILL }},
656 { &hf_ncp_missing_data_count,
657 { "Missing Data Count", "ncp.missing_data_count",
658 FT_UINT16, BASE_DEC, NULL, 0x0,
659 "Number of bytes of missing data", HFILL }},
660 { &hf_ncp_completion_code,
661 { "Completion Code", "ncp.completion_code",
662 FT_UINT8, BASE_DEC, NULL, 0x0,
664 { &hf_ncp_connection_status,
665 { "Connection Status", "ncp.connection_status",
666 FT_UINT8, BASE_DEC, NULL, 0x0,
669 { "Slot", "ncp.slot",
670 FT_UINT8, BASE_DEC, NULL, 0x0,
672 { &hf_ncp_control_code,
673 { "Control Code", "ncp.control_code",
674 FT_UINT8, BASE_DEC, NULL, 0x0,
676 { &hf_ncp_fragment_handle,
677 { "Fragment Handle", "ncp.fragger_hndl",
678 FT_UINT16, BASE_HEX, NULL, 0x0,
681 { "Large Internet Packet Echo", "ncp.lip_echo",
682 FT_STRING, BASE_NONE, NULL, 0x0,
685 static gint *ett[] = {
687 &ett_ncp_system_flags,
689 module_t *ncp_module;
691 proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
692 proto_register_field_array(proto_ncp, hf, array_length(hf));
693 proto_register_subtree_array(ett, array_length(ett));
695 ncp_module = prefs_register_protocol(proto_ncp, NULL);
696 prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
697 prefs_register_bool_preference(ncp_module, "desegment",
698 "Desegment all NCP-over-TCP messages spanning multiple segments",
699 "Whether the NCP dissector should desegment all messages spanning multiple TCP segments",
704 proto_reg_handoff_ncp(void)
706 dissector_handle_t ncp_handle;
707 dissector_handle_t ncp_tcp_handle;
709 ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
710 ncp_tcp_handle = create_dissector_handle(dissect_ncp_tcp, proto_ncp);
711 dissector_add("tcp.port", TCP_PORT_NCP, ncp_tcp_handle);
712 dissector_add("udp.port", UDP_PORT_NCP, ncp_handle);
713 dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
714 dissector_add("ipx.socket", IPX_SOCKET_NCP, ncp_handle);
716 data_handle = find_dissector("data");