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 * Portions Copyright (c) by Gilbert Ramirez 2000-2002
9 * Portions Copyright (c) by James Coe 2000-2002
10 * Portions Copyright (c) Novell, Inc. 2000-2003
12 * $Id: packet-ncp.c,v 1.73 2003/08/25 22:14:07 guy Exp $
14 * Ethereal - Network traffic analyzer
15 * By Gerald Combs <gerald@ethereal.com>
16 * Copyright 2000 Gerald Combs
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
47 #include <epan/packet.h>
48 #include <epan/conversation.h>
50 #include "packet-ipx.h"
51 #include "packet-tcp.h"
52 #include "packet-ncp-int.h"
53 #include "reassemble.h"
55 gboolean is_signed = FALSE;
57 static int hf_ncp_ip_ver = -1;
58 static int hf_ncp_ip_length = -1;
59 static int hf_ncp_ip_rplybufsize = -1;
60 static int hf_ncp_ip_sig = -1;
61 static int hf_ncp_ip_packetsig = -1;
62 static int hf_ncp_type = -1;
63 static int hf_ncp_seq = -1;
64 static int hf_ncp_connection = -1;
65 static int hf_ncp_task = -1;
66 static int hf_ncp_stream_type = -1;
67 static int hf_ncp_system_flags = -1;
68 static int hf_ncp_system_flags_abt = -1;
69 static int hf_ncp_system_flags_eob = -1;
70 static int hf_ncp_system_flags_sys = -1;
71 static int hf_ncp_src_connection = -1;
72 static int hf_ncp_dst_connection = -1;
73 static int hf_ncp_packet_seqno = -1;
74 static int hf_ncp_delay_time = -1;
75 static int hf_ncp_burst_seqno = -1;
76 static int hf_ncp_ack_seqno = -1;
77 static int hf_ncp_burst_len = -1;
78 static int hf_ncp_data_offset = -1;
79 static int hf_ncp_data_bytes = -1;
80 static int hf_ncp_missing_fraglist_count = -1;
81 static int hf_ncp_missing_data_offset = -1;
82 static int hf_ncp_missing_data_count = -1;
83 static int hf_ncp_oplock_flag = -1;
84 static int hf_ncp_oplock_handle = -1;
85 static int hf_ncp_completion_code = -1;
86 static int hf_ncp_connection_status = -1;
87 static int hf_ncp_slot = -1;
88 static int hf_ncp_control_code = -1;
89 static int hf_ncp_fragment_handle = -1;
90 static int hf_lip_echo = -1;
94 gint ett_nds_segments = -1;
95 gint ett_nds_segment = -1;
96 static gint ett_ncp_system_flags = -1;
99 /* Tables for reassembly of fragments. */
100 GHashTable *nds_fragment_table = NULL;
101 GHashTable *nds_reassembled_table = NULL;
102 dissector_handle_t nds_data_handle;
104 /* desegmentation of NCP over TCP */
105 static gboolean ncp_desegment = TRUE;
107 static dissector_handle_t data_handle;
109 #define TCP_PORT_NCP 524
110 #define UDP_PORT_NCP 524
112 #define NCP_RQST_HDR_LENGTH 7
113 #define NCP_RPLY_HDR_LENGTH 8
117 gint ncp_equal (gconstpointer v, gconstpointer v2);
118 guint ncp_hash (gconstpointer v);
120 /* These are the header structures to handle NCP over IP */
121 #define NCPIP_RQST 0x446d6454 /* "DmdT" */
122 #define NCPIP_RPLY 0x744e6350 /* "tNcP" */
124 struct ncp_ip_header {
129 /* This header only appears on NCP over IP request packets */
130 struct ncp_ip_rqhdr {
135 static const value_string ncp_ip_signature[] = {
136 { NCPIP_RQST, "Demand Transport (Request)" },
137 { NCPIP_RPLY, "Transport is NCP (Reply)" },
141 /* The information in this module comes from:
142 NetWare LAN Analysis, Second Edition
143 Laura A. Chappell and Dan E. Hakes
144 (c) 1994 Novell, Inc.
145 Novell Press, San Jose.
148 And from the ncpfs source code by Volker Lendecke
151 Programmer's Guide to the NetWare Core Protocol
152 Steve Conner & Diane Conner
153 (c) 1996 by Steve Conner & Diane Conner
154 Published by Annabooks, San Diego, California
158 http:developer.novell.com
164 * Every NCP packet has this common header (except for burst packets).
166 struct ncp_common_header {
171 guint8 conn_high; /* type=0x5555 doesn't have this */
175 static value_string ncp_type_vals[] = {
176 { NCP_ALLOCATE_SLOT, "Create a service connection" },
177 { NCP_SERVICE_REQUEST, "Service request" },
178 { NCP_SERVICE_REPLY, "Service reply" },
179 { NCP_WATCHDOG, "Watchdog" },
180 { NCP_DEALLOCATE_SLOT, "Destroy service connection" },
181 { NCP_BROADCAST_SLOT, "Server Broadcast" },
182 { NCP_BURST_MODE_XFER, "Burst mode transfer" },
183 { NCP_POSITIVE_ACK, "Request being processed" },
184 { NCP_LIP_ECHO, "Large Internet Packet Echo" },
190 * Burst packet system flags.
192 #define ABT 0x04 /* Abort request */
193 #define EOB 0x10 /* End of burst */
194 #define SYS 0x80 /* System packet */
197 dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
200 proto_tree *ncp_tree = NULL;
202 struct ncp_ip_header ncpiph;
203 struct ncp_ip_rqhdr ncpiphrq;
204 struct ncp_common_header header;
205 guint16 nw_connection;
207 char flags_str[1+3+1+3+1+3+1+1];
209 proto_tree *flags_tree = NULL;
210 guint16 data_len = 0;
211 guint16 missing_fraglist_count = 0;
215 gint length_remaining;
220 if (check_col(pinfo->cinfo, COL_PROTOCOL))
221 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
222 if (check_col(pinfo->cinfo, COL_INFO))
223 col_clear(pinfo->cinfo, COL_INFO);
228 if (tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RQST && tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RPLY)
232 ncpiph.signature = tvb_get_ntohl(tvb, hdr_offset);
233 ncpiph.length = tvb_get_ntohl(tvb, hdr_offset+4);
235 if ( ncpiph.signature == NCPIP_RQST ) {
236 ncpiphrq.version = tvb_get_ntohl(tvb, hdr_offset);
238 ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, hdr_offset);
241 if (ncpiph.length & 0x80000000 || ncpiph.signature == NCPIP_RPLY)
243 if (!pinfo->fd->flags.visited)
246 * This appears to indicate that this packet
247 * is signed; the signature is 8 bytes long.
249 * XXX - that bit does *not* appear to be set
250 * in signed replies, and we can't dissect the
251 * reply enough to find the matching request
252 * without knowing whether the reply is
255 * XXX - what about NCP-over-IPX signed
258 if (ncpiph.signature == NCPIP_RQST) {
261 ncpiph.length &= 0x7fffffff;
268 ncpiph.length &= 0x7fffffff;
281 ncpiph.length &= 0x7fffffff;
291 /* Record the offset where the NCP common header starts */
292 commhdr = hdr_offset;
294 header.type = tvb_get_ntohs(tvb, commhdr);
295 header.sequence = tvb_get_guint8(tvb, commhdr+2);
296 header.conn_low = tvb_get_guint8(tvb, commhdr+3);
297 header.conn_high = tvb_get_guint8(tvb, commhdr+5);
299 if (check_col(pinfo->cinfo, COL_INFO)) {
300 col_add_fstr(pinfo->cinfo, COL_INFO,
302 val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
306 nw_connection = (header.conn_high << 16) + header.conn_low;
309 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE);
310 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
313 proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature);
314 proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length);
315 if (ncpiph.signature == NCPIP_RQST) {
316 proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version);
317 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize);
319 proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 16, 8, FALSE);
324 proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 8, 8, FALSE);
327 proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr + 0, 2, header.type);
332 * Process the packet-type-specific header.
334 switch (header.type) {
336 case NCP_BROADCAST_SLOT: /* Server Broadcast */
337 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
338 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
339 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
340 proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, FALSE);
341 proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, FALSE);
344 case NCP_LIP_ECHO: /* Lip Echo Packet */
345 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 13, FALSE);
348 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
350 * XXX - we should keep track of whether there's a burst
351 * outstanding on a connection and, if not, treat the
352 * beginning of the data as a burst header.
354 * The burst header contains:
356 * 4 bytes of little-endian function number:
357 * 1 = read, 2 = write;
359 * 4 bytes of file handle;
363 * 4 bytes of big-endian file offset;
365 * 4 bytes of big-endian byte count.
367 * The data follows for a burst write operation.
369 * The first packet of a burst read reply contains:
371 * 4 bytes of little-endian result code:
377 * 4 bytes of returned byte count (big-endian?).
381 * Each burst of a write request is responded to with a
382 * burst packet with a 2-byte little-endian result code:
384 * 0: Write successful
387 flags = tvb_get_guint8(tvb, commhdr + 2);
388 strcpy(flags_str, "");
391 strcat(flags_str, sep);
392 strcat(flags_str, "ABT");
396 strcat(flags_str, sep);
397 strcat(flags_str, "EOB");
401 strcat(flags_str, sep);
402 strcat(flags_str, "SYS");
404 if (flags_str[0] != '\0')
405 strcat(flags_str, ")");
406 ti = proto_tree_add_uint_format(ncp_tree, hf_ncp_system_flags,
407 tvb, commhdr + 2, 1, flags, "Flags: 0x%04x%s", flags,
409 flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
410 proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
411 tvb, commhdr + 2, 1, FALSE);
412 proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
413 tvb, commhdr + 2, 1, FALSE);
414 proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
415 tvb, commhdr + 2, 1, FALSE);
417 proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
418 tvb, commhdr + 3, 1, FALSE);
419 proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
420 tvb, commhdr + 4, 4, FALSE);
421 proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
422 tvb, commhdr + 8, 4, FALSE);
423 proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
424 tvb, commhdr + 12, 4, FALSE);
425 proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
426 tvb, commhdr + 16, 4, FALSE);
427 proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
428 tvb, commhdr + 20, 2, FALSE);
429 proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
430 tvb, commhdr + 22, 2, FALSE);
431 proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
432 tvb, commhdr + 24, 4, FALSE);
433 proto_tree_add_item(ncp_tree, hf_ncp_data_offset,
434 tvb, commhdr + 28, 4, FALSE);
435 data_len = tvb_get_ntohs(tvb, commhdr + 32);
436 proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
437 tvb, commhdr + 32, 2, data_len);
438 missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
439 proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
440 tvb, commhdr + 34, 2, FALSE);
443 case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
444 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
445 if (length_remaining > 4) {
446 testvar = tvb_get_ntohl(tvb, commhdr+4);
447 if (testvar == 0x4c495020) {
448 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr+4, 13, FALSE);
452 /* otherwise fall through */
454 case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
455 case NCP_SERVICE_REQUEST: /* Server NCP Request */
456 case NCP_SERVICE_REPLY: /* Server NCP Reply */
457 case NCP_WATCHDOG: /* Watchdog Packet */
458 case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
460 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
461 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
462 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
467 * Process the packet body.
469 switch (header.type) {
471 case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
472 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
473 "Destroy Service Connection");
475 case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
476 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
477 if (length_remaining > 4) {
478 testvar = tvb_get_ntohl(tvb, commhdr+4);
479 if (testvar == 0x4c495020) {
480 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
486 case NCP_SERVICE_REQUEST: /* Server NCP Request */
487 case NCP_BROADCAST_SLOT: /* Server Broadcast Packet */
488 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
489 if (tvb_get_guint8(tvb, commhdr+6) == 0x68) {
490 subfunction = tvb_get_guint8(tvb, commhdr+7);
491 switch (subfunction) {
493 case 0x02: /* NDS Frag Packet to decode */
494 dissect_nds_request(next_tvb, pinfo,
495 nw_connection, header.sequence,
496 header.type, ncp_tree);
499 case 0x01: /* NDS Ping */
500 dissect_ping_req(next_tvb, pinfo,
501 nw_connection, header.sequence,
502 header.type, ncp_tree);
506 dissect_ncp_request(next_tvb, pinfo,
507 nw_connection, header.sequence,
508 header.type, ncp_tree);
512 dissect_ncp_request(next_tvb, pinfo, nw_connection,
513 header.sequence, header.type, ncp_tree);
517 case NCP_SERVICE_REPLY: /* Server NCP Reply */
518 case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
519 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
520 nds_defrag(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree);
523 case NCP_WATCHDOG: /* Watchdog Packet */
525 * XXX - should the completion code be interpreted as
526 * it is in "packet-ncp2222.inc"? If so, this
527 * packet should be handled by "dissect_ncp_reply()".
529 proto_tree_add_item(ncp_tree, hf_ncp_completion_code,
530 tvb, commhdr + 6, 1, TRUE);
531 proto_tree_add_item(ncp_tree, hf_ncp_connection_status,
532 tvb, commhdr + 7, 1, TRUE);
533 proto_tree_add_item(ncp_tree, hf_ncp_slot,
534 tvb, commhdr + 8, 1, TRUE);
535 proto_tree_add_item(ncp_tree, hf_ncp_control_code,
536 tvb, commhdr + 9, 1, TRUE);
538 * Display the rest of the packet as data.
540 if (tvb_offset_exists(tvb, commhdr + 10)) {
541 call_dissector(data_handle,
542 tvb_new_subset(tvb, commhdr + 10, -1, -1),
547 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
550 * System packet; show missing fragments if there
553 offset = commhdr + 36;
554 while (missing_fraglist_count != 0) {
555 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
556 tvb, offset, 4, FALSE);
557 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
558 tvb, offset, 2, FALSE);
559 missing_fraglist_count--;
563 * XXX - do this by using -1 and -1 as the length
564 * arguments to "tvb_new_subset()" and then calling
565 * "tvb_set_reported_length()"? That'll throw an
566 * exception if "data_len" goes past the reported
567 * length of the packet, but that's arguably a
568 * feature in this case.
570 length_remaining = tvb_length_remaining(tvb, commhdr + 36);
571 if (length_remaining > data_len)
572 length_remaining = data_len;
574 call_dissector(data_handle,
575 tvb_new_subset(tvb, commhdr + 36,
576 length_remaining, data_len),
582 case NCP_LIP_ECHO: /* LIP Echo Packet */
583 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
589 proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1,
590 "%s packets not supported yet",
591 val_to_str(header.type, ncp_type_vals,
592 "Unknown type (0x%04x)"));
599 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
601 dissect_ncp_common(tvb, pinfo, tree, FALSE);
605 get_ncp_pdu_len(tvbuff_t *tvb, int offset)
610 * Check the NCP-over-TCP header signature, to make sure it's there.
611 * If it's not there, we cannot trust the next 4 bytes to be a
612 * packet length+"has signature" flag, so we just say the length is
613 * "what remains in the packet".
615 /*if (tvb_get_guint8(tvb, offset)==0xff)
619 signature = tvb_get_ntohl(tvb, offset);
620 if (signature != NCPIP_RQST && signature != NCPIP_RPLY)
621 return tvb_length_remaining(tvb, offset);
624 * Get the length of the NCP-over-TCP packet. Strip off the "has
628 return tvb_get_ntohl(tvb, offset + 4) & 0x7fffffff;
632 dissect_ncp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
634 dissect_ncp_common(tvb, pinfo, tree, TRUE);
638 dissect_ncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
640 tcp_dissect_pdus(tvb, pinfo, tree, ncp_desegment, 8, get_ncp_pdu_len,
641 dissect_ncp_tcp_pdu);
645 proto_register_ncp(void)
648 static hf_register_info hf[] = {
650 { "NCP over IP signature", "ncp.ip.signature",
651 FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
654 { "NCP over IP length", "ncp.ip.length",
655 FT_UINT32, BASE_DEC, NULL, 0x0,
658 { "NCP over IP Version", "ncp.ip.version",
659 FT_UINT32, BASE_DEC, NULL, 0x0,
661 { &hf_ncp_ip_rplybufsize,
662 { "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize",
663 FT_UINT32, BASE_DEC, NULL, 0x0,
665 { &hf_ncp_ip_packetsig,
666 { "NCP over IP Packet Signature", "ncp.ip.packetsig",
667 FT_BYTES, BASE_NONE, NULL, 0x0,
670 { "Type", "ncp.type",
671 FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
672 "NCP message type", HFILL }},
674 { "Sequence Number", "ncp.seq",
675 FT_UINT8, BASE_DEC, NULL, 0x0,
677 { &hf_ncp_connection,
678 { "Connection Number", "ncp.connection",
679 FT_UINT16, BASE_DEC, NULL, 0x0,
682 { "Task Number", "ncp.task",
683 FT_UINT8, BASE_DEC, NULL, 0x0,
685 { &hf_ncp_oplock_flag,
686 { "Oplock Flag", "ncp.oplock_flag",
687 FT_UINT8, BASE_HEX, NULL, 0x0,
689 { &hf_ncp_oplock_handle,
690 { "File Handle", "ncp.oplock_handle",
691 FT_UINT16, BASE_HEX, NULL, 0x0,
693 { &hf_ncp_stream_type,
694 { "Stream Type", "ncp.stream_type",
695 FT_UINT8, BASE_HEX, NULL, 0x0,
696 "Type of burst", HFILL }},
697 { &hf_ncp_system_flags,
698 { "System Flags", "ncp.system_flags",
699 FT_UINT8, BASE_HEX, NULL, 0x0,
701 { &hf_ncp_system_flags_abt,
702 { "ABT", "ncp.system_flags.abt",
703 FT_BOOLEAN, 8, NULL, ABT,
704 "Is this an abort request?", HFILL }},
705 { &hf_ncp_system_flags_eob,
706 { "EOB", "ncp.system_flags.eob",
707 FT_BOOLEAN, 8, NULL, EOB,
708 "Is this the last packet of the burst?", HFILL }},
709 { &hf_ncp_system_flags_sys,
710 { "SYS", "ncp.system_flags.sys",
711 FT_BOOLEAN, 8, NULL, SYS,
712 "Is this a system packet?", HFILL }},
713 { &hf_ncp_src_connection,
714 { "Source Connection ID", "ncp.src_connection",
715 FT_UINT32, BASE_DEC, NULL, 0x0,
716 "The workstation's connection identification number", HFILL }},
717 { &hf_ncp_dst_connection,
718 { "Destination Connection ID", "ncp.dst_connection",
719 FT_UINT32, BASE_DEC, NULL, 0x0,
720 "The server's connection identification number", HFILL }},
721 { &hf_ncp_packet_seqno,
722 { "Packet Sequence Number", "ncp.packet_seqno",
723 FT_UINT32, BASE_DEC, NULL, 0x0,
724 "Sequence number of this packet in a burst", HFILL }},
725 { &hf_ncp_delay_time,
726 { "Delay Time", "ncp.delay_time", /* in 100 us increments */
727 FT_UINT32, BASE_DEC, NULL, 0x0,
728 "Delay time between consecutive packet sends (100 us increments)", HFILL }},
729 { &hf_ncp_burst_seqno,
730 { "Burst Sequence Number", "ncp.burst_seqno",
731 FT_UINT16, BASE_DEC, NULL, 0x0,
732 "Sequence number of this packet in the burst", HFILL }},
734 { "ACK Sequence Number", "ncp.ack_seqno",
735 FT_UINT16, BASE_DEC, NULL, 0x0,
736 "Next expected burst sequence number", HFILL }},
738 { "Burst Length", "ncp.burst_len",
739 FT_UINT32, BASE_DEC, NULL, 0x0,
740 "Total length of data in this burst", HFILL }},
741 { &hf_ncp_data_offset,
742 { "Data Offset", "ncp.data_offset",
743 FT_UINT32, BASE_DEC, NULL, 0x0,
744 "Offset of this packet in the burst", HFILL }},
745 { &hf_ncp_data_bytes,
746 { "Data Bytes", "ncp.data_bytes",
747 FT_UINT16, BASE_DEC, NULL, 0x0,
748 "Number of data bytes in this packet", HFILL }},
749 { &hf_ncp_missing_fraglist_count,
750 { "Missing Fragment List Count", "ncp.missing_fraglist_count",
751 FT_UINT16, BASE_DEC, NULL, 0x0,
752 "Number of missing fragments reported", HFILL }},
753 { &hf_ncp_missing_data_offset,
754 { "Missing Data Offset", "ncp.missing_data_offset",
755 FT_UINT32, BASE_DEC, NULL, 0x0,
756 "Offset of beginning of missing data", HFILL }},
757 { &hf_ncp_missing_data_count,
758 { "Missing Data Count", "ncp.missing_data_count",
759 FT_UINT16, BASE_DEC, NULL, 0x0,
760 "Number of bytes of missing data", HFILL }},
761 { &hf_ncp_completion_code,
762 { "Completion Code", "ncp.completion_code",
763 FT_UINT8, BASE_DEC, NULL, 0x0,
765 { &hf_ncp_connection_status,
766 { "Connection Status", "ncp.connection_status",
767 FT_UINT8, BASE_DEC, NULL, 0x0,
770 { "Slot", "ncp.slot",
771 FT_UINT8, BASE_DEC, NULL, 0x0,
773 { &hf_ncp_control_code,
774 { "Control Code", "ncp.control_code",
775 FT_UINT8, BASE_DEC, NULL, 0x0,
777 { &hf_ncp_fragment_handle,
778 { "Fragment Handle", "ncp.fragger_hndl",
779 FT_UINT16, BASE_HEX, NULL, 0x0,
782 { "Large Internet Packet Echo", "ncp.lip_echo",
783 FT_STRING, BASE_NONE, NULL, 0x0,
787 static gint *ett[] = {
789 &ett_ncp_system_flags,
794 module_t *ncp_module;
796 proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
797 proto_register_field_array(proto_ncp, hf, array_length(hf));
798 proto_register_subtree_array(ett, array_length(ett));
800 ncp_module = prefs_register_protocol(proto_ncp, NULL);
801 prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
802 prefs_register_bool_preference(ncp_module, "desegment",
803 "Desegment all NCP-over-TCP messages spanning multiple segments",
804 "Whether the NCP dissector should desegment all messages spanning multiple TCP segments",
806 prefs_register_bool_preference(ncp_module, "defragment_nds",
807 "Defragment all NDS messages spanning multiple packets",
808 "Whether the NCP dissector should defragment all NDS messages spanning multiple packets",
813 proto_reg_handoff_ncp(void)
815 dissector_handle_t ncp_handle;
816 dissector_handle_t ncp_tcp_handle;
818 ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
819 ncp_tcp_handle = create_dissector_handle(dissect_ncp_tcp, proto_ncp);
820 dissector_add("tcp.port", TCP_PORT_NCP, ncp_tcp_handle);
821 dissector_add("udp.port", UDP_PORT_NCP, ncp_handle);
822 dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
823 dissector_add("ipx.socket", IPX_SOCKET_NCP, ncp_handle);
825 data_handle = find_dissector("data");