HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-ncp.c
blob59177b03b50be9a7475726ea0045f717dae303d9
1 /* packet-ncp.c
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$
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.
33 /* XXX:
34 ToDo: Find and fix possible memory leak(s):
36 Example:
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).
45 #include "config.h"
47 #include <string.h>
49 #include <glib.h>
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>
59 #include <epan/tap.h>
61 int proto_ncp = -1;
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;
103 gint ett_ncp = -1;
104 gint ett_nds = -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 {
135 guint32 signature;
136 guint32 length;
139 /* This header only appears on NCP over IP request packets */
140 struct ncp_ip_rqhdr {
141 guint32 version;
142 guint32 rplybufsize;
145 static const value_string ncp_ip_signature[] = {
146 { NCPIP_RQST, "Demand Transport (Request)" },
147 { NCPIP_RPLY, "Transport is NCP (Reply)" },
148 { 0, NULL }
151 static const value_string burst_command[] = {
152 { 0x01000000, "Burst Read" },
153 { 0x02000000, "Burst Write" },
154 { 0, NULL }
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.
162 ISBN: 0-7821-1362-1
164 And from the ncpfs source code by Volker Lendecke
166 And:
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
171 ISBN: 0-929392-31-0
173 And:
174 http:developer.novell.com
175 NCP documentation
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" },
189 { 0, NULL }
192 static const value_string ncp_oplock_vals[] = {
193 { 0x21, "Message Waiting" },
194 { 0x24, "Clear Op-lock" },
195 { 0, NULL }
198 /* Conversation Struct so we can detect NCP server sessions */
200 typedef struct {
201 conversation_t *conversation;
202 guint32 nwconnection;
203 guint8 nwtask;
204 } mncp_rhash_key;
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
211 * Operating Systems.
213 typedef struct {
214 guint32 session_start_packet_num;
215 } mncp_rhash_value;
217 static GHashTable *mncp_rhash = NULL;
219 /* Hash Functions */
220 static gint
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) {
227 return 1;
229 return 0;
232 static guint
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 */
241 static void
242 mncp_init_protocol(void)
244 if (mncp_rhash)
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. */
253 static void
254 mncp_postseq_cleanup(void)
258 static mncp_rhash_value*
259 mncp_hash_insert(conversation_t *conversation, guint32 nwconnection, guint8 nwtask, packet_info *pinfo)
261 mncp_rhash_key *key;
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;
281 return value;
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)
288 mncp_rhash_key key;
290 key.conversation = conversation;
291 key.nwconnection = nwconnection;
292 key.nwtask = nwtask;
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 */
306 static void
307 dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
308 gboolean is_tcp)
310 proto_tree *ncp_tree = NULL;
311 proto_item *ti;
312 struct ncp_ip_header ncpiph;
313 struct ncp_ip_rqhdr ncpiphrq;
314 guint16 ncp_burst_seqno, ncp_ack_seqno;
315 guint16 flags = 0;
316 proto_tree *flags_tree = NULL;
317 int hdr_offset = 0;
318 int commhdr = 0;
319 int offset = 0;
320 gint length_remaining;
321 tvbuff_t *next_tvb;
322 guint32 testvar = 0, ncp_burst_command, burst_len, burst_off, burst_file;
323 guint8 subfunction;
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);
334 ncp_hdr = &header;
336 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, ENC_NA);
337 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
338 if (is_tcp) {
339 if (tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RQST && tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RPLY)
340 commhdr += 1;
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);
346 commhdr += 8;
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);
350 commhdr += 4;
351 ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, commhdr);
352 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, commhdr, 4, ncpiphrq.rplybufsize);
353 commhdr += 4;
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);
360 commhdr += 8;
363 } else {
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
378 * connection.
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
385 * values
387 if (!pinfo->fd->flags.visited) {
388 if (conversation != NULL) {
389 /* find the record telling us the
390 * request made that caused this
391 * reply
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
396 * one */
397 if (request_value == NULL) {
398 mncp_hash_insert(conversation, nw_connection, header.task, pinfo);
400 } else {
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);*/
419 } else {
420 /* Get request value data */
421 request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
422 if (request_value) {
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);
428 } else {
429 if (!pinfo->fd->flags.visited) {
430 if (conversation != NULL) {
431 /* find the record telling us the
432 * request made that caused this
433 * reply
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
438 * one */
439 if (request_value == NULL) {
440 mncp_hash_insert(conversation, nw_connection, header.task, pinfo);
442 } else {
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
453 } else {
454 request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
455 if (request_value) {
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));
482 break;
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);
486 break;
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;
501 * 8 reserved bytes;
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:
512 * 0: No error
513 * 1: Initial error
514 * 2: I/O error
515 * 3: No data read;
517 * 4 bytes of returned byte count (big-endian?).
519 * The data follows.
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
525 * 4: Write error
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);
535 if (flags & ABT) {
536 proto_item_append_text(ti, " ABT");
538 flags&=(~( ABT ));
540 proto_tree_add_item(flags_tree, hf_ncp_system_flags_bsy,
541 tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
542 if (flags & BSY) {
543 proto_item_append_text(ti, " BSY");
545 flags&=(~( BSY ));
547 proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
548 tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
549 if (flags & EOB) {
550 proto_item_append_text(ti, " EOB");
552 flags&=(~( EOB ));
554 proto_tree_add_item(flags_tree, hf_ncp_system_flags_lst,
555 tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
556 if (flags & LST) {
557 proto_item_append_text(ti, " LST");
559 flags&=(~( LST ));
561 proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
562 tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
563 if (flags & SYS) {
564 proto_item_append_text(ti, " SYS");
566 flags&=(~( 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 &&
598 data_offset == 0) {
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).
606 if (data_len < 4)
607 return;
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);
611 offset += 4;
612 data_len -= 4;
614 if (data_len < 4)
615 return;
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);
619 offset += 4;
620 data_len -= 4;
622 if (data_len < 8)
623 return;
624 proto_tree_add_item(ncp_tree, hf_ncp_burst_reserved,
625 tvb, offset, 8, ENC_NA);
626 offset += 8;
627 data_len -= 8;
629 if (data_len < 4)
630 return;
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);
634 offset += 4;
635 data_len -= 4;
637 if (data_len < 4)
638 return;
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);
642 offset += 4;
643 data_len -= 4;
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);
650 break;
651 } else {
652 if (tvb_get_guint8(tvb, commhdr + 2) & 0x10) {
653 col_set_str(pinfo->cinfo, COL_INFO, "End of Burst");
656 break;
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);
664 break;
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 */
674 default:
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);
678 break;
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,
692 "Lip Echo Packet");
693 /*break;*/
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);
699 break;
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);
705 break;
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);
718 break;
720 case 0x01: /* NDS Ping */
721 dissect_ping_req(next_tvb, pinfo,
722 nw_connection, header.sequence,
723 header.type, ncp_tree);
724 break;
726 default:
727 dissect_ncp_request(next_tvb, pinfo,
728 nw_connection, header.sequence,
729 header.type, ncp_tree);
730 break;
732 } else {
733 dissect_ncp_request(next_tvb, pinfo, nw_connection,
734 header.sequence, header.type, ncp_tree);
736 break;
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);
742 break;
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
748 * do?
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);
753 break;
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),
775 pinfo, ncp_tree);
777 break;
779 case NCP_BURST_MODE_XFER: /* Packet Burst Packet */
780 if (flags & SYS) {
782 * System packet; show missing fragments if there
783 * are any.
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);
788 offset += 4;
789 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
790 tvb, offset, 2, ENC_BIG_ENDIAN);
791 offset += 2;
792 missing_fraglist_count--;
794 } else {
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;
806 if (data_len != 0) {
807 call_dissector(data_handle,
808 tvb_new_subset(tvb, offset,
809 length_remaining, data_len),
810 pinfo, ncp_tree);
813 break;
815 case NCP_LIP_ECHO: /* LIP Echo Packet */
816 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
817 "Lip Echo Packet");
818 break;
820 default:
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)"));
825 if (ncp_echo_err) {
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)"));
828 break;
832 static void
833 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
835 dissect_ncp_common(tvb, pinfo, tree, FALSE);
838 static guint
839 get_ncp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
841 guint32 signature;
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
855 * signature" flag.
858 return tvb_get_ntohl(tvb, offset + 4) & 0x7fffffff;
861 static int
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);
868 static int
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);
876 void
877 proto_register_ncp(void)
879 static hf_register_info hf[] = {
880 { &hf_ncp_ip_sig,
881 { "NCP over IP signature", "ncp.ip.signature",
882 FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
883 NULL, HFILL }},
884 { &hf_ncp_ip_length,
885 { "NCP over IP length", "ncp.ip.length",
886 FT_UINT32, BASE_DEC, NULL, 0x0,
887 NULL, HFILL }},
888 { &hf_ncp_ip_ver,
889 { "NCP over IP Version", "ncp.ip.version",
890 FT_UINT32, BASE_DEC, NULL, 0x0,
891 NULL, HFILL }},
892 { &hf_ncp_ip_rplybufsize,
893 { "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize",
894 FT_UINT32, BASE_DEC, NULL, 0x0,
895 NULL, HFILL }},
896 { &hf_ncp_ip_packetsig,
897 { "NCP over IP Packet Signature", "ncp.ip.packetsig",
898 FT_BYTES, BASE_NONE, NULL, 0x0,
899 NULL, HFILL }},
900 { &hf_ncp_type,
901 { "Type", "ncp.type",
902 FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
903 "NCP message type", HFILL }},
904 { &hf_ncp_seq,
905 { "Sequence Number", "ncp.seq",
906 FT_UINT8, BASE_DEC, NULL, 0x0,
907 NULL, HFILL }},
908 { &hf_ncp_connection,
909 { "Connection Number", "ncp.connection",
910 FT_UINT16, BASE_DEC, NULL, 0x0,
911 NULL, HFILL }},
912 { &hf_ncp_task,
913 { "Task Number", "ncp.task",
914 FT_UINT8, BASE_DEC, NULL, 0x0,
915 NULL, HFILL }},
916 { &hf_ncp_oplock_flag,
917 { "Broadcast Message Flag", "ncp.msg_flag",
918 FT_UINT8, BASE_HEX, VALS(ncp_oplock_vals), 0x0,
919 NULL, HFILL }},
920 { &hf_ncp_oplock_handle,
921 { "File Handle", "ncp.oplock_handle",
922 FT_UINT16, BASE_HEX, NULL, 0x0,
923 NULL, HFILL }},
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,
931 NULL, HFILL }},
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 }},
972 { &hf_ncp_ack_seqno,
973 { "ACK Sequence Number", "ncp.ack_seqno",
974 FT_UINT16, BASE_DEC, NULL, 0x0,
975 "Next expected burst sequence number", HFILL }},
976 { &hf_ncp_burst_len,
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,
1007 NULL, HFILL }},
1008 { &hf_ncp_connection_status,
1009 { "Connection Status", "ncp.connection_status",
1010 FT_UINT8, BASE_DEC, NULL, 0x0,
1011 NULL, HFILL }},
1012 { &hf_ncp_slot,
1013 { "Slot", "ncp.slot",
1014 FT_UINT8, BASE_DEC, NULL, 0x0,
1015 NULL, HFILL }},
1016 { &hf_ncp_control_code,
1017 { "Control Code", "ncp.control_code",
1018 FT_UINT8, BASE_DEC, NULL, 0x0,
1019 NULL, HFILL }},
1020 #if 0
1021 { &hf_ncp_fragment_handle,
1022 { "Fragment Handle", "ncp.fragger_hndl",
1023 FT_UINT16, BASE_HEX, NULL, 0x0,
1024 NULL, HFILL }},
1025 #endif
1026 { &hf_lip_echo,
1027 { "Large Internet Packet Echo", "ncp.lip_echo",
1028 FT_STRING, BASE_NONE, NULL, 0x0,
1029 NULL, HFILL }},
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[] = {
1043 &ett_ncp,
1044 &ett_ncp_system_flags,
1045 &ett_nds,
1046 &ett_nds_segments,
1047 &ett_nds_segment
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.",
1069 &ncp_desegment);
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.",
1073 &nds_defragment);
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.",
1077 &ncp_newstyle);
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.",
1081 &nds_echo_eid);
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.",
1085 &ncp_echo_conn);
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.",
1089 &ncp_echo_err);
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.",
1093 &ncp_echo_server);
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.",
1097 &ncp_echo_file);
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);
1104 void
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
1123 * Local variables:
1124 * c-basic-offset: 4
1125 * tab-width: 4
1126 * indent-tabs-mode: nil
1127 * End:
1129 * vi: set shiftwidth=4 tabstop=4 expandtab:
1130 * :indentSize=4:tabSize=4:noTabs=true: