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, packet signature,
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.77 2004/02/18 06:01:47 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>
49 #include "packet-ipx.h"
50 #include "packet-tcp.h"
51 #include "packet-ncp-int.h"
52 #include "reassemble.h"
53 #include <epan/conversation.h>
56 static int hf_ncp_ip_ver = -1;
57 static int hf_ncp_ip_length = -1;
58 static int hf_ncp_ip_rplybufsize = -1;
59 static int hf_ncp_ip_sig = -1;
60 static int hf_ncp_ip_packetsig = -1;
61 static int hf_ncp_type = -1;
62 static int hf_ncp_seq = -1;
63 static int hf_ncp_connection = -1;
64 static int hf_ncp_task = -1;
65 static int hf_ncp_stream_type = -1;
66 static int hf_ncp_system_flags = -1;
67 static int hf_ncp_system_flags_abt = -1;
68 static int hf_ncp_system_flags_eob = -1;
69 static int hf_ncp_system_flags_sys = -1;
70 static int hf_ncp_src_connection = -1;
71 static int hf_ncp_dst_connection = -1;
72 static int hf_ncp_packet_seqno = -1;
73 static int hf_ncp_delay_time = -1;
74 static int hf_ncp_burst_seqno = -1;
75 static int hf_ncp_ack_seqno = -1;
76 static int hf_ncp_burst_len = -1;
77 static int hf_ncp_data_offset = -1;
78 static int hf_ncp_data_bytes = -1;
79 static int hf_ncp_missing_fraglist_count = -1;
80 static int hf_ncp_missing_data_offset = -1;
81 static int hf_ncp_missing_data_count = -1;
82 static int hf_ncp_oplock_flag = -1;
83 static int hf_ncp_oplock_handle = -1;
84 static int hf_ncp_completion_code = -1;
85 static int hf_ncp_connection_status = -1;
86 static int hf_ncp_slot = -1;
87 static int hf_ncp_control_code = -1;
88 static int hf_ncp_fragment_handle = -1;
89 static int hf_lip_echo = -1;
93 gint ett_nds_segments = -1;
94 gint ett_nds_segment = -1;
95 static gint ett_ncp_system_flags = -1;
98 /* Tables for reassembly of fragments. */
99 GHashTable *nds_fragment_table = NULL;
100 GHashTable *nds_reassembled_table = NULL;
101 dissector_handle_t nds_data_handle;
103 /* desegmentation of NCP over TCP */
104 static gboolean ncp_desegment = TRUE;
106 static dissector_handle_t data_handle;
108 #define TCP_PORT_NCP 524
109 #define UDP_PORT_NCP 524
111 #define NCP_RQST_HDR_LENGTH 7
112 #define NCP_RPLY_HDR_LENGTH 8
116 gint ncp_equal (gconstpointer v, gconstpointer v2);
117 guint ncp_hash (gconstpointer v);
119 /* These are the header structures to handle NCP over IP */
120 #define NCPIP_RQST 0x446d6454 /* "DmdT" */
121 #define NCPIP_RPLY 0x744e6350 /* "tNcP" */
123 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" },
188 /* Conversation Struct so we can store whether the conversation is using Packet Signature */
191 conversation_t *conversation;
195 gboolean packet_signature;
198 static GHashTable *mncp_rhash = NULL;
199 static GMemChunk *mncp_rhash_keys = NULL;
200 static GMemChunk *mncp_rhash_values = NULL;
204 mncp_equal(gconstpointer v, gconstpointer v2)
206 const mncp_rhash_key *val1 = (const mncp_rhash_key*)v;
207 const mncp_rhash_key *val2 = (const mncp_rhash_key*)v2;
209 if (val1->conversation == val2->conversation ) {
216 mncp_hash(gconstpointer v)
218 const mncp_rhash_key *mncp_key = (const mncp_rhash_key*)v;
219 return GPOINTER_TO_UINT(mncp_key->conversation);
222 /* Initializes the hash table and the mem_chunk area each time a new
223 * file is loaded or re-loaded in ethereal */
225 mncp_init_protocol(void)
228 g_hash_table_destroy(mncp_rhash);
230 g_mem_chunk_destroy(mncp_rhash_keys);
231 if (mncp_rhash_values)
232 g_mem_chunk_destroy(mncp_rhash_values);
234 mncp_rhash = g_hash_table_new(mncp_hash, mncp_equal);
235 mncp_rhash_keys = g_mem_chunk_new("mncp_rhash_keys",
236 sizeof(mncp_rhash_key),
237 200 * sizeof(mncp_rhash_key),
239 mncp_rhash_values = g_mem_chunk_new("mncp_rhash_values",
240 sizeof(mncp_rhash_value),
241 200 * sizeof(mncp_rhash_value),
245 /* After the sequential run, we don't need the ncp_request hash and keys
246 * anymore; the lookups have already been done and the vital info
247 * saved in the reply-packets' private_data in the frame_data struct. */
249 mncp_postseq_cleanup(void)
254 mncp_hash_insert(conversation_t *conversation)
257 mncp_rhash_value *value;
259 /* Now remember the request, so we can find it if we later
261 key = g_mem_chunk_alloc(mncp_rhash_keys);
262 key->conversation = conversation;
264 value = g_mem_chunk_alloc(mncp_rhash_values);
265 value->packet_signature = FALSE;
267 g_hash_table_insert(mncp_rhash, key, value);
272 /* Returns the ncp_rec*, or NULL if not found. */
274 mncp_hash_lookup(conversation_t *conversation)
278 key.conversation = conversation;
280 return g_hash_table_lookup(mncp_rhash, &key);
284 * Burst packet system flags.
286 #define ABT 0x04 /* Abort request */
287 #define EOB 0x10 /* End of burst */
288 #define SYS 0x80 /* System packet */
291 dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
294 proto_tree *ncp_tree = NULL;
296 struct ncp_ip_header ncpiph;
297 struct ncp_ip_rqhdr ncpiphrq;
298 struct ncp_common_header header;
299 guint16 nw_connection;
301 char flags_str[1+3+1+3+1+3+1+1];
303 proto_tree *flags_tree = NULL;
304 guint16 data_len = 0;
305 guint16 missing_fraglist_count = 0;
309 gint length_remaining;
313 mncp_rhash_value *request_value = NULL;
314 conversation_t *conversation;
316 if (check_col(pinfo->cinfo, COL_PROTOCOL))
317 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
318 if (check_col(pinfo->cinfo, COL_INFO))
319 col_clear(pinfo->cinfo, COL_INFO);
325 if (tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RQST && tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RPLY)
327 ncpiph.signature = tvb_get_ntohl(tvb, hdr_offset);
328 ncpiph.length = tvb_get_ntohl(tvb, hdr_offset+4);
330 if (ncpiph.signature == NCPIP_RQST)
332 ncpiphrq.version = tvb_get_ntohl(tvb, hdr_offset);
334 ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, hdr_offset);
337 /* Ok, we need to track the conversation so that we can determine
338 * if packet signature is occuring for this connection. We will
339 * store the conversation the first time and that state of packet
340 * signature will be stored later in our logic. This way when we
341 * dissect reply packets we will be able to determine if we need
342 * to also dissect with a signature.
344 conversation = find_conversation(&pinfo->src, &pinfo->dst,
345 PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0);
346 if (ncpiph.length & 0x80000000 || ncpiph.signature == NCPIP_RPLY)
348 /* First time through we will store packet signature state */
349 if (!pinfo->fd->flags.visited)
351 if (conversation != NULL)
353 /* find the record telling us the request made that caused
355 request_value = mncp_hash_lookup(conversation);
356 /* if for some reason we have no conversation in our hash, create one */
357 if (request_value==NULL)
359 request_value = mncp_hash_insert(conversation);
364 /* It's not part of any conversation - create a new one. */
365 conversation = conversation_new(&pinfo->src, &pinfo->dst,
366 PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0);
367 request_value = mncp_hash_insert(conversation);
369 /* If this is a request packet then we know that we have a signature */
370 if (ncpiph.signature == NCPIP_RQST)
373 ncpiph.length &= 0x7fffffff;
374 request_value->packet_signature=TRUE;
378 /* Now on reply packets we have to use the state of the original request packet */
379 /* So look up the request value and check the state of packet signature */
380 request_value = mncp_hash_lookup(conversation);
381 if (request_value->packet_signature==TRUE)
384 ncpiph.length &= 0x7fffffff;
385 request_value->packet_signature=TRUE;
389 request_value->packet_signature=FALSE;
395 /* Get request value data */
396 request_value = mncp_hash_lookup(conversation);
397 if (request_value->packet_signature==TRUE)
400 ncpiph.length &= 0x7fffffff;
406 if (!pinfo->fd->flags.visited)
408 if (conversation != NULL)
410 /* find the record telling us the request made that caused
412 request_value = mncp_hash_lookup(conversation);
413 /* if for some reason we have no conversation in our hash, create one */
414 if (request_value==NULL)
416 request_value = mncp_hash_insert(conversation);
421 /* It's not part of any conversation - create a new one. */
422 conversation = conversation_new(&pinfo->src, &pinfo->dst,
423 PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0);
424 request_value = mncp_hash_insert(conversation);
426 /* find the record telling us the request made that caused
428 request_value->packet_signature=FALSE;
432 request_value = mncp_hash_lookup(conversation);
437 /* Record the offset where the NCP common header starts */
438 commhdr = hdr_offset;
440 header.type = tvb_get_ntohs(tvb, commhdr);
441 header.sequence = tvb_get_guint8(tvb, commhdr+2);
442 header.conn_low = tvb_get_guint8(tvb, commhdr+3);
443 header.conn_high = tvb_get_guint8(tvb, commhdr+5);
445 if (check_col(pinfo->cinfo, COL_INFO)) {
446 col_add_fstr(pinfo->cinfo, COL_INFO,
448 val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
452 nw_connection = (header.conn_high << 16) + header.conn_low;
455 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE);
456 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
459 proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature);
460 proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length);
461 if (ncpiph.signature == NCPIP_RQST) {
462 proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version);
463 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize);
464 if (request_value->packet_signature==TRUE)
465 proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 16, 8, FALSE);
467 if (request_value->packet_signature==TRUE)
468 proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 8, 8, FALSE);
471 proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr + 0, 2, header.type);
476 * Process the packet-type-specific header.
478 switch (header.type) {
480 case NCP_BROADCAST_SLOT: /* Server Broadcast */
481 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
482 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
483 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
484 proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, FALSE);
485 proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, FALSE);
488 case NCP_LIP_ECHO: /* Lip Echo Packet */
489 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 13, FALSE);
492 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
494 * XXX - we should keep track of whether there's a burst
495 * outstanding on a connection and, if not, treat the
496 * beginning of the data as a burst header.
498 * The burst header contains:
500 * 4 bytes of little-endian function number:
501 * 1 = read, 2 = write;
503 * 4 bytes of file handle;
507 * 4 bytes of big-endian file offset;
509 * 4 bytes of big-endian byte count.
511 * The data follows for a burst write operation.
513 * The first packet of a burst read reply contains:
515 * 4 bytes of little-endian result code:
521 * 4 bytes of returned byte count (big-endian?).
525 * Each burst of a write request is responded to with a
526 * burst packet with a 2-byte little-endian result code:
528 * 0: Write successful
531 flags = tvb_get_guint8(tvb, commhdr + 2);
532 strcpy(flags_str, "");
535 strcat(flags_str, sep);
536 strcat(flags_str, "ABT");
540 strcat(flags_str, sep);
541 strcat(flags_str, "EOB");
545 strcat(flags_str, sep);
546 strcat(flags_str, "SYS");
548 if (flags_str[0] != '\0')
549 strcat(flags_str, ")");
550 ti = proto_tree_add_uint_format(ncp_tree, hf_ncp_system_flags,
551 tvb, commhdr + 2, 1, flags, "Flags: 0x%04x%s", flags,
553 flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
554 proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
555 tvb, commhdr + 2, 1, FALSE);
556 proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
557 tvb, commhdr + 2, 1, FALSE);
558 proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
559 tvb, commhdr + 2, 1, FALSE);
561 proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
562 tvb, commhdr + 3, 1, FALSE);
563 proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
564 tvb, commhdr + 4, 4, FALSE);
565 proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
566 tvb, commhdr + 8, 4, FALSE);
567 proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
568 tvb, commhdr + 12, 4, FALSE);
569 proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
570 tvb, commhdr + 16, 4, FALSE);
571 proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
572 tvb, commhdr + 20, 2, FALSE);
573 proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
574 tvb, commhdr + 22, 2, FALSE);
575 proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
576 tvb, commhdr + 24, 4, FALSE);
577 proto_tree_add_item(ncp_tree, hf_ncp_data_offset,
578 tvb, commhdr + 28, 4, FALSE);
579 data_len = tvb_get_ntohs(tvb, commhdr + 32);
580 proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
581 tvb, commhdr + 32, 2, data_len);
582 missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
583 proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
584 tvb, commhdr + 34, 2, FALSE);
587 case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
588 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
589 if (length_remaining > 4) {
590 testvar = tvb_get_ntohl(tvb, commhdr+4);
591 if (testvar == 0x4c495020) {
592 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr+4, 13, FALSE);
596 /* otherwise fall through */
598 case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
599 case NCP_SERVICE_REQUEST: /* Server NCP Request */
600 case NCP_SERVICE_REPLY: /* Server NCP Reply */
601 case NCP_WATCHDOG: /* Watchdog Packet */
602 case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
604 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
605 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
606 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE);
611 * Process the packet body.
613 switch (header.type) {
615 case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
616 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
617 if (length_remaining > 4) {
618 testvar = tvb_get_ntohl(tvb, commhdr+4);
619 if (testvar == 0x4c495020) {
620 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
626 case NCP_SERVICE_REQUEST: /* Server NCP Request */
627 case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
628 case NCP_BROADCAST_SLOT: /* Server Broadcast Packet */
629 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
630 if (tvb_get_guint8(tvb, commhdr+6) == 0x68) {
631 subfunction = tvb_get_guint8(tvb, commhdr+7);
632 switch (subfunction) {
634 case 0x02: /* NDS Frag Packet to decode */
635 dissect_nds_request(next_tvb, pinfo,
636 nw_connection, header.sequence,
637 header.type, ncp_tree);
640 case 0x01: /* NDS Ping */
641 dissect_ping_req(next_tvb, pinfo,
642 nw_connection, header.sequence,
643 header.type, ncp_tree);
647 dissect_ncp_request(next_tvb, pinfo,
648 nw_connection, header.sequence,
649 header.type, ncp_tree);
653 dissect_ncp_request(next_tvb, pinfo, nw_connection,
654 header.sequence, header.type, ncp_tree);
658 case NCP_SERVICE_REPLY: /* Server NCP Reply */
659 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
660 nds_defrag(next_tvb, pinfo, nw_connection, header.sequence,
661 header.type, ncp_tree);
664 case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
666 * XXX - this used to call "nds_defrag()", which would
667 * clear out "frags". Was that the right thing to
670 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
671 dissect_ncp_reply(next_tvb, pinfo, nw_connection,
672 header.sequence, header.type, ncp_tree);
675 case NCP_WATCHDOG: /* Watchdog Packet */
677 * XXX - should the completion code be interpreted as
678 * it is in "packet-ncp2222.inc"? If so, this
679 * packet should be handled by "dissect_ncp_reply()".
681 proto_tree_add_item(ncp_tree, hf_ncp_completion_code,
682 tvb, commhdr + 6, 1, TRUE);
683 proto_tree_add_item(ncp_tree, hf_ncp_connection_status,
684 tvb, commhdr + 7, 1, TRUE);
685 proto_tree_add_item(ncp_tree, hf_ncp_slot,
686 tvb, commhdr + 8, 1, TRUE);
687 proto_tree_add_item(ncp_tree, hf_ncp_control_code,
688 tvb, commhdr + 9, 1, TRUE);
690 * Display the rest of the packet as data.
692 if (tvb_offset_exists(tvb, commhdr + 10)) {
693 call_dissector(data_handle,
694 tvb_new_subset(tvb, commhdr + 10, -1, -1),
699 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
702 * System packet; show missing fragments if there
705 offset = commhdr + 36;
706 while (missing_fraglist_count != 0) {
707 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
708 tvb, offset, 4, FALSE);
709 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
710 tvb, offset, 2, FALSE);
711 missing_fraglist_count--;
715 * XXX - do this by using -1 and -1 as the length
716 * arguments to "tvb_new_subset()" and then calling
717 * "tvb_set_reported_length()"? That'll throw an
718 * exception if "data_len" goes past the reported
719 * length of the packet, but that's arguably a
720 * feature in this case.
722 length_remaining = tvb_length_remaining(tvb, commhdr + 36);
723 if (length_remaining > data_len)
724 length_remaining = data_len;
726 call_dissector(data_handle,
727 tvb_new_subset(tvb, commhdr + 36,
728 length_remaining, data_len),
734 case NCP_LIP_ECHO: /* LIP Echo Packet */
735 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
741 proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1,
742 "%s packets not supported yet",
743 val_to_str(header.type, ncp_type_vals,
744 "Unknown type (0x%04x)"));
751 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
753 dissect_ncp_common(tvb, pinfo, tree, FALSE);
757 get_ncp_pdu_len(tvbuff_t *tvb, int offset)
762 * Check the NCP-over-TCP header signature, to make sure it's there.
763 * If it's not there, we cannot trust the next 4 bytes to be a
764 * packet length+"has signature" flag, so we just say the length is
765 * "what remains in the packet".
767 /*if (tvb_get_guint8(tvb, offset)==0xff)
771 signature = tvb_get_ntohl(tvb, offset);
772 if (signature != NCPIP_RQST && signature != NCPIP_RPLY)
773 return tvb_length_remaining(tvb, offset);
776 * Get the length of the NCP-over-TCP packet. Strip off the "has
780 return tvb_get_ntohl(tvb, offset + 4) & 0x7fffffff;
784 dissect_ncp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
786 dissect_ncp_common(tvb, pinfo, tree, TRUE);
790 dissect_ncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
792 tcp_dissect_pdus(tvb, pinfo, tree, ncp_desegment, 8, get_ncp_pdu_len,
793 dissect_ncp_tcp_pdu);
797 proto_register_ncp(void)
800 static hf_register_info hf[] = {
802 { "NCP over IP signature", "ncp.ip.signature",
803 FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
806 { "NCP over IP length", "ncp.ip.length",
807 FT_UINT32, BASE_DEC, NULL, 0x0,
810 { "NCP over IP Version", "ncp.ip.version",
811 FT_UINT32, BASE_DEC, NULL, 0x0,
813 { &hf_ncp_ip_rplybufsize,
814 { "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize",
815 FT_UINT32, BASE_DEC, NULL, 0x0,
817 { &hf_ncp_ip_packetsig,
818 { "NCP over IP Packet Signature", "ncp.ip.packetsig",
819 FT_BYTES, BASE_NONE, NULL, 0x0,
822 { "Type", "ncp.type",
823 FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
824 "NCP message type", HFILL }},
826 { "Sequence Number", "ncp.seq",
827 FT_UINT8, BASE_DEC, NULL, 0x0,
829 { &hf_ncp_connection,
830 { "Connection Number", "ncp.connection",
831 FT_UINT16, BASE_DEC, NULL, 0x0,
834 { "Task Number", "ncp.task",
835 FT_UINT8, BASE_DEC, NULL, 0x0,
837 { &hf_ncp_oplock_flag,
838 { "Oplock Flag", "ncp.oplock_flag",
839 FT_UINT8, BASE_HEX, NULL, 0x0,
841 { &hf_ncp_oplock_handle,
842 { "File Handle", "ncp.oplock_handle",
843 FT_UINT16, BASE_HEX, NULL, 0x0,
845 { &hf_ncp_stream_type,
846 { "Stream Type", "ncp.stream_type",
847 FT_UINT8, BASE_HEX, NULL, 0x0,
848 "Type of burst", HFILL }},
849 { &hf_ncp_system_flags,
850 { "System Flags", "ncp.system_flags",
851 FT_UINT8, BASE_HEX, NULL, 0x0,
853 { &hf_ncp_system_flags_abt,
854 { "ABT", "ncp.system_flags.abt",
855 FT_BOOLEAN, 8, NULL, ABT,
856 "Is this an abort request?", HFILL }},
857 { &hf_ncp_system_flags_eob,
858 { "EOB", "ncp.system_flags.eob",
859 FT_BOOLEAN, 8, NULL, EOB,
860 "Is this the last packet of the burst?", HFILL }},
861 { &hf_ncp_system_flags_sys,
862 { "SYS", "ncp.system_flags.sys",
863 FT_BOOLEAN, 8, NULL, SYS,
864 "Is this a system packet?", HFILL }},
865 { &hf_ncp_src_connection,
866 { "Source Connection ID", "ncp.src_connection",
867 FT_UINT32, BASE_DEC, NULL, 0x0,
868 "The workstation's connection identification number", HFILL }},
869 { &hf_ncp_dst_connection,
870 { "Destination Connection ID", "ncp.dst_connection",
871 FT_UINT32, BASE_DEC, NULL, 0x0,
872 "The server's connection identification number", HFILL }},
873 { &hf_ncp_packet_seqno,
874 { "Packet Sequence Number", "ncp.packet_seqno",
875 FT_UINT32, BASE_DEC, NULL, 0x0,
876 "Sequence number of this packet in a burst", HFILL }},
877 { &hf_ncp_delay_time,
878 { "Delay Time", "ncp.delay_time", /* in 100 us increments */
879 FT_UINT32, BASE_DEC, NULL, 0x0,
880 "Delay time between consecutive packet sends (100 us increments)", HFILL }},
881 { &hf_ncp_burst_seqno,
882 { "Burst Sequence Number", "ncp.burst_seqno",
883 FT_UINT16, BASE_DEC, NULL, 0x0,
884 "Sequence number of this packet in the burst", HFILL }},
886 { "ACK Sequence Number", "ncp.ack_seqno",
887 FT_UINT16, BASE_DEC, NULL, 0x0,
888 "Next expected burst sequence number", HFILL }},
890 { "Burst Length", "ncp.burst_len",
891 FT_UINT32, BASE_DEC, NULL, 0x0,
892 "Total length of data in this burst", HFILL }},
893 { &hf_ncp_data_offset,
894 { "Data Offset", "ncp.data_offset",
895 FT_UINT32, BASE_DEC, NULL, 0x0,
896 "Offset of this packet in the burst", HFILL }},
897 { &hf_ncp_data_bytes,
898 { "Data Bytes", "ncp.data_bytes",
899 FT_UINT16, BASE_DEC, NULL, 0x0,
900 "Number of data bytes in this packet", HFILL }},
901 { &hf_ncp_missing_fraglist_count,
902 { "Missing Fragment List Count", "ncp.missing_fraglist_count",
903 FT_UINT16, BASE_DEC, NULL, 0x0,
904 "Number of missing fragments reported", HFILL }},
905 { &hf_ncp_missing_data_offset,
906 { "Missing Data Offset", "ncp.missing_data_offset",
907 FT_UINT32, BASE_DEC, NULL, 0x0,
908 "Offset of beginning of missing data", HFILL }},
909 { &hf_ncp_missing_data_count,
910 { "Missing Data Count", "ncp.missing_data_count",
911 FT_UINT16, BASE_DEC, NULL, 0x0,
912 "Number of bytes of missing data", HFILL }},
913 { &hf_ncp_completion_code,
914 { "Completion Code", "ncp.completion_code",
915 FT_UINT8, BASE_DEC, NULL, 0x0,
917 { &hf_ncp_connection_status,
918 { "Connection Status", "ncp.connection_status",
919 FT_UINT8, BASE_DEC, NULL, 0x0,
922 { "Slot", "ncp.slot",
923 FT_UINT8, BASE_DEC, NULL, 0x0,
925 { &hf_ncp_control_code,
926 { "Control Code", "ncp.control_code",
927 FT_UINT8, BASE_DEC, NULL, 0x0,
929 { &hf_ncp_fragment_handle,
930 { "Fragment Handle", "ncp.fragger_hndl",
931 FT_UINT16, BASE_HEX, NULL, 0x0,
934 { "Large Internet Packet Echo", "ncp.lip_echo",
935 FT_STRING, BASE_NONE, NULL, 0x0,
939 static gint *ett[] = {
941 &ett_ncp_system_flags,
946 module_t *ncp_module;
948 proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
949 proto_register_field_array(proto_ncp, hf, array_length(hf));
950 proto_register_subtree_array(ett, array_length(ett));
952 ncp_module = prefs_register_protocol(proto_ncp, NULL);
953 prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
954 prefs_register_bool_preference(ncp_module, "desegment",
955 "Desegment all NCP-over-TCP messages spanning multiple segments",
956 "Whether the NCP dissector should desegment all messages spanning multiple TCP segments",
958 prefs_register_bool_preference(ncp_module, "defragment_nds",
959 "Defragment all NDS messages spanning multiple packets",
960 "Whether the NCP dissector should defragment all NDS messages spanning multiple packets",
962 register_init_routine(&mncp_init_protocol);
963 register_postseq_cleanup_routine(&mncp_postseq_cleanup);
967 proto_reg_handoff_ncp(void)
969 dissector_handle_t ncp_handle;
970 dissector_handle_t ncp_tcp_handle;
972 ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
973 ncp_tcp_handle = create_dissector_handle(dissect_ncp_tcp, proto_ncp);
974 dissector_add("tcp.port", TCP_PORT_NCP, ncp_tcp_handle);
975 dissector_add("udp.port", UDP_PORT_NCP, ncp_handle);
976 dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
977 dissector_add("ipx.socket", IPX_SOCKET_NCP, ncp_handle);
979 data_handle = find_dissector("data");