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
14 * Wireshark - Network traffic analyzer
15 * By Gerald Combs <gerald@wireshark.org>
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.
34 ToDo: Find and fix possible memory leak(s):
38 A 40M capture file with mostly NCP frames results
39 in a 400K-800K memory usage increase each time the file is reloaded.
41 (If the NCP dissection is disabled, there is minimal memory usage
42 increase each time the file is reloaded).
49 #ifdef HAVE_SYS_TYPES_H
50 # include <sys/types.h>
53 #ifdef HAVE_NETINET_IN_H
54 # include <netinet/in.h>
59 #include <epan/packet.h>
60 #include <epan/emem.h>
61 #include <epan/prefs.h>
62 #include "packet-ipx.h"
63 #include "packet-tcp.h"
64 #include "packet-ncp-int.h"
65 #include <epan/reassemble.h>
66 #include <epan/conversation.h>
70 static int hf_ncp_ip_ver = -1;
71 static int hf_ncp_ip_length = -1;
72 static int hf_ncp_ip_rplybufsize = -1;
73 static int hf_ncp_ip_sig = -1;
74 static int hf_ncp_ip_packetsig = -1;
75 static int hf_ncp_type = -1;
76 static int hf_ncp_seq = -1;
77 static int hf_ncp_connection = -1;
78 static int hf_ncp_task = -1;
79 static int hf_ncp_stream_type = -1;
80 static int hf_ncp_system_flags = -1;
81 static int hf_ncp_system_flags_abt = -1;
82 static int hf_ncp_system_flags_eob = -1;
83 static int hf_ncp_system_flags_sys = -1;
84 static int hf_ncp_system_flags_bsy = -1;
85 static int hf_ncp_system_flags_lst = -1;
86 static int hf_ncp_src_connection = -1;
87 static int hf_ncp_dst_connection = -1;
88 static int hf_ncp_packet_seqno = -1;
89 static int hf_ncp_delay_time = -1;
90 static int hf_ncp_burst_seqno = -1;
91 static int hf_ncp_ack_seqno = -1;
92 static int hf_ncp_burst_len = -1;
93 static int hf_ncp_burst_offset = -1;
94 static int hf_ncp_data_offset = -1;
95 static int hf_ncp_data_bytes = -1;
96 static int hf_ncp_missing_fraglist_count = -1;
97 static int hf_ncp_missing_data_offset = -1;
98 static int hf_ncp_missing_data_count = -1;
99 static int hf_ncp_oplock_flag = -1;
100 static int hf_ncp_oplock_handle = -1;
101 static int hf_ncp_completion_code = -1;
102 static int hf_ncp_connection_status = -1;
103 static int hf_ncp_slot = -1;
104 static int hf_ncp_control_code = -1;
105 static int hf_ncp_fragment_handle = -1;
106 static int hf_lip_echo = -1;
107 static int hf_ncp_burst_command = -1;
108 static int hf_ncp_burst_file_handle = -1;
109 static int hf_ncp_burst_reserved = -1;
113 gint ett_nds_segments = -1;
114 gint ett_nds_segment = -1;
115 static gint ett_ncp_system_flags = -1;
117 static struct novell_tap ncp_tap;
118 static struct ncp_common_header header;
119 static struct ncp_common_header *ncp_hdr;
121 /* Tables for reassembly of fragments. */
122 GHashTable *nds_fragment_table = NULL;
123 GHashTable *nds_reassembled_table = NULL;
124 dissector_handle_t nds_data_handle;
126 /* desegmentation of NCP over TCP */
127 static gboolean ncp_desegment = TRUE;
129 static dissector_handle_t data_handle;
131 #define TCP_PORT_NCP 524
132 #define UDP_PORT_NCP 524
134 #define NCP_RQST_HDR_LENGTH 7
135 #define NCP_RPLY_HDR_LENGTH 8
137 /* These are the header structures to handle NCP over IP */
138 #define NCPIP_RQST 0x446d6454 /* "DmdT" */
139 #define NCPIP_RPLY 0x744e6350 /* "tNcP" */
141 struct ncp_ip_header {
146 /* This header only appears on NCP over IP request packets */
147 struct ncp_ip_rqhdr {
152 static const value_string ncp_ip_signature[] = {
153 { NCPIP_RQST, "Demand Transport (Request)" },
154 { NCPIP_RPLY, "Transport is NCP (Reply)" },
158 static const value_string burst_command[] = {
159 { 0x01000000, "Burst Read" },
160 { 0x02000000, "Burst Write" },
164 /* The information in this module comes from:
165 NetWare LAN Analysis, Second Edition
166 Laura A. Chappell and Dan E. Hakes
167 (c) 1994 Novell, Inc.
168 Novell Press, San Jose.
171 And from the ncpfs source code by Volker Lendecke
174 Programmer's Guide to the NetWare Core Protocol
175 Steve Conner & Diane Conner
176 (c) 1996 by Steve Conner & Diane Conner
177 Published by Annabooks, San Diego, California
181 http:developer.novell.com
186 static const value_string ncp_type_vals[] = {
187 { NCP_ALLOCATE_SLOT, "Create a service connection" },
188 { NCP_SERVICE_REQUEST, "Service request" },
189 { NCP_SERVICE_REPLY, "Service reply" },
190 { NCP_WATCHDOG, "Watchdog" },
191 { NCP_DEALLOCATE_SLOT, "Destroy service connection" },
192 { NCP_BROADCAST_SLOT, "Server Broadcast" },
193 { NCP_BURST_MODE_XFER, "Burst mode transfer" },
194 { NCP_POSITIVE_ACK, "Request being processed" },
195 { NCP_LIP_ECHO, "Large Internet Packet Echo" },
199 static const value_string ncp_oplock_vals[] = {
200 { 0x21, "Message Waiting" },
201 { 0x24, "Clear Op-lock" },
205 /* Conversation Struct so we can detect NCP server sessions */
208 conversation_t *conversation;
209 guint32 nwconnection;
213 /* Store the packet number for the start of the NCP session.
214 * Note sessions are defined as
215 * NCP Connection + NCP Task == Unique NCP server session
216 * It is normal for multiple sessions per connection to exist
217 * These are normally different applications running on multi-tasking
221 guint32 session_start_packet_num;
224 static GHashTable *mncp_rhash = NULL;
228 mncp_equal(gconstpointer v, gconstpointer v2)
230 const mncp_rhash_key *val1 = (const mncp_rhash_key*)v;
231 const mncp_rhash_key *val2 = (const mncp_rhash_key*)v2;
233 if (val1->conversation == val2->conversation && val1->nwconnection == val2->nwconnection && val1->nwtask == val2->nwtask) {
240 mncp_hash(gconstpointer v)
242 const mncp_rhash_key *mncp_key = (const mncp_rhash_key*)v;
243 return GPOINTER_TO_UINT(mncp_key->conversation)+mncp_key->nwconnection+mncp_key->nwtask;
246 /* Initializes the hash table each time a new
247 * file is loaded or re-loaded in wireshark */
249 mncp_init_protocol(void)
252 g_hash_table_destroy(mncp_rhash);
254 mncp_rhash = g_hash_table_new(mncp_hash, mncp_equal);
257 /* After the sequential run, we don't need the ncp_request hash and keys
258 * anymore; the lookups have already been done and the vital info
259 * saved in the reply-packets' private_data in the frame_data struct. */
261 mncp_postseq_cleanup(void)
265 static mncp_rhash_value*
266 mncp_hash_insert(conversation_t *conversation, guint32 nwconnection, guint8 nwtask, packet_info *pinfo)
269 mncp_rhash_value *value;
271 /* Now remember the request, so we can find it if we later
272 a reply to it. Track by conversation, connection, and task number.
273 in NetWare these values determine each unique session */
274 key = se_alloc(sizeof(mncp_rhash_key));
275 key->conversation = conversation;
276 key->nwconnection = nwconnection;
277 key->nwtask = nwtask;
279 value = se_alloc(sizeof(mncp_rhash_value));
281 g_hash_table_insert(mncp_rhash, key, value);
283 if (ncp_echo_conn && nwconnection != 65535) {
284 expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE, PI_CHAT, "Detected New Server Session. Connection %d, Task %d", nwconnection, nwtask);
285 value->session_start_packet_num = pinfo->fd->num;
291 /* Returns the ncp_rec*, or NULL if not found. */
292 static mncp_rhash_value*
293 mncp_hash_lookup(conversation_t *conversation, guint32 nwconnection, guint8 nwtask)
297 key.conversation = conversation;
298 key.nwconnection = nwconnection;
301 return g_hash_table_lookup(mncp_rhash, &key);
305 * Burst packet system flags.
307 #define ABT 0x04 /* Abort request */
308 #define BSY 0x08 /* Server Busy */
309 #define EOB 0x10 /* End of burst */
310 #define LST 0x40 /* Include Fragment List */
311 #define SYS 0x80 /* System packet */
314 dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
317 proto_tree *ncp_tree = NULL;
319 struct ncp_ip_header ncpiph;
320 struct ncp_ip_rqhdr ncpiphrq;
321 guint16 ncp_burst_seqno, ncp_ack_seqno;
323 proto_tree *flags_tree = NULL;
327 gint length_remaining;
329 guint32 testvar = 0, ncp_burst_command, burst_len, burst_off, burst_file;
331 guint32 nw_connection = 0, data_offset;
332 guint16 data_len = 0;
333 guint16 missing_fraglist_count = 0;
334 mncp_rhash_value *request_value = NULL;
335 conversation_t *conversation;
336 proto_item *expert_item;
338 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
339 col_clear(pinfo->cinfo, COL_INFO);
343 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, ENC_NA);
344 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
346 if (tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RQST && tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RPLY)
348 /* Get NCPIP Header data */
349 ncpiph.signature = tvb_get_ntohl(tvb, commhdr);
350 proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, commhdr, 4, ncpiph.signature);
351 ncpiph.length = (0x7fffffff & tvb_get_ntohl(tvb, commhdr+4));
352 proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, commhdr+4, 4, ncpiph.length);
354 if (ncpiph.signature == NCPIP_RQST) {
355 ncpiphrq.version = tvb_get_ntohl(tvb, commhdr);
356 proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, commhdr, 4, ncpiphrq.version);
358 ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, commhdr);
359 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, commhdr, 4, ncpiphrq.rplybufsize);
362 /* Check to see if this is a valid offset, otherwise increment for packet signature */
363 if (match_strval(tvb_get_ntohs(tvb, commhdr), ncp_type_vals)==NULL) {
364 /* Check to see if we have a valid type after packet signature length */
365 if (match_strval(tvb_get_ntohs(tvb, commhdr+8), ncp_type_vals)!=NULL) {
366 proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, commhdr, 8, ENC_NA);
371 /* Initialize this structure, we use it below */
372 memset(&ncpiph, 0, sizeof(ncpiph));
375 header.type = tvb_get_ntohs(tvb, commhdr);
376 header.sequence = tvb_get_guint8(tvb, commhdr+2);
377 header.conn_low = tvb_get_guint8(tvb, commhdr+3);
378 header.task = tvb_get_guint8(tvb, commhdr+4);
379 header.conn_high = tvb_get_guint8(tvb, commhdr+5);
380 proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr, 2, header.type);
381 nw_connection = (header.conn_high*256)+header.conn_low;
383 /* Ok, we need to track the conversation so that we can
384 * determine if a new server session is occuring for this
387 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
388 PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport,
390 if ((ncpiph.length & 0x80000000) || ncpiph.signature == NCPIP_RPLY) {
391 /* First time through we will record the initial connection and task
394 if (!pinfo->fd->flags.visited) {
395 if (conversation != NULL) {
396 /* find the record telling us the
397 * request made that caused this
400 request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
401 /* if for some reason we have no
402 * conversation in our hash, create
404 if (request_value == NULL) {
405 request_value = mncp_hash_insert(conversation, nw_connection, header.task, pinfo);
408 /* It's not part of any conversation
409 * - create a new one.
411 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
412 &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0);
413 request_value = mncp_hash_insert(conversation, nw_connection, header.task, pinfo);
415 /* If this is a request packet then we
416 * might have a new task
418 if (ncpiph.signature == NCPIP_RPLY) {
419 /* Now on reply packets we have to
420 * use the state of the original
421 * request packet, so look up the
422 * request value and check the task number
424 request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
427 /* Get request value data */
428 request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
430 if ((request_value->session_start_packet_num == pinfo->fd->num) && ncp_echo_conn)
432 expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE, PI_CHAT, "Detected New Server Session. Connection %d, Task %d", nw_connection, header.task);
437 if (!pinfo->fd->flags.visited) {
438 if (conversation != NULL) {
439 /* find the record telling us the
440 * request made that caused this
443 request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
444 /* if for some reason we have no
445 * conversation in our hash, create
447 if (request_value == NULL) {
448 request_value = mncp_hash_insert(conversation, nw_connection, header.task, pinfo);
451 /* It's not part of any conversation
452 * - create a new one.
454 conversation = conversation_new(pinfo->fd->num, &pinfo->src,
455 &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0);
456 request_value = mncp_hash_insert(conversation, nw_connection, header.task, pinfo);
458 /* find the record telling us the request
459 * made that caused this reply
462 request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
464 if ((request_value->session_start_packet_num == pinfo->fd->num) && ncp_echo_conn)
466 expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE, PI_CHAT, "Detected New Server Session. Connection %d, Task %d", nw_connection, header.task);
472 tap_queue_packet(ncp_tap.hdr, pinfo, ncp_hdr);
474 if (check_col(pinfo->cinfo, COL_INFO)) {
475 col_add_str(pinfo->cinfo, COL_INFO,
476 val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
480 * Process the packet-type-specific header.
482 switch (header.type) {
484 case NCP_BROADCAST_SLOT: /* Server Broadcast */
485 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
486 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
487 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, ENC_BIG_ENDIAN);
488 proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, tvb_get_guint8(tvb, commhdr+9));
489 proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, ENC_BIG_ENDIAN);
490 if ((tvb_get_guint8(tvb, commhdr+9)==0x24) && ncp_echo_file)
492 expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE, PI_CHAT, "Server requesting station to clear oplock on handle - %08x", tvb_get_ntohl(tvb, commhdr+10));
496 case NCP_LIP_ECHO: /* Lip Echo Packet */
497 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 13, ENC_ASCII|ENC_NA);
500 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
502 * XXX - we should keep track of whether there's a burst
503 * outstanding on a connection and, if not, treat the
504 * beginning of the data as a burst header.
506 * The burst header contains:
508 * 4 bytes of little-endian function number:
509 * 1 = read, 2 = write;
511 * 4 bytes of file handle;
515 * 4 bytes of big-endian file offset;
517 * 4 bytes of big-endian byte count.
519 * The data follows for a burst write operation.
521 * The first packet of a burst read reply contains:
523 * 4 bytes of little-endian result code:
529 * 4 bytes of returned byte count (big-endian?).
533 * Each burst of a write request is responded to with a
534 * burst packet with a 2-byte little-endian result code:
536 * 0: Write successful
539 flags = tvb_get_guint8(tvb, commhdr + 2);
541 ti = proto_tree_add_uint(ncp_tree, hf_ncp_system_flags,
542 tvb, commhdr + 2, 1, flags);
543 flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
545 proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
546 tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
548 proto_item_append_text(ti, " ABT");
552 proto_tree_add_item(flags_tree, hf_ncp_system_flags_bsy,
553 tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
555 proto_item_append_text(ti, " BSY");
559 proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
560 tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
562 proto_item_append_text(ti, " EOB");
566 proto_tree_add_item(flags_tree, hf_ncp_system_flags_lst,
567 tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
569 proto_item_append_text(ti, " LST");
573 proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
574 tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
576 proto_item_append_text(ti, " SYS");
581 proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
582 tvb, commhdr + 3, 1, ENC_BIG_ENDIAN);
583 proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
584 tvb, commhdr + 4, 4, ENC_BIG_ENDIAN);
585 proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
586 tvb, commhdr + 8, 4, ENC_BIG_ENDIAN);
587 proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
588 tvb, commhdr + 12, 4, ENC_BIG_ENDIAN);
589 proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
590 tvb, commhdr + 16, 4, ENC_BIG_ENDIAN);
591 ncp_burst_seqno = tvb_get_ntohs(tvb, commhdr+20);
592 proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
593 tvb, commhdr + 20, 2, ENC_BIG_ENDIAN);
594 ncp_ack_seqno = tvb_get_ntohs(tvb, commhdr+22);
595 proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
596 tvb, commhdr + 22, 2, ENC_BIG_ENDIAN);
597 proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
598 tvb, commhdr + 24, 4, ENC_BIG_ENDIAN);
599 data_offset = tvb_get_ntohl(tvb, commhdr + 28);
600 proto_tree_add_uint(ncp_tree, hf_ncp_data_offset,
601 tvb, commhdr + 28, 4, data_offset);
602 data_len = tvb_get_ntohs(tvb, commhdr + 32);
603 proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
604 tvb, commhdr + 32, 2, data_len);
605 missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
606 proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
607 tvb, commhdr + 34, 2, ENC_BIG_ENDIAN);
608 offset = commhdr + 36;
609 if (!(flags & SYS) && ncp_burst_seqno == ncp_ack_seqno &&
612 * This is either a Burst Read or Burst Write
613 * command. The data length includes the burst
614 * mode header, plus any data in the command
615 * (there shouldn't be any in a read, but there
616 * might be some in a write).
620 ncp_burst_command = tvb_get_ntohl(tvb, offset);
621 proto_tree_add_item(ncp_tree, hf_ncp_burst_command,
622 tvb, offset, 4, ENC_BIG_ENDIAN);
628 burst_file = tvb_get_ntohl(tvb, offset);
629 proto_tree_add_item(ncp_tree, hf_ncp_burst_file_handle,
630 tvb, offset, 4, ENC_BIG_ENDIAN);
636 proto_tree_add_item(ncp_tree, hf_ncp_burst_reserved,
637 tvb, offset, 8, ENC_NA);
643 burst_off = tvb_get_ntohl(tvb, offset);
644 proto_tree_add_uint(ncp_tree, hf_ncp_burst_offset,
645 tvb, offset, 4, burst_off);
651 burst_len = tvb_get_ntohl(tvb, offset);
652 proto_tree_add_uint(ncp_tree, hf_ncp_burst_len,
653 tvb, offset, 4, burst_len);
657 if (check_col(pinfo->cinfo, COL_INFO)) {
658 col_add_fstr(pinfo->cinfo, COL_INFO,
659 "%s %d bytes starting at offset %d in file 0x%08x",
660 val_to_str(ncp_burst_command,
661 burst_command, "Unknown (0x%08x)"),
662 burst_len, burst_off, burst_file);
666 if (tvb_get_guint8(tvb, commhdr + 2) & 0x10) {
667 col_set_str(pinfo->cinfo, COL_INFO, "End of Burst");
672 case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
673 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
674 if (length_remaining > 4) {
675 testvar = tvb_get_ntohl(tvb, commhdr+4);
676 if (testvar == 0x4c495020) {
677 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr+4, 13, ENC_ASCII|ENC_NA);
681 /* otherwise fall through */
683 case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
684 case NCP_SERVICE_REQUEST: /* Server NCP Request */
685 case NCP_SERVICE_REPLY: /* Server NCP Reply */
686 case NCP_WATCHDOG: /* Watchdog Packet */
687 case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
689 proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
690 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
691 proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, ENC_BIG_ENDIAN);
696 * Process the packet body.
698 switch (header.type) {
700 case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */
701 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
702 if (length_remaining > 4) {
703 testvar = tvb_get_ntohl(tvb, commhdr+4);
704 if (testvar == 0x4c495020) {
705 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
710 next_tvb = tvb_new_subset_remaining(tvb, commhdr);
711 dissect_ncp_request(next_tvb, pinfo, nw_connection,
712 header.sequence, header.type, ncp_tree);
715 case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */
716 next_tvb = tvb_new_subset_remaining(tvb, commhdr);
717 dissect_ncp_request(next_tvb, pinfo, nw_connection,
718 header.sequence, header.type, ncp_tree);
721 case NCP_SERVICE_REQUEST: /* Server NCP Request */
722 case NCP_BROADCAST_SLOT: /* Server Broadcast Packet */
723 next_tvb = tvb_new_subset_remaining(tvb, commhdr);
724 if (tvb_get_guint8(tvb, commhdr+6) == 0x68) {
725 subfunction = tvb_get_guint8(tvb, commhdr+7);
726 switch (subfunction) {
728 case 0x02: /* NDS Frag Packet to decode */
729 dissect_nds_request(next_tvb, pinfo,
730 nw_connection, header.sequence,
731 header.type, ncp_tree);
734 case 0x01: /* NDS Ping */
735 dissect_ping_req(next_tvb, pinfo,
736 nw_connection, header.sequence,
737 header.type, ncp_tree);
741 dissect_ncp_request(next_tvb, pinfo,
742 nw_connection, header.sequence,
743 header.type, ncp_tree);
747 dissect_ncp_request(next_tvb, pinfo, nw_connection,
748 header.sequence, header.type, ncp_tree);
752 case NCP_SERVICE_REPLY: /* Server NCP Reply */
753 next_tvb = tvb_new_subset_remaining(tvb, commhdr);
754 nds_defrag(next_tvb, pinfo, nw_connection, header.sequence,
755 header.type, ncp_tree, &ncp_tap);
758 case NCP_POSITIVE_ACK: /* Positive Acknowledgement */
760 * XXX - this used to call "nds_defrag()", which would
761 * clear out "frags". Was that the right thing to
764 next_tvb = tvb_new_subset_remaining(tvb, commhdr);
765 dissect_ncp_reply(next_tvb, pinfo, nw_connection,
766 header.sequence, header.type, ncp_tree, &ncp_tap);
769 case NCP_WATCHDOG: /* Watchdog Packet */
771 * XXX - should the completion code be interpreted as
772 * it is in "packet-ncp2222.inc"? If so, this
773 * packet should be handled by "dissect_ncp_reply()".
775 proto_tree_add_item(ncp_tree, hf_ncp_completion_code,
776 tvb, commhdr + 6, 1, ENC_LITTLE_ENDIAN);
777 proto_tree_add_item(ncp_tree, hf_ncp_connection_status,
778 tvb, commhdr + 7, 1, ENC_LITTLE_ENDIAN);
779 proto_tree_add_item(ncp_tree, hf_ncp_slot,
780 tvb, commhdr + 8, 1, ENC_LITTLE_ENDIAN);
781 proto_tree_add_item(ncp_tree, hf_ncp_control_code,
782 tvb, commhdr + 9, 1, ENC_LITTLE_ENDIAN);
784 * Display the rest of the packet as data.
786 if (tvb_offset_exists(tvb, commhdr + 10)) {
787 call_dissector(data_handle,
788 tvb_new_subset_remaining(tvb, commhdr + 10),
793 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
796 * System packet; show missing fragments if there
799 while (missing_fraglist_count != 0) {
800 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
801 tvb, offset, 4, ENC_BIG_ENDIAN);
803 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
804 tvb, offset, 2, ENC_BIG_ENDIAN);
806 missing_fraglist_count--;
810 * XXX - do this by using -1 and -1 as the length
811 * arguments to "tvb_new_subset()" and then calling
812 * "tvb_set_reported_length()"? That'll throw an
813 * exception if "data_len" goes past the reported
814 * length of the packet, but that's arguably a
815 * feature in this case.
817 length_remaining = tvb_length_remaining(tvb, offset);
818 if (length_remaining > data_len)
819 length_remaining = data_len;
821 call_dissector(data_handle,
822 tvb_new_subset(tvb, offset,
823 length_remaining, data_len),
829 case NCP_LIP_ECHO: /* LIP Echo Packet */
830 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
835 expert_item = proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1,
836 "%s packets not supported yet",
837 val_to_str(header.type, ncp_type_vals,
838 "Unknown type (0x%04x)"));
840 expert_add_info_format(pinfo, expert_item, PI_UNDECODED, PI_NOTE, "%s packets not supported yet", val_to_str(header.type, ncp_type_vals,
841 "Unknown type (0x%04x)"));
848 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
850 dissect_ncp_common(tvb, pinfo, tree, FALSE);
854 get_ncp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
859 * Check the NCP-over-TCP header signature, to make sure it's there.
860 * If it's not there, we cannot trust the next 4 bytes to be a
861 * packet length+"has signature" flag, so we just say the length is
862 * "what remains in the packet".
864 signature = tvb_get_ntohl(tvb, offset);
865 if (signature != NCPIP_RQST && signature != NCPIP_RPLY)
866 return tvb_length_remaining(tvb, offset);
869 * Get the length of the NCP-over-TCP packet. Strip off the "has
873 return tvb_get_ntohl(tvb, offset + 4) & 0x7fffffff;
877 dissect_ncp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
879 dissect_ncp_common(tvb, pinfo, tree, TRUE);
883 dissect_ncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
885 tcp_dissect_pdus(tvb, pinfo, tree, ncp_desegment, 8, get_ncp_pdu_len,
886 dissect_ncp_tcp_pdu);
890 proto_register_ncp(void)
892 static hf_register_info hf[] = {
894 { "NCP over IP signature", "ncp.ip.signature",
895 FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
898 { "NCP over IP length", "ncp.ip.length",
899 FT_UINT32, BASE_DEC, NULL, 0x0,
902 { "NCP over IP Version", "ncp.ip.version",
903 FT_UINT32, BASE_DEC, NULL, 0x0,
905 { &hf_ncp_ip_rplybufsize,
906 { "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize",
907 FT_UINT32, BASE_DEC, NULL, 0x0,
909 { &hf_ncp_ip_packetsig,
910 { "NCP over IP Packet Signature", "ncp.ip.packetsig",
911 FT_BYTES, BASE_NONE, NULL, 0x0,
914 { "Type", "ncp.type",
915 FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
916 "NCP message type", HFILL }},
918 { "Sequence Number", "ncp.seq",
919 FT_UINT8, BASE_DEC, NULL, 0x0,
921 { &hf_ncp_connection,
922 { "Connection Number", "ncp.connection",
923 FT_UINT16, BASE_DEC, NULL, 0x0,
926 { "Task Number", "ncp.task",
927 FT_UINT8, BASE_DEC, NULL, 0x0,
929 { &hf_ncp_oplock_flag,
930 { "Broadcast Message Flag", "ncp.msg_flag",
931 FT_UINT8, BASE_HEX, VALS(ncp_oplock_vals), 0x0,
933 { &hf_ncp_oplock_handle,
934 { "File Handle", "ncp.oplock_handle",
935 FT_UINT16, BASE_HEX, NULL, 0x0,
937 { &hf_ncp_stream_type,
938 { "Stream Type", "ncp.stream_type",
939 FT_UINT8, BASE_HEX, NULL, 0x0,
940 "Type of burst", HFILL }},
941 { &hf_ncp_system_flags,
942 { "System Flags", "ncp.system_flags",
943 FT_UINT8, BASE_HEX, NULL, 0x0,
945 { &hf_ncp_system_flags_abt,
946 { "ABT", "ncp.system_flags.abt",
947 FT_BOOLEAN, 8, NULL, ABT,
948 "Is this an abort request?", HFILL }},
949 { &hf_ncp_system_flags_eob,
950 { "EOB", "ncp.system_flags.eob",
951 FT_BOOLEAN, 8, NULL, EOB,
952 "Is this the last packet of the burst?", HFILL }},
953 { &hf_ncp_system_flags_sys,
954 { "SYS", "ncp.system_flags.sys",
955 FT_BOOLEAN, 8, NULL, SYS,
956 "Is this a system packet?", HFILL }},
957 { &hf_ncp_system_flags_bsy,
958 { "BSY", "ncp.system_flags.bsy",
959 FT_BOOLEAN, 8, NULL, BSY,
960 "Is the server busy?", HFILL }},
961 { &hf_ncp_system_flags_lst,
962 { "LST", "ncp.system_flags.lst",
963 FT_BOOLEAN, 8, NULL, LST,
964 "Return Fragment List?", HFILL }},
965 { &hf_ncp_src_connection,
966 { "Source Connection ID", "ncp.src_connection",
967 FT_UINT32, BASE_DEC, NULL, 0x0,
968 "The workstation's connection identification number", HFILL }},
969 { &hf_ncp_dst_connection,
970 { "Destination Connection ID", "ncp.dst_connection",
971 FT_UINT32, BASE_DEC, NULL, 0x0,
972 "The server's connection identification number", HFILL }},
973 { &hf_ncp_packet_seqno,
974 { "Packet Sequence Number", "ncp.packet_seqno",
975 FT_UINT32, BASE_DEC, NULL, 0x0,
976 "Sequence number of this packet in a burst", HFILL }},
977 { &hf_ncp_delay_time,
978 { "Delay Time", "ncp.delay_time", /* in 100 us increments */
979 FT_UINT32, BASE_DEC, NULL, 0x0,
980 "Delay time between consecutive packet sends (100 us increments)", HFILL }},
981 { &hf_ncp_burst_seqno,
982 { "Burst Sequence Number", "ncp.burst_seqno",
983 FT_UINT16, BASE_DEC, NULL, 0x0,
984 "Sequence number of this packet in the burst", HFILL }},
986 { "ACK Sequence Number", "ncp.ack_seqno",
987 FT_UINT16, BASE_DEC, NULL, 0x0,
988 "Next expected burst sequence number", HFILL }},
990 { "Burst Length", "ncp.burst_len",
991 FT_UINT32, BASE_DEC, NULL, 0x0,
992 "Total length of data in this burst", HFILL }},
993 { &hf_ncp_burst_offset,
994 { "Burst Offset", "ncp.burst_offset",
995 FT_UINT32, BASE_DEC, NULL, 0x0,
996 "Offset of data in the burst", HFILL }},
997 { &hf_ncp_data_offset,
998 { "Data Offset", "ncp.data_offset",
999 FT_UINT32, BASE_DEC, NULL, 0x0,
1000 "Offset of this packet", HFILL }},
1001 { &hf_ncp_data_bytes,
1002 { "Data Bytes", "ncp.data_bytes",
1003 FT_UINT16, BASE_DEC, NULL, 0x0,
1004 "Number of data bytes in this packet", HFILL }},
1005 { &hf_ncp_missing_fraglist_count,
1006 { "Missing Fragment List Count", "ncp.missing_fraglist_count",
1007 FT_UINT16, BASE_DEC, NULL, 0x0,
1008 "Number of missing fragments reported", HFILL }},
1009 { &hf_ncp_missing_data_offset,
1010 { "Missing Data Offset", "ncp.missing_data_offset",
1011 FT_UINT32, BASE_DEC, NULL, 0x0,
1012 "Offset of beginning of missing data", HFILL }},
1013 { &hf_ncp_missing_data_count,
1014 { "Missing Data Count", "ncp.missing_data_count",
1015 FT_UINT16, BASE_DEC, NULL, 0x0,
1016 "Number of bytes of missing data", HFILL }},
1017 { &hf_ncp_completion_code,
1018 { "Completion Code", "ncp.completion_code",
1019 FT_UINT8, BASE_DEC, NULL, 0x0,
1021 { &hf_ncp_connection_status,
1022 { "Connection Status", "ncp.connection_status",
1023 FT_UINT8, BASE_DEC, NULL, 0x0,
1026 { "Slot", "ncp.slot",
1027 FT_UINT8, BASE_DEC, NULL, 0x0,
1029 { &hf_ncp_control_code,
1030 { "Control Code", "ncp.control_code",
1031 FT_UINT8, BASE_DEC, NULL, 0x0,
1033 { &hf_ncp_fragment_handle,
1034 { "Fragment Handle", "ncp.fragger_hndl",
1035 FT_UINT16, BASE_HEX, NULL, 0x0,
1038 { "Large Internet Packet Echo", "ncp.lip_echo",
1039 FT_STRING, BASE_NONE, NULL, 0x0,
1041 { &hf_ncp_burst_command,
1042 { "Burst Command", "ncp.burst_command",
1043 FT_UINT32, BASE_HEX, VALS(burst_command), 0x0,
1044 "Packet Burst Command", HFILL }},
1045 { &hf_ncp_burst_file_handle,
1046 { "Burst File Handle", "ncp.file_handle",
1047 FT_UINT32, BASE_HEX, NULL, 0x0,
1048 "Packet Burst File Handle", HFILL }},
1049 { &hf_ncp_burst_reserved,
1050 { "Reserved", "ncp.burst_reserved",
1051 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1054 static gint *ett[] = {
1056 &ett_ncp_system_flags,
1061 module_t *ncp_module;
1063 proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
1064 proto_register_field_array(proto_ncp, hf, array_length(hf));
1065 proto_register_subtree_array(ett, array_length(ett));
1067 ncp_module = prefs_register_protocol(proto_ncp, NULL);
1068 prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
1069 prefs_register_bool_preference(ncp_module, "desegment",
1070 "Reassemble NCP-over-TCP messages spanning multiple TCP segments",
1071 "Whether the NCP dissector should reassemble messages spanning multiple TCP segments."
1072 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1074 prefs_register_bool_preference(ncp_module, "defragment_nds",
1075 "Reassemble fragmented NDS messages spanning multiple reply packets",
1076 "Whether the NCP dissector should defragment NDS messages spanning multiple reply packets.",
1078 prefs_register_bool_preference(ncp_module, "newstyle",
1079 "Dissect New Netware Information Structure",
1080 "Dissect the NetWare Information Structure as NetWare 5.x or higher or as older NetWare 3.x.",
1082 prefs_register_bool_preference(ncp_module, "eid_2_expert",
1083 "Expert: EID to Name lookups?",
1084 "Whether the NCP dissector should echo the NDS Entry ID to name resolves to the expert table.",
1086 prefs_register_bool_preference(ncp_module, "connection_2_expert",
1087 "Expert: NCP Connections?",
1088 "Whether the NCP dissector should echo NCP connection information to the expert table.",
1090 prefs_register_bool_preference(ncp_module, "error_2_expert",
1091 "Expert: NCP Errors?",
1092 "Whether the NCP dissector should echo protocol errors to the expert table.",
1094 prefs_register_bool_preference(ncp_module, "server_2_expert",
1095 "Expert: Server Information?",
1096 "Whether the NCP dissector should echo server information to the expert table.",
1098 prefs_register_bool_preference(ncp_module, "file_2_expert",
1099 "Expert: File Information?",
1100 "Whether the NCP dissector should echo file open/close/oplock information to the expert table.",
1102 register_init_routine(&mncp_init_protocol);
1103 ncp_tap.stat=register_tap("ncp_srt");
1104 ncp_tap.hdr=register_tap("ncp_hdr");
1105 register_postseq_cleanup_routine(&mncp_postseq_cleanup);
1109 proto_reg_handoff_ncp(void)
1111 dissector_handle_t ncp_handle;
1112 dissector_handle_t ncp_tcp_handle;
1114 ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
1115 ncp_tcp_handle = create_dissector_handle(dissect_ncp_tcp, proto_ncp);
1116 dissector_add_uint("tcp.port", TCP_PORT_NCP, ncp_tcp_handle);
1117 dissector_add_uint("udp.port", UDP_PORT_NCP, ncp_handle);
1118 dissector_add_uint("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
1119 dissector_add_uint("ipx.socket", IPX_SOCKET_NCP, ncp_handle);
1121 data_handle = find_dissector("data");