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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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).
51 #include <epan/packet.h>
52 #include <epan/wmem/wmem.h>
53 #include <epan/prefs.h>
54 #include "packet-ipx.h"
55 #include "packet-tcp.h"
56 #include "packet-ncp-int.h"
57 #include <epan/reassemble.h>
58 #include <epan/conversation.h>
62 static int hf_ncp_ip_ver
= -1;
63 static int hf_ncp_ip_length
= -1;
64 static int hf_ncp_ip_rplybufsize
= -1;
65 static int hf_ncp_ip_sig
= -1;
66 static int hf_ncp_ip_packetsig
= -1;
67 static int hf_ncp_type
= -1;
68 static int hf_ncp_seq
= -1;
69 static int hf_ncp_connection
= -1;
70 static int hf_ncp_task
= -1;
71 static int hf_ncp_stream_type
= -1;
72 static int hf_ncp_system_flags
= -1;
73 static int hf_ncp_system_flags_abt
= -1;
74 static int hf_ncp_system_flags_eob
= -1;
75 static int hf_ncp_system_flags_sys
= -1;
76 static int hf_ncp_system_flags_bsy
= -1;
77 static int hf_ncp_system_flags_lst
= -1;
78 static int hf_ncp_src_connection
= -1;
79 static int hf_ncp_dst_connection
= -1;
80 static int hf_ncp_packet_seqno
= -1;
81 static int hf_ncp_delay_time
= -1;
82 static int hf_ncp_burst_seqno
= -1;
83 static int hf_ncp_ack_seqno
= -1;
84 static int hf_ncp_burst_len
= -1;
85 static int hf_ncp_burst_offset
= -1;
86 static int hf_ncp_data_offset
= -1;
87 static int hf_ncp_data_bytes
= -1;
88 static int hf_ncp_missing_fraglist_count
= -1;
89 static int hf_ncp_missing_data_offset
= -1;
90 static int hf_ncp_missing_data_count
= -1;
91 static int hf_ncp_oplock_flag
= -1;
92 static int hf_ncp_oplock_handle
= -1;
93 static int hf_ncp_completion_code
= -1;
94 static int hf_ncp_connection_status
= -1;
95 static int hf_ncp_slot
= -1;
96 static int hf_ncp_control_code
= -1;
97 /* static int hf_ncp_fragment_handle = -1; */
98 static int hf_lip_echo
= -1;
99 static int hf_ncp_burst_command
= -1;
100 static int hf_ncp_burst_file_handle
= -1;
101 static int hf_ncp_burst_reserved
= -1;
105 gint ett_nds_segments
= -1;
106 gint ett_nds_segment
= -1;
107 static gint ett_ncp_system_flags
= -1;
109 static expert_field ei_ncp_oplock_handle
= EI_INIT
;
110 static expert_field ei_ncp_new_server_session
= EI_INIT
;
111 static expert_field ei_ncp_type
= EI_INIT
;
113 static struct novell_tap ncp_tap
;
114 static struct ncp_common_header header
;
115 static struct ncp_common_header
*ncp_hdr
;
117 dissector_handle_t nds_data_handle
;
119 /* desegmentation of NCP over TCP */
120 static gboolean ncp_desegment
= TRUE
;
122 static dissector_handle_t data_handle
;
124 #define TCP_PORT_NCP 524
125 #define UDP_PORT_NCP 524
127 #define NCP_RQST_HDR_LENGTH 7
128 #define NCP_RPLY_HDR_LENGTH 8
130 /* These are the header structures to handle NCP over IP */
131 #define NCPIP_RQST 0x446d6454 /* "DmdT" */
132 #define NCPIP_RPLY 0x744e6350 /* "tNcP" */
134 struct ncp_ip_header
{
139 /* This header only appears on NCP over IP request packets */
140 struct ncp_ip_rqhdr
{
145 static const value_string ncp_ip_signature
[] = {
146 { NCPIP_RQST
, "Demand Transport (Request)" },
147 { NCPIP_RPLY
, "Transport is NCP (Reply)" },
151 static const value_string burst_command
[] = {
152 { 0x01000000, "Burst Read" },
153 { 0x02000000, "Burst Write" },
157 /* The information in this module comes from:
158 NetWare LAN Analysis, Second Edition
159 Laura A. Chappell and Dan E. Hakes
160 (c) 1994 Novell, Inc.
161 Novell Press, San Jose.
164 And from the ncpfs source code by Volker Lendecke
167 Programmer's Guide to the NetWare Core Protocol
168 Steve Conner & Diane Conner
169 (c) 1996 by Steve Conner & Diane Conner
170 Published by Annabooks, San Diego, California
174 http:developer.novell.com
179 static const value_string ncp_type_vals
[] = {
180 { NCP_ALLOCATE_SLOT
, "Create a service connection" },
181 { NCP_SERVICE_REQUEST
, "Service request" },
182 { NCP_SERVICE_REPLY
, "Service reply" },
183 { NCP_WATCHDOG
, "Watchdog" },
184 { NCP_DEALLOCATE_SLOT
, "Destroy service connection" },
185 { NCP_BROADCAST_SLOT
, "Server Broadcast" },
186 { NCP_BURST_MODE_XFER
, "Burst mode transfer" },
187 { NCP_POSITIVE_ACK
, "Request being processed" },
188 { NCP_LIP_ECHO
, "Large Internet Packet Echo" },
192 static const value_string ncp_oplock_vals
[] = {
193 { 0x21, "Message Waiting" },
194 { 0x24, "Clear Op-lock" },
198 /* Conversation Struct so we can detect NCP server sessions */
201 conversation_t
*conversation
;
202 guint32 nwconnection
;
206 /* Store the packet number for the start of the NCP session.
207 * Note sessions are defined as
208 * NCP Connection + NCP Task == Unique NCP server session
209 * It is normal for multiple sessions per connection to exist
210 * These are normally different applications running on multi-tasking
214 guint32 session_start_packet_num
;
217 static GHashTable
*mncp_rhash
= NULL
;
221 mncp_equal(gconstpointer v
, gconstpointer v2
)
223 const mncp_rhash_key
*val1
= (const mncp_rhash_key
*)v
;
224 const mncp_rhash_key
*val2
= (const mncp_rhash_key
*)v2
;
226 if (val1
->conversation
== val2
->conversation
&& val1
->nwconnection
== val2
->nwconnection
&& val1
->nwtask
== val2
->nwtask
) {
233 mncp_hash(gconstpointer v
)
235 const mncp_rhash_key
*mncp_key
= (const mncp_rhash_key
*)v
;
236 return GPOINTER_TO_UINT(mncp_key
->conversation
)+mncp_key
->nwconnection
+mncp_key
->nwtask
;
239 /* Initializes the hash table each time a new
240 * file is loaded or re-loaded in wireshark */
242 mncp_init_protocol(void)
245 g_hash_table_destroy(mncp_rhash
);
247 mncp_rhash
= g_hash_table_new(mncp_hash
, mncp_equal
);
250 /* After the sequential run, we don't need the ncp_request hash and keys
251 * anymore; the lookups have already been done and the vital info
252 * saved in the reply-packets' private_data in the frame_data struct. */
254 mncp_postseq_cleanup(void)
258 static mncp_rhash_value
*
259 mncp_hash_insert(conversation_t
*conversation
, guint32 nwconnection
, guint8 nwtask
, packet_info
*pinfo
)
262 mncp_rhash_value
*value
;
264 /* Now remember the request, so we can find it if we later
265 a reply to it. Track by conversation, connection, and task number.
266 in NetWare these values determine each unique session */
267 key
= wmem_new(wmem_file_scope(), mncp_rhash_key
);
268 key
->conversation
= conversation
;
269 key
->nwconnection
= nwconnection
;
270 key
->nwtask
= nwtask
;
272 value
= wmem_new(wmem_file_scope(), mncp_rhash_value
);
274 g_hash_table_insert(mncp_rhash
, key
, value
);
276 if (ncp_echo_conn
&& nwconnection
!= 65535) {
277 expert_add_info_format(pinfo
, NULL
, &ei_ncp_new_server_session
, "Detected New Server Session. Connection %d, Task %d", nwconnection
, nwtask
);
278 value
->session_start_packet_num
= pinfo
->fd
->num
;
284 /* Returns the ncp_rec*, or NULL if not found. */
285 static mncp_rhash_value
*
286 mncp_hash_lookup(conversation_t
*conversation
, guint32 nwconnection
, guint8 nwtask
)
290 key
.conversation
= conversation
;
291 key
.nwconnection
= nwconnection
;
294 return (mncp_rhash_value
*)g_hash_table_lookup(mncp_rhash
, &key
);
298 * Burst packet system flags.
300 #define ABT 0x04 /* Abort request */
301 #define BSY 0x08 /* Server Busy */
302 #define EOB 0x10 /* End of burst */
303 #define LST 0x40 /* Include Fragment List */
304 #define SYS 0x80 /* System packet */
307 dissect_ncp_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
310 proto_tree
*ncp_tree
= NULL
;
312 struct ncp_ip_header ncpiph
;
313 struct ncp_ip_rqhdr ncpiphrq
;
314 guint16 ncp_burst_seqno
, ncp_ack_seqno
;
316 proto_tree
*flags_tree
= NULL
;
320 gint length_remaining
;
322 guint32 testvar
= 0, ncp_burst_command
, burst_len
, burst_off
, burst_file
;
324 guint32 nw_connection
= 0, data_offset
;
325 guint16 data_len
= 0;
326 guint16 missing_fraglist_count
= 0;
327 mncp_rhash_value
*request_value
= NULL
;
328 conversation_t
*conversation
;
329 proto_item
*expert_item
;
331 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "NCP");
332 col_clear(pinfo
->cinfo
, COL_INFO
);
336 ti
= proto_tree_add_item(tree
, proto_ncp
, tvb
, 0, -1, ENC_NA
);
337 ncp_tree
= proto_item_add_subtree(ti
, ett_ncp
);
339 if (tvb_get_ntohl(tvb
, hdr_offset
) != NCPIP_RQST
&& tvb_get_ntohl(tvb
, hdr_offset
) != NCPIP_RPLY
)
341 /* Get NCPIP Header data */
342 ncpiph
.signature
= tvb_get_ntohl(tvb
, commhdr
);
343 proto_tree_add_uint(ncp_tree
, hf_ncp_ip_sig
, tvb
, commhdr
, 4, ncpiph
.signature
);
344 ncpiph
.length
= (0x7fffffff & tvb_get_ntohl(tvb
, commhdr
+4));
345 proto_tree_add_uint(ncp_tree
, hf_ncp_ip_length
, tvb
, commhdr
+4, 4, ncpiph
.length
);
347 if (ncpiph
.signature
== NCPIP_RQST
) {
348 ncpiphrq
.version
= tvb_get_ntohl(tvb
, commhdr
);
349 proto_tree_add_uint(ncp_tree
, hf_ncp_ip_ver
, tvb
, commhdr
, 4, ncpiphrq
.version
);
351 ncpiphrq
.rplybufsize
= tvb_get_ntohl(tvb
, commhdr
);
352 proto_tree_add_uint(ncp_tree
, hf_ncp_ip_rplybufsize
, tvb
, commhdr
, 4, ncpiphrq
.rplybufsize
);
355 /* Check to see if this is a valid offset, otherwise increment for packet signature */
356 if (try_val_to_str(tvb_get_ntohs(tvb
, commhdr
), ncp_type_vals
)==NULL
) {
357 /* Check to see if we have a valid type after packet signature length */
358 if (try_val_to_str(tvb_get_ntohs(tvb
, commhdr
+8), ncp_type_vals
)!=NULL
) {
359 proto_tree_add_item(ncp_tree
, hf_ncp_ip_packetsig
, tvb
, commhdr
, 8, ENC_NA
);
364 /* Initialize this structure, we use it below */
365 memset(&ncpiph
, 0, sizeof(ncpiph
));
368 header
.type
= tvb_get_ntohs(tvb
, commhdr
);
369 header
.sequence
= tvb_get_guint8(tvb
, commhdr
+2);
370 header
.conn_low
= tvb_get_guint8(tvb
, commhdr
+3);
371 header
.task
= tvb_get_guint8(tvb
, commhdr
+4);
372 header
.conn_high
= tvb_get_guint8(tvb
, commhdr
+5);
373 proto_tree_add_uint(ncp_tree
, hf_ncp_type
, tvb
, commhdr
, 2, header
.type
);
374 nw_connection
= (header
.conn_high
*256)+header
.conn_low
;
376 /* Ok, we need to track the conversation so that we can
377 * determine if a new server session is occuring for this
380 conversation
= find_conversation(pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
,
381 PT_NCP
, (guint32
) pinfo
->srcport
, (guint32
) pinfo
->destport
,
383 if ((ncpiph
.length
& 0x80000000) || ncpiph
.signature
== NCPIP_RPLY
) {
384 /* First time through we will record the initial connection and task
387 if (!pinfo
->fd
->flags
.visited
) {
388 if (conversation
!= NULL
) {
389 /* find the record telling us the
390 * request made that caused this
393 request_value
= mncp_hash_lookup(conversation
, nw_connection
, header
.task
);
394 /* if for some reason we have no
395 * conversation in our hash, create
397 if (request_value
== NULL
) {
398 mncp_hash_insert(conversation
, nw_connection
, header
.task
, pinfo
);
401 /* It's not part of any conversation
402 * - create a new one.
404 conversation
= conversation_new(pinfo
->fd
->num
, &pinfo
->src
,
405 &pinfo
->dst
, PT_NCP
, (guint32
) pinfo
->srcport
, (guint32
) pinfo
->destport
, 0);
406 mncp_hash_insert(conversation
, nw_connection
, header
.task
, pinfo
);
408 /* If this is a request packet then we
409 * might have a new task
411 if (ncpiph
.signature
== NCPIP_RPLY
) {
412 /* Now on reply packets we have to
413 * use the state of the original
414 * request packet, so look up the
415 * request value and check the task number
417 /*request_value = mncp_hash_lookup(conversation, nw_connection, header.task);*/
420 /* Get request value data */
421 request_value
= mncp_hash_lookup(conversation
, nw_connection
, header
.task
);
423 if ((request_value
->session_start_packet_num
== pinfo
->fd
->num
) && ncp_echo_conn
) {
424 expert_add_info_format(pinfo
, NULL
, &ei_ncp_new_server_session
, "Detected New Server Session. Connection %d, Task %d", nw_connection
, header
.task
);
429 if (!pinfo
->fd
->flags
.visited
) {
430 if (conversation
!= NULL
) {
431 /* find the record telling us the
432 * request made that caused this
435 request_value
= mncp_hash_lookup(conversation
, nw_connection
, header
.task
);
436 /* if for some reason we have no
437 * conversation in our hash, create
439 if (request_value
== NULL
) {
440 mncp_hash_insert(conversation
, nw_connection
, header
.task
, pinfo
);
443 /* It's not part of any conversation
444 * - create a new one.
446 conversation
= conversation_new(pinfo
->fd
->num
, &pinfo
->src
,
447 &pinfo
->dst
, PT_NCP
, (guint32
) pinfo
->srcport
, (guint32
) pinfo
->destport
, 0);
448 mncp_hash_insert(conversation
, nw_connection
, header
.task
, pinfo
);
450 /* find the record telling us the request
451 * made that caused this reply
454 request_value
= mncp_hash_lookup(conversation
, nw_connection
, header
.task
);
456 if ((request_value
->session_start_packet_num
== pinfo
->fd
->num
) && ncp_echo_conn
) {
457 expert_add_info_format(pinfo
, NULL
, &ei_ncp_new_server_session
, "Detected New Server Session. Connection %d, Task %d", nw_connection
, header
.task
);
463 tap_queue_packet(ncp_tap
.hdr
, pinfo
, ncp_hdr
);
465 col_add_str(pinfo
->cinfo
, COL_INFO
,
466 val_to_str(header
.type
, ncp_type_vals
, "Unknown type (0x%04x)"));
469 * Process the packet-type-specific header.
471 switch (header
.type
) {
473 case NCP_BROADCAST_SLOT
: /* Server Broadcast */
474 proto_tree_add_uint(ncp_tree
, hf_ncp_seq
, tvb
, commhdr
+ 2, 1, header
.sequence
);
475 proto_tree_add_uint(ncp_tree
, hf_ncp_connection
,tvb
, commhdr
+ 3, 3, nw_connection
);
476 proto_tree_add_item(ncp_tree
, hf_ncp_task
, tvb
, commhdr
+ 4, 1, ENC_BIG_ENDIAN
);
477 proto_tree_add_item(ncp_tree
, hf_ncp_oplock_flag
, tvb
, commhdr
+ 9, 1, tvb_get_guint8(tvb
, commhdr
+9));
478 proto_tree_add_item(ncp_tree
, hf_ncp_oplock_handle
, tvb
, commhdr
+ 10, 4, ENC_BIG_ENDIAN
);
479 if ((tvb_get_guint8(tvb
, commhdr
+9)==0x24) && ncp_echo_file
) {
480 expert_add_info_format(pinfo
, NULL
, &ei_ncp_oplock_handle
, "Server requesting station to clear oplock on handle - %08x", tvb_get_ntohl(tvb
, commhdr
+10));
484 case NCP_LIP_ECHO
: /* Lip Echo Packet */
485 proto_tree_add_item(ncp_tree
, hf_lip_echo
, tvb
, commhdr
, 13, ENC_ASCII
|ENC_NA
);
488 case NCP_BURST_MODE_XFER
: /* Packet Burst Packet */
490 * XXX - we should keep track of whether there's a burst
491 * outstanding on a connection and, if not, treat the
492 * beginning of the data as a burst header.
494 * The burst header contains:
496 * 4 bytes of little-endian function number:
497 * 1 = read, 2 = write;
499 * 4 bytes of file handle;
503 * 4 bytes of big-endian file offset;
505 * 4 bytes of big-endian byte count.
507 * The data follows for a burst write operation.
509 * The first packet of a burst read reply contains:
511 * 4 bytes of little-endian result code:
517 * 4 bytes of returned byte count (big-endian?).
521 * Each burst of a write request is responded to with a
522 * burst packet with a 2-byte little-endian result code:
524 * 0: Write successful
527 flags
= tvb_get_guint8(tvb
, commhdr
+ 2);
529 ti
= proto_tree_add_uint(ncp_tree
, hf_ncp_system_flags
,
530 tvb
, commhdr
+ 2, 1, flags
);
531 flags_tree
= proto_item_add_subtree(ti
, ett_ncp_system_flags
);
533 proto_tree_add_item(flags_tree
, hf_ncp_system_flags_abt
,
534 tvb
, commhdr
+ 2, 1, ENC_BIG_ENDIAN
);
536 proto_item_append_text(ti
, " ABT");
540 proto_tree_add_item(flags_tree
, hf_ncp_system_flags_bsy
,
541 tvb
, commhdr
+ 2, 1, ENC_BIG_ENDIAN
);
543 proto_item_append_text(ti
, " BSY");
547 proto_tree_add_item(flags_tree
, hf_ncp_system_flags_eob
,
548 tvb
, commhdr
+ 2, 1, ENC_BIG_ENDIAN
);
550 proto_item_append_text(ti
, " EOB");
554 proto_tree_add_item(flags_tree
, hf_ncp_system_flags_lst
,
555 tvb
, commhdr
+ 2, 1, ENC_BIG_ENDIAN
);
557 proto_item_append_text(ti
, " LST");
561 proto_tree_add_item(flags_tree
, hf_ncp_system_flags_sys
,
562 tvb
, commhdr
+ 2, 1, ENC_BIG_ENDIAN
);
564 proto_item_append_text(ti
, " SYS");
569 proto_tree_add_item(ncp_tree
, hf_ncp_stream_type
,
570 tvb
, commhdr
+ 3, 1, ENC_BIG_ENDIAN
);
571 proto_tree_add_item(ncp_tree
, hf_ncp_src_connection
,
572 tvb
, commhdr
+ 4, 4, ENC_BIG_ENDIAN
);
573 proto_tree_add_item(ncp_tree
, hf_ncp_dst_connection
,
574 tvb
, commhdr
+ 8, 4, ENC_BIG_ENDIAN
);
575 proto_tree_add_item(ncp_tree
, hf_ncp_packet_seqno
,
576 tvb
, commhdr
+ 12, 4, ENC_BIG_ENDIAN
);
577 proto_tree_add_item(ncp_tree
, hf_ncp_delay_time
,
578 tvb
, commhdr
+ 16, 4, ENC_BIG_ENDIAN
);
579 ncp_burst_seqno
= tvb_get_ntohs(tvb
, commhdr
+20);
580 proto_tree_add_item(ncp_tree
, hf_ncp_burst_seqno
,
581 tvb
, commhdr
+ 20, 2, ENC_BIG_ENDIAN
);
582 ncp_ack_seqno
= tvb_get_ntohs(tvb
, commhdr
+22);
583 proto_tree_add_item(ncp_tree
, hf_ncp_ack_seqno
,
584 tvb
, commhdr
+ 22, 2, ENC_BIG_ENDIAN
);
585 proto_tree_add_item(ncp_tree
, hf_ncp_burst_len
,
586 tvb
, commhdr
+ 24, 4, ENC_BIG_ENDIAN
);
587 data_offset
= tvb_get_ntohl(tvb
, commhdr
+ 28);
588 proto_tree_add_uint(ncp_tree
, hf_ncp_data_offset
,
589 tvb
, commhdr
+ 28, 4, data_offset
);
590 data_len
= tvb_get_ntohs(tvb
, commhdr
+ 32);
591 proto_tree_add_uint(ncp_tree
, hf_ncp_data_bytes
,
592 tvb
, commhdr
+ 32, 2, data_len
);
593 missing_fraglist_count
= tvb_get_ntohs(tvb
, commhdr
+ 34);
594 proto_tree_add_item(ncp_tree
, hf_ncp_missing_fraglist_count
,
595 tvb
, commhdr
+ 34, 2, ENC_BIG_ENDIAN
);
596 offset
= commhdr
+ 36;
597 if (!(flags
& SYS
) && ncp_burst_seqno
== ncp_ack_seqno
&&
600 * This is either a Burst Read or Burst Write
601 * command. The data length includes the burst
602 * mode header, plus any data in the command
603 * (there shouldn't be any in a read, but there
604 * might be some in a write).
608 ncp_burst_command
= tvb_get_ntohl(tvb
, offset
);
609 proto_tree_add_item(ncp_tree
, hf_ncp_burst_command
,
610 tvb
, offset
, 4, ENC_BIG_ENDIAN
);
616 burst_file
= tvb_get_ntohl(tvb
, offset
);
617 proto_tree_add_item(ncp_tree
, hf_ncp_burst_file_handle
,
618 tvb
, offset
, 4, ENC_BIG_ENDIAN
);
624 proto_tree_add_item(ncp_tree
, hf_ncp_burst_reserved
,
625 tvb
, offset
, 8, ENC_NA
);
631 burst_off
= tvb_get_ntohl(tvb
, offset
);
632 proto_tree_add_uint(ncp_tree
, hf_ncp_burst_offset
,
633 tvb
, offset
, 4, burst_off
);
639 burst_len
= tvb_get_ntohl(tvb
, offset
);
640 proto_tree_add_uint(ncp_tree
, hf_ncp_burst_len
,
641 tvb
, offset
, 4, burst_len
);
645 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
646 "%s %d bytes starting at offset %d in file 0x%08x",
647 val_to_str(ncp_burst_command
,
648 burst_command
, "Unknown (0x%08x)"),
649 burst_len
, burst_off
, burst_file
);
652 if (tvb_get_guint8(tvb
, commhdr
+ 2) & 0x10) {
653 col_set_str(pinfo
->cinfo
, COL_INFO
, "End of Burst");
658 case NCP_ALLOCATE_SLOT
: /* Allocate Slot Request */
659 length_remaining
= tvb_length_remaining(tvb
, commhdr
+ 4);
660 if (length_remaining
> 4) {
661 testvar
= tvb_get_ntohl(tvb
, commhdr
+4);
662 if (testvar
== 0x4c495020) {
663 proto_tree_add_item(ncp_tree
, hf_lip_echo
, tvb
, commhdr
+4, 13, ENC_ASCII
|ENC_NA
);
667 /* otherwise fall through */
669 case NCP_POSITIVE_ACK
: /* Positive Acknowledgement */
670 case NCP_SERVICE_REQUEST
: /* Server NCP Request */
671 case NCP_SERVICE_REPLY
: /* Server NCP Reply */
672 case NCP_WATCHDOG
: /* Watchdog Packet */
673 case NCP_DEALLOCATE_SLOT
: /* Deallocate Slot Request */
675 proto_tree_add_uint(ncp_tree
, hf_ncp_seq
, tvb
, commhdr
+ 2, 1, header
.sequence
);
676 proto_tree_add_uint(ncp_tree
, hf_ncp_connection
,tvb
, commhdr
+ 3, 3, nw_connection
);
677 proto_tree_add_item(ncp_tree
, hf_ncp_task
, tvb
, commhdr
+ 4, 1, ENC_BIG_ENDIAN
);
682 * Process the packet body.
684 switch (header
.type
) {
686 case NCP_ALLOCATE_SLOT
: /* Allocate Slot Request */
687 length_remaining
= tvb_length_remaining(tvb
, commhdr
+ 4);
688 if (length_remaining
> 4) {
689 testvar
= tvb_get_ntohl(tvb
, commhdr
+4);
690 if (testvar
== 0x4c495020) {
691 proto_tree_add_text(ncp_tree
, tvb
, commhdr
, -1,
696 next_tvb
= tvb_new_subset_remaining(tvb
, commhdr
);
697 dissect_ncp_request(next_tvb
, pinfo
, nw_connection
,
698 header
.sequence
, header
.type
, ncp_tree
);
701 case NCP_DEALLOCATE_SLOT
: /* Deallocate Slot Request */
702 next_tvb
= tvb_new_subset_remaining(tvb
, commhdr
);
703 dissect_ncp_request(next_tvb
, pinfo
, nw_connection
,
704 header
.sequence
, header
.type
, ncp_tree
);
707 case NCP_SERVICE_REQUEST
: /* Server NCP Request */
708 case NCP_BROADCAST_SLOT
: /* Server Broadcast Packet */
709 next_tvb
= tvb_new_subset_remaining(tvb
, commhdr
);
710 if (tvb_get_guint8(tvb
, commhdr
+6) == 0x68) {
711 subfunction
= tvb_get_guint8(tvb
, commhdr
+7);
712 switch (subfunction
) {
714 case 0x02: /* NDS Frag Packet to decode */
715 dissect_nds_request(next_tvb
, pinfo
,
716 nw_connection
, header
.sequence
,
717 header
.type
, ncp_tree
);
720 case 0x01: /* NDS Ping */
721 dissect_ping_req(next_tvb
, pinfo
,
722 nw_connection
, header
.sequence
,
723 header
.type
, ncp_tree
);
727 dissect_ncp_request(next_tvb
, pinfo
,
728 nw_connection
, header
.sequence
,
729 header
.type
, ncp_tree
);
733 dissect_ncp_request(next_tvb
, pinfo
, nw_connection
,
734 header
.sequence
, header
.type
, ncp_tree
);
738 case NCP_SERVICE_REPLY
: /* Server NCP Reply */
739 next_tvb
= tvb_new_subset_remaining(tvb
, commhdr
);
740 nds_defrag(next_tvb
, pinfo
, nw_connection
, header
.sequence
,
741 header
.type
, ncp_tree
, &ncp_tap
);
744 case NCP_POSITIVE_ACK
: /* Positive Acknowledgement */
746 * XXX - this used to call "nds_defrag()", which would
747 * clear out "frags". Was that the right thing to
750 next_tvb
= tvb_new_subset_remaining(tvb
, commhdr
);
751 dissect_ncp_reply(next_tvb
, pinfo
, nw_connection
,
752 header
.sequence
, header
.type
, ncp_tree
, &ncp_tap
);
755 case NCP_WATCHDOG
: /* Watchdog Packet */
757 * XXX - should the completion code be interpreted as
758 * it is in "packet-ncp2222.inc"? If so, this
759 * packet should be handled by "dissect_ncp_reply()".
761 proto_tree_add_item(ncp_tree
, hf_ncp_completion_code
,
762 tvb
, commhdr
+ 6, 1, ENC_LITTLE_ENDIAN
);
763 proto_tree_add_item(ncp_tree
, hf_ncp_connection_status
,
764 tvb
, commhdr
+ 7, 1, ENC_LITTLE_ENDIAN
);
765 proto_tree_add_item(ncp_tree
, hf_ncp_slot
,
766 tvb
, commhdr
+ 8, 1, ENC_LITTLE_ENDIAN
);
767 proto_tree_add_item(ncp_tree
, hf_ncp_control_code
,
768 tvb
, commhdr
+ 9, 1, ENC_LITTLE_ENDIAN
);
770 * Display the rest of the packet as data.
772 if (tvb_offset_exists(tvb
, commhdr
+ 10)) {
773 call_dissector(data_handle
,
774 tvb_new_subset_remaining(tvb
, commhdr
+ 10),
779 case NCP_BURST_MODE_XFER
: /* Packet Burst Packet */
782 * System packet; show missing fragments if there
785 while (missing_fraglist_count
!= 0) {
786 proto_tree_add_item(ncp_tree
, hf_ncp_missing_data_offset
,
787 tvb
, offset
, 4, ENC_BIG_ENDIAN
);
789 proto_tree_add_item(ncp_tree
, hf_ncp_missing_data_count
,
790 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
792 missing_fraglist_count
--;
796 * XXX - do this by using -1 and -1 as the length
797 * arguments to "tvb_new_subset()" and then calling
798 * "tvb_set_reported_length()"? That'll throw an
799 * exception if "data_len" goes past the reported
800 * length of the packet, but that's arguably a
801 * feature in this case.
803 length_remaining
= tvb_length_remaining(tvb
, offset
);
804 if (length_remaining
> data_len
)
805 length_remaining
= data_len
;
807 call_dissector(data_handle
,
808 tvb_new_subset(tvb
, offset
,
809 length_remaining
, data_len
),
815 case NCP_LIP_ECHO
: /* LIP Echo Packet */
816 proto_tree_add_text(ncp_tree
, tvb
, commhdr
, -1,
821 expert_item
= proto_tree_add_text(ncp_tree
, tvb
, commhdr
+ 6, -1,
822 "%s packets not supported yet",
823 val_to_str(header
.type
, ncp_type_vals
,
824 "Unknown type (0x%04x)"));
826 expert_add_info_format(pinfo
, expert_item
, &ei_ncp_type
, "%s packets not supported yet", val_to_str(header
.type
, ncp_type_vals
, "Unknown type (0x%04x)"));
833 dissect_ncp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
835 dissect_ncp_common(tvb
, pinfo
, tree
, FALSE
);
839 get_ncp_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
)
844 * Check the NCP-over-TCP header signature, to make sure it's there.
845 * If it's not there, we cannot trust the next 4 bytes to be a
846 * packet length+"has signature" flag, so we just say the length is
847 * "what remains in the packet".
849 signature
= tvb_get_ntohl(tvb
, offset
);
850 if (signature
!= NCPIP_RQST
&& signature
!= NCPIP_RPLY
)
851 return tvb_length_remaining(tvb
, offset
);
854 * Get the length of the NCP-over-TCP packet. Strip off the "has
858 return tvb_get_ntohl(tvb
, offset
+ 4) & 0x7fffffff;
862 dissect_ncp_tcp_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
864 dissect_ncp_common(tvb
, pinfo
, tree
, TRUE
);
865 return tvb_length(tvb
);
869 dissect_ncp_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
871 tcp_dissect_pdus(tvb
, pinfo
, tree
, ncp_desegment
, 8, get_ncp_pdu_len
,
872 dissect_ncp_tcp_pdu
, data
);
873 return tvb_length(tvb
);
877 proto_register_ncp(void)
879 static hf_register_info hf
[] = {
881 { "NCP over IP signature", "ncp.ip.signature",
882 FT_UINT32
, BASE_HEX
, VALS(ncp_ip_signature
), 0x0,
885 { "NCP over IP length", "ncp.ip.length",
886 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
889 { "NCP over IP Version", "ncp.ip.version",
890 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
892 { &hf_ncp_ip_rplybufsize
,
893 { "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize",
894 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
896 { &hf_ncp_ip_packetsig
,
897 { "NCP over IP Packet Signature", "ncp.ip.packetsig",
898 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
901 { "Type", "ncp.type",
902 FT_UINT16
, BASE_HEX
, VALS(ncp_type_vals
), 0x0,
903 "NCP message type", HFILL
}},
905 { "Sequence Number", "ncp.seq",
906 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
908 { &hf_ncp_connection
,
909 { "Connection Number", "ncp.connection",
910 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
913 { "Task Number", "ncp.task",
914 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
916 { &hf_ncp_oplock_flag
,
917 { "Broadcast Message Flag", "ncp.msg_flag",
918 FT_UINT8
, BASE_HEX
, VALS(ncp_oplock_vals
), 0x0,
920 { &hf_ncp_oplock_handle
,
921 { "File Handle", "ncp.oplock_handle",
922 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
924 { &hf_ncp_stream_type
,
925 { "Stream Type", "ncp.stream_type",
926 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
927 "Type of burst", HFILL
}},
928 { &hf_ncp_system_flags
,
929 { "System Flags", "ncp.system_flags",
930 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
932 { &hf_ncp_system_flags_abt
,
933 { "ABT", "ncp.system_flags.abt",
934 FT_BOOLEAN
, 8, NULL
, ABT
,
935 "Is this an abort request?", HFILL
}},
936 { &hf_ncp_system_flags_eob
,
937 { "EOB", "ncp.system_flags.eob",
938 FT_BOOLEAN
, 8, NULL
, EOB
,
939 "Is this the last packet of the burst?", HFILL
}},
940 { &hf_ncp_system_flags_sys
,
941 { "SYS", "ncp.system_flags.sys",
942 FT_BOOLEAN
, 8, NULL
, SYS
,
943 "Is this a system packet?", HFILL
}},
944 { &hf_ncp_system_flags_bsy
,
945 { "BSY", "ncp.system_flags.bsy",
946 FT_BOOLEAN
, 8, NULL
, BSY
,
947 "Is the server busy?", HFILL
}},
948 { &hf_ncp_system_flags_lst
,
949 { "LST", "ncp.system_flags.lst",
950 FT_BOOLEAN
, 8, NULL
, LST
,
951 "Return Fragment List?", HFILL
}},
952 { &hf_ncp_src_connection
,
953 { "Source Connection ID", "ncp.src_connection",
954 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
955 "The workstation's connection identification number", HFILL
}},
956 { &hf_ncp_dst_connection
,
957 { "Destination Connection ID", "ncp.dst_connection",
958 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
959 "The server's connection identification number", HFILL
}},
960 { &hf_ncp_packet_seqno
,
961 { "Packet Sequence Number", "ncp.packet_seqno",
962 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
963 "Sequence number of this packet in a burst", HFILL
}},
964 { &hf_ncp_delay_time
,
965 { "Delay Time", "ncp.delay_time", /* in 100 us increments */
966 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
967 "Delay time between consecutive packet sends (100 us increments)", HFILL
}},
968 { &hf_ncp_burst_seqno
,
969 { "Burst Sequence Number", "ncp.burst_seqno",
970 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
971 "Sequence number of this packet in the burst", HFILL
}},
973 { "ACK Sequence Number", "ncp.ack_seqno",
974 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
975 "Next expected burst sequence number", HFILL
}},
977 { "Burst Length", "ncp.burst_len",
978 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
979 "Total length of data in this burst", HFILL
}},
980 { &hf_ncp_burst_offset
,
981 { "Burst Offset", "ncp.burst_offset",
982 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
983 "Offset of data in the burst", HFILL
}},
984 { &hf_ncp_data_offset
,
985 { "Data Offset", "ncp.data_offset",
986 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
987 "Offset of this packet", HFILL
}},
988 { &hf_ncp_data_bytes
,
989 { "Data Bytes", "ncp.data_bytes",
990 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
991 "Number of data bytes in this packet", HFILL
}},
992 { &hf_ncp_missing_fraglist_count
,
993 { "Missing Fragment List Count", "ncp.missing_fraglist_count",
994 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
995 "Number of missing fragments reported", HFILL
}},
996 { &hf_ncp_missing_data_offset
,
997 { "Missing Data Offset", "ncp.missing_data_offset",
998 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
999 "Offset of beginning of missing data", HFILL
}},
1000 { &hf_ncp_missing_data_count
,
1001 { "Missing Data Count", "ncp.missing_data_count",
1002 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1003 "Number of bytes of missing data", HFILL
}},
1004 { &hf_ncp_completion_code
,
1005 { "Completion Code", "ncp.completion_code",
1006 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1008 { &hf_ncp_connection_status
,
1009 { "Connection Status", "ncp.connection_status",
1010 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1013 { "Slot", "ncp.slot",
1014 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1016 { &hf_ncp_control_code
,
1017 { "Control Code", "ncp.control_code",
1018 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1021 { &hf_ncp_fragment_handle
,
1022 { "Fragment Handle", "ncp.fragger_hndl",
1023 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
1027 { "Large Internet Packet Echo", "ncp.lip_echo",
1028 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1030 { &hf_ncp_burst_command
,
1031 { "Burst Command", "ncp.burst_command",
1032 FT_UINT32
, BASE_HEX
, VALS(burst_command
), 0x0,
1033 "Packet Burst Command", HFILL
}},
1034 { &hf_ncp_burst_file_handle
,
1035 { "Burst File Handle", "ncp.file_handle",
1036 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1037 "Packet Burst File Handle", HFILL
}},
1038 { &hf_ncp_burst_reserved
,
1039 { "Reserved", "ncp.burst_reserved",
1040 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}}
1042 static gint
*ett
[] = {
1044 &ett_ncp_system_flags
,
1049 static ei_register_info ei
[] = {
1050 { &ei_ncp_new_server_session
, { "ncp.new_server_session", PI_RESPONSE_CODE
, PI_CHAT
, "Detected New Server Session", EXPFILL
}},
1051 { &ei_ncp_oplock_handle
, { "ncp.oplock_handle.clear", PI_RESPONSE_CODE
, PI_CHAT
, "Server requesting station to clear oplock", EXPFILL
}},
1052 { &ei_ncp_type
, { "ncp.type.unsupported", PI_UNDECODED
, PI_NOTE
, "Packet type not supported yet", EXPFILL
}},
1054 module_t
*ncp_module
;
1055 expert_module_t
* expert_ncp
;
1057 proto_ncp
= proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
1058 proto_register_field_array(proto_ncp
, hf
, array_length(hf
));
1059 proto_register_subtree_array(ett
, array_length(ett
));
1060 expert_ncp
= expert_register_protocol(proto_ncp
);
1061 expert_register_field_array(expert_ncp
, ei
, array_length(ei
));
1063 ncp_module
= prefs_register_protocol(proto_ncp
, NULL
);
1064 prefs_register_obsolete_preference(ncp_module
, "initial_hash_size");
1065 prefs_register_bool_preference(ncp_module
, "desegment",
1066 "Reassemble NCP-over-TCP messages spanning multiple TCP segments",
1067 "Whether the NCP dissector should reassemble messages spanning multiple TCP segments."
1068 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1070 prefs_register_bool_preference(ncp_module
, "defragment_nds",
1071 "Reassemble fragmented NDS messages spanning multiple reply packets",
1072 "Whether the NCP dissector should defragment NDS messages spanning multiple reply packets.",
1074 prefs_register_bool_preference(ncp_module
, "newstyle",
1075 "Dissect New Netware Information Structure",
1076 "Dissect the NetWare Information Structure as NetWare 5.x or higher or as older NetWare 3.x.",
1078 prefs_register_bool_preference(ncp_module
, "eid_2_expert",
1079 "Expert: EID to Name lookups?",
1080 "Whether the NCP dissector should echo the NDS Entry ID to name resolves to the expert table.",
1082 prefs_register_bool_preference(ncp_module
, "connection_2_expert",
1083 "Expert: NCP Connections?",
1084 "Whether the NCP dissector should echo NCP connection information to the expert table.",
1086 prefs_register_bool_preference(ncp_module
, "error_2_expert",
1087 "Expert: NCP Errors?",
1088 "Whether the NCP dissector should echo protocol errors to the expert table.",
1090 prefs_register_bool_preference(ncp_module
, "server_2_expert",
1091 "Expert: Server Information?",
1092 "Whether the NCP dissector should echo server information to the expert table.",
1094 prefs_register_bool_preference(ncp_module
, "file_2_expert",
1095 "Expert: File Information?",
1096 "Whether the NCP dissector should echo file open/close/oplock information to the expert table.",
1098 register_init_routine(&mncp_init_protocol
);
1099 ncp_tap
.stat
=register_tap("ncp_srt");
1100 ncp_tap
.hdr
=register_tap("ncp_hdr");
1101 register_postseq_cleanup_routine(&mncp_postseq_cleanup
);
1105 proto_reg_handoff_ncp(void)
1107 dissector_handle_t ncp_handle
;
1108 dissector_handle_t ncp_tcp_handle
;
1110 ncp_handle
= create_dissector_handle(dissect_ncp
, proto_ncp
);
1111 ncp_tcp_handle
= new_create_dissector_handle(dissect_ncp_tcp
, proto_ncp
);
1112 dissector_add_uint("tcp.port", TCP_PORT_NCP
, ncp_tcp_handle
);
1113 dissector_add_uint("udp.port", UDP_PORT_NCP
, ncp_handle
);
1114 dissector_add_uint("ipx.packet_type", IPX_PACKET_TYPE_NCP
, ncp_handle
);
1115 dissector_add_uint("ipx.socket", IPX_SOCKET_NCP
, ncp_handle
);
1117 data_handle
= find_dissector("data");
1121 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1126 * indent-tabs-mode: nil
1129 * vi: set shiftwidth=4 tabstop=4 expandtab:
1130 * :indentSize=4:tabSize=4:noTabs=true: