removed some gcc warnings (hopefully)
[obnox/wireshark/wip.git] / epan / dissectors / packet-ncp.c
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>
7  *
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
11  *
12  * $Id$
13  *
14  * Ethereal - Network traffic analyzer
15  * By Gerald Combs <gerald@ethereal.com>
16  * Copyright 2000 Gerald Combs
17  *
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.
22  *
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.
27  *
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.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
39 #endif
40
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
43 #endif
44
45 #include <string.h>
46 #include <glib.h>
47 #include <epan/packet.h>
48 #include <epan/prefs.h>
49 #include "packet-ipx.h"
50 #include "packet-tcp.h"
51 #include "packet-ncp-int.h"
52 #include "reassemble.h"
53 #include <epan/conversation.h>
54
55 int proto_ncp = -1;
56 static int hf_ncp_ip_ver = -1;
57 static int hf_ncp_ip_length = -1;
58 static int hf_ncp_ip_rplybufsize = -1;
59 static int hf_ncp_ip_sig = -1;
60 static int hf_ncp_ip_packetsig = -1;
61 static int hf_ncp_type = -1;
62 static int hf_ncp_seq = -1;
63 static int hf_ncp_connection = -1;
64 static int hf_ncp_task = -1;
65 static int hf_ncp_stream_type = -1;
66 static int hf_ncp_system_flags = -1;
67 static int hf_ncp_system_flags_abt = -1;
68 static int hf_ncp_system_flags_eob = -1;
69 static int hf_ncp_system_flags_sys = -1;
70 static int hf_ncp_system_flags_bsy = -1;
71 static int hf_ncp_system_flags_lst = -1;
72 static int hf_ncp_src_connection = -1;
73 static int hf_ncp_dst_connection = -1;
74 static int hf_ncp_packet_seqno = -1;
75 static int hf_ncp_delay_time = -1;
76 static int hf_ncp_burst_seqno = -1;
77 static int hf_ncp_ack_seqno = -1;
78 static int hf_ncp_burst_len = -1;
79 static int hf_ncp_burst_offset = -1;
80 static int hf_ncp_data_offset = -1;
81 static int hf_ncp_data_bytes = -1;
82 static int hf_ncp_missing_fraglist_count = -1;
83 static int hf_ncp_missing_data_offset = -1;
84 static int hf_ncp_missing_data_count = -1;
85 static int hf_ncp_oplock_flag = -1;
86 static int hf_ncp_oplock_handle = -1;
87 static int hf_ncp_completion_code = -1;
88 static int hf_ncp_connection_status = -1;
89 static int hf_ncp_slot = -1;
90 static int hf_ncp_control_code = -1;
91 static int hf_ncp_fragment_handle = -1;
92 static int hf_lip_echo = -1;
93 static int hf_ncp_burst_command = -1;
94 static int hf_ncp_burst_file_handle = -1;
95 static int hf_ncp_burst_reserved = -1;
96
97 gint ett_ncp = -1;
98 gint ett_nds = -1;
99 gint ett_nds_segments = -1;
100 gint ett_nds_segment = -1;
101 static gint ett_ncp_system_flags = -1;
102
103
104 /* Tables for reassembly of fragments. */ 
105 GHashTable *nds_fragment_table = NULL;
106 GHashTable *nds_reassembled_table = NULL;
107 dissector_handle_t nds_data_handle;
108
109 /* desegmentation of NCP over TCP */
110 static gboolean ncp_desegment = TRUE;
111
112 static dissector_handle_t data_handle;
113
114 #define TCP_PORT_NCP            524
115 #define UDP_PORT_NCP            524
116
117 #define NCP_RQST_HDR_LENGTH     7
118 #define NCP_RPLY_HDR_LENGTH     8
119
120
121 /* Hash functions */
122 gint  ncp_equal (gconstpointer v, gconstpointer v2);
123 guint ncp_hash  (gconstpointer v);
124
125 /* These are the header structures to handle NCP over IP */
126 #define NCPIP_RQST      0x446d6454      /* "DmdT" */
127 #define NCPIP_RPLY      0x744e6350      /* "tNcP" */
128
129 struct ncp_ip_header {
130         guint32 signature;
131         guint32 length;
132 };
133
134
135 /* This header only appears on NCP over IP request packets */
136 struct ncp_ip_rqhdr {
137         guint32 version;
138         guint32 rplybufsize;
139 };
140
141 static const value_string ncp_ip_signature[] = {
142         { NCPIP_RQST, "Demand Transport (Request)" },
143         { NCPIP_RPLY, "Transport is NCP (Reply)" },
144         { 0, NULL },
145 };
146
147 static const value_string burst_command[] = {
148     { 0x01000000, "Burst Read" },
149     { 0x02000000, "Burst Write" },
150     { 0, NULL },
151 };
152
153 /* The information in this module comes from:
154         NetWare LAN Analysis, Second Edition
155         Laura A. Chappell and Dan E. Hakes
156         (c) 1994 Novell, Inc.
157         Novell Press, San Jose.
158         ISBN: 0-7821-1362-1
159
160   And from the ncpfs source code by Volker Lendecke
161
162   And:
163         Programmer's Guide to the NetWare Core Protocol
164         Steve Conner & Diane Conner
165         (c) 1996 by Steve Conner & Diane Conner
166         Published by Annabooks, San Diego, California
167         ISBN: 0-929392-31-0
168         
169  And:
170     http:developer.novell.com
171     NCP documentation        
172
173 */
174
175 /*
176  * Every NCP packet has this common header (except for burst packets).
177  */
178 struct ncp_common_header {
179         guint16 type;
180         guint8  sequence;
181         guint8  conn_low;
182         guint8  task;
183         guint8  conn_high; /* type=0x5555 doesn't have this */
184 };
185
186
187 static value_string ncp_type_vals[] = {
188         { NCP_ALLOCATE_SLOT,    "Create a service connection" },
189         { NCP_SERVICE_REQUEST,  "Service request" },
190         { NCP_SERVICE_REPLY,    "Service reply" },
191         { NCP_WATCHDOG,         "Watchdog" },
192         { NCP_DEALLOCATE_SLOT,  "Destroy service connection" },
193         { NCP_BROADCAST_SLOT,   "Server Broadcast" },
194         { NCP_BURST_MODE_XFER,  "Burst mode transfer" },
195         { NCP_POSITIVE_ACK,     "Request being processed" },
196         { NCP_LIP_ECHO,         "Large Internet Packet Echo" },
197         { 0,                    NULL }
198 };
199
200 /* Conversation Struct so we can store whether the conversation is using Packet Signature */
201
202 typedef struct {
203         conversation_t  *conversation;
204 } mncp_rhash_key;
205
206 typedef struct {
207         gboolean            packet_signature;
208 } mncp_rhash_value;
209
210 static GHashTable *mncp_rhash = NULL;
211 static GMemChunk *mncp_rhash_keys = NULL;
212 static GMemChunk *mncp_rhash_values = NULL;
213
214 /* Hash Functions */
215 gint
216 mncp_equal(gconstpointer v, gconstpointer v2)
217 {
218         const mncp_rhash_key    *val1 = (const mncp_rhash_key*)v;
219         const mncp_rhash_key    *val2 = (const mncp_rhash_key*)v2;
220
221         if (val1->conversation == val2->conversation ) {
222                 return 1;
223         }
224         return 0;
225 }
226
227 guint
228 mncp_hash(gconstpointer v)
229 {
230         const mncp_rhash_key    *mncp_key = (const mncp_rhash_key*)v;
231         return GPOINTER_TO_UINT(mncp_key->conversation);
232 }
233
234 /* Initializes the hash table and the mem_chunk area each time a new
235  * file is loaded or re-loaded in ethereal */
236 static void
237 mncp_init_protocol(void)
238 {
239         if (mncp_rhash)
240                 g_hash_table_destroy(mncp_rhash);
241         if (mncp_rhash_keys)
242                 g_mem_chunk_destroy(mncp_rhash_keys);
243         if (mncp_rhash_values)
244                 g_mem_chunk_destroy(mncp_rhash_values);
245
246         mncp_rhash = g_hash_table_new(mncp_hash, mncp_equal);
247         mncp_rhash_keys = g_mem_chunk_new("mncp_rhash_keys",
248                         sizeof(mncp_rhash_key),
249                         200 * sizeof(mncp_rhash_key),
250                         G_ALLOC_ONLY);
251         mncp_rhash_values = g_mem_chunk_new("mncp_rhash_values",
252                         sizeof(mncp_rhash_value),
253                         200 * sizeof(mncp_rhash_value),
254                         G_ALLOC_ONLY);
255 }
256
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. */
260 static void
261 mncp_postseq_cleanup(void)
262 {
263 }
264
265 mncp_rhash_value*
266 mncp_hash_insert(conversation_t *conversation)
267 {
268         mncp_rhash_key          *key;
269         mncp_rhash_value        *value;
270
271         /* Now remember the request, so we can find it if we later
272            a reply to it. */
273         key = g_mem_chunk_alloc(mncp_rhash_keys);
274         key->conversation = conversation;
275
276         value = g_mem_chunk_alloc(mncp_rhash_values);
277         value->packet_signature = FALSE;
278        
279         g_hash_table_insert(mncp_rhash, key, value);
280
281         return value;
282 }
283
284 /* Returns the ncp_rec*, or NULL if not found. */
285 mncp_rhash_value*
286 mncp_hash_lookup(conversation_t *conversation)
287 {
288         mncp_rhash_key          key;
289
290         key.conversation = conversation;
291
292         return g_hash_table_lookup(mncp_rhash, &key);
293 }
294
295 /*
296  * Burst packet system flags.
297  */
298 #define ABT     0x04            /* Abort request */
299 #define BSY 0x08        /* Server Busy */
300 #define EOB     0x10            /* End of burst */
301 #define LST 0x40        /* Include Fragment List */
302 #define SYS     0x80            /* System packet */
303
304 static void
305 dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
306     gboolean is_tcp)
307 {
308         proto_tree                      *ncp_tree = NULL;
309         proto_item                      *ti;
310         struct ncp_ip_header            ncpiph;
311         struct ncp_ip_rqhdr             ncpiphrq;
312         struct ncp_common_header        header;
313         guint16                         nw_connection, ncp_burst_seqno, ncp_ack_seqno;
314         guint16                         flags = 0;
315         char                            flags_str[1+3+1+3+1+3+1+1];
316         char                            *sep;
317         proto_tree                      *flags_tree = NULL;
318         int                             hdr_offset = 0;
319         int                             commhdr;
320         int                             offset = 0;
321         gint                            length_remaining;
322         tvbuff_t                        *next_tvb;
323         guint32                         testvar = 0, ncp_burst_command, burst_len, burst_off, burst_file;
324         guint8                          subfunction;
325         guint32                         data_offset;
326         guint16                         data_len = 0;
327         guint16                         missing_fraglist_count = 0;
328         mncp_rhash_value                *request_value = NULL;
329         conversation_t                  *conversation;
330
331         if (check_col(pinfo->cinfo, COL_PROTOCOL))
332                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
333         if (check_col(pinfo->cinfo, COL_INFO))
334                 col_clear(pinfo->cinfo, COL_INFO);
335
336         hdr_offset = 0;
337
338         if (is_tcp) {
339                 if (tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RQST && tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RPLY) 
340                         hdr_offset += 1;
341                 ncpiph.signature        = tvb_get_ntohl(tvb, hdr_offset);
342                 ncpiph.length           = tvb_get_ntohl(tvb, hdr_offset+4);
343                 hdr_offset += 8;
344                 if (ncpiph.signature == NCPIP_RQST) {
345                         ncpiphrq.version        = tvb_get_ntohl(tvb, hdr_offset);
346                         hdr_offset += 4;
347                         ncpiphrq.rplybufsize    = tvb_get_ntohl(tvb, hdr_offset);
348                         hdr_offset += 4;
349                 }
350                 /* Ok, we need to track the conversation so that we can
351                  * determine if packet signature is occuring for this
352                  * connection. We will store the conversation the first
353                  * time and that state of packet signature will be stored
354                  * later in our logic. This way when we dissect reply
355                  * packets we will be able to determine if we need 
356                  * to also dissect with a signature.
357                  */
358                 conversation = find_conversation(&pinfo->src, &pinfo->dst,
359                     PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport,
360                     0);
361                 if ((ncpiph.length & 0x80000000) ||
362                     ncpiph.signature == NCPIP_RPLY) {
363                         /* First time through we will store packet signature
364                          * state
365                          */
366                         if (!pinfo->fd->flags.visited) {
367                                 if (conversation != NULL) {
368                                         /* find the record telling us the
369                                          * request made that caused this
370                                          * reply
371                                          */
372                                         request_value =
373                                             mncp_hash_lookup(conversation);
374                                         /* if for some reason we have no
375                                          * conversation in our hash, create
376                                          * one */
377                                         if (request_value == NULL) {
378                                                 request_value =
379                                                     mncp_hash_insert(conversation);
380                                         }
381                                 } else {
382                                         /* It's not part of any conversation
383                                          * - create a new one.
384                                          */
385                                         conversation = conversation_new(&pinfo->src,
386                                             &pinfo->dst, PT_NCP,
387                                             (guint32) pinfo->srcport,
388                                             (guint32) pinfo->destport, 0);
389                                         request_value =
390                                             mncp_hash_insert(conversation);
391                                 }
392                                 /* If this is a request packet then we know
393                                  * that we have a signature
394                                  */
395                                 if (ncpiph.signature == NCPIP_RQST) {
396                                         hdr_offset += 8;
397                                         ncpiph.length &= 0x7fffffff;
398                                         request_value->packet_signature=TRUE;
399                                 } else {
400                                         /* Now on reply packets we have to
401                                          * use the state of the original
402                                          * request packet, so look up the
403                                          * request value and check the state
404                                          * of packet signature
405                                          */
406                                         request_value =
407                                             mncp_hash_lookup(conversation);
408                                         if (request_value->packet_signature) {
409                                                 hdr_offset += 8;
410                                                 ncpiph.length &= 0x7fffffff;
411                                                 /* XXX - it already *is* TRUE */
412                                                 request_value->packet_signature=TRUE;
413                                         } else {
414                                                 /* XXX - it already *is* FALSE */
415                                                 request_value->packet_signature=FALSE;
416                                         }
417                                 }
418                         } else {
419                                 /* Get request value data */
420                                 request_value = mncp_hash_lookup(conversation);
421                                 if (request_value->packet_signature) {
422                                         hdr_offset += 8;
423                                         ncpiph.length &= 0x7fffffff;
424                                 }
425                         }
426                 } else {
427                         if (!pinfo->fd->flags.visited) {
428                                 if (conversation != NULL) {
429                                         /* find the record telling us the
430                                          * request made that caused this
431                                          * reply
432                                          */
433                                         request_value =
434                                             mncp_hash_lookup(conversation);
435                                         /* if for some reason we have no
436                                          * conversation in our hash, create
437                                          * one */
438                                         if (request_value == NULL) {
439                                                 request_value =
440                                                     mncp_hash_insert(conversation);
441                                         }
442                                 } else {
443                                         /* It's not part of any conversation
444                                          * - create a new one.
445                                          */
446                                         conversation = conversation_new(&pinfo->src,
447                                             &pinfo->dst, PT_NCP,
448                                             (guint32) pinfo->srcport,
449                                             (guint32) pinfo->destport, 0);
450                                         request_value =
451                                             mncp_hash_insert(conversation);
452                                 }
453                                 /* find the record telling us the request
454                                  * made that caused this reply
455                                  */
456                                 request_value->packet_signature=FALSE;
457                         } else {
458                                 request_value = mncp_hash_lookup(conversation);
459                         }
460                 }
461         }
462
463         /* Record the offset where the NCP common header starts */
464         commhdr = hdr_offset;
465
466         header.type             = tvb_get_ntohs(tvb, commhdr);
467         header.sequence         = tvb_get_guint8(tvb, commhdr+2);
468         header.conn_low         = tvb_get_guint8(tvb, commhdr+3);
469         header.conn_high        = tvb_get_guint8(tvb, commhdr+5);
470
471         if (check_col(pinfo->cinfo, COL_INFO)) {
472             col_add_fstr(pinfo->cinfo, COL_INFO,
473                     "%s",
474                     val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
475         }
476
477         nw_connection = (header.conn_high << 16) + header.conn_low;
478
479         if (tree) {
480                 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE);
481                 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
482
483                 if (is_tcp) {
484                         proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature);
485                         proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length);
486                         if (ncpiph.signature == NCPIP_RQST) {
487                                 proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version);
488                                 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize);
489                                 if (request_value->packet_signature==TRUE)
490                                         proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 16, 8, FALSE);
491                         } else {
492                                 if (request_value->packet_signature==TRUE)
493                                         proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 8, 8, FALSE);
494                         }
495                 }
496                 proto_tree_add_uint(ncp_tree, hf_ncp_type,      tvb, commhdr + 0, 2, header.type);
497         }
498
499
500         /*
501          * Process the packet-type-specific header.
502          */
503         switch (header.type) {
504
505         case NCP_BROADCAST_SLOT:    /* Server Broadcast */
506                 proto_tree_add_uint(ncp_tree, hf_ncp_seq,       tvb, commhdr + 2, 1, header.sequence);
507                 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
508                 proto_tree_add_item(ncp_tree, hf_ncp_task,      tvb, commhdr + 4, 1, FALSE);
509                 proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, FALSE);
510                 proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, FALSE);
511                 break;
512
513         case NCP_LIP_ECHO:    /* Lip Echo Packet */
514                 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 13, FALSE);
515                 break;
516
517         case NCP_BURST_MODE_XFER:       /* Packet Burst Packet */
518                 /*
519                  * XXX - we should keep track of whether there's a burst
520                  * outstanding on a connection and, if not, treat the
521                  * beginning of the data as a burst header.
522                  *
523                  * The burst header contains:
524                  *
525                  *      4 bytes of little-endian function number:
526                  *          1 = read, 2 = write;
527                  *
528                  *      4 bytes of file handle;
529                  *
530                  *      8 reserved bytes;
531                  *
532                  *      4 bytes of big-endian file offset;
533                  *
534                  *      4 bytes of big-endian byte count.
535                  *
536                  * The data follows for a burst write operation.
537                  *
538                  * The first packet of a burst read reply contains:
539                  *
540                  *      4 bytes of little-endian result code:
541                  *         0: No error
542                  *         1: Initial error
543                  *         2: I/O error
544                  *         3: No data read;
545                  *
546                  *      4 bytes of returned byte count (big-endian?).
547                  *
548                  * The data follows.
549                  *
550                  * Each burst of a write request is responded to with a
551                  * burst packet with a 2-byte little-endian result code:
552                  *
553                  *      0: Write successful
554                  *      4: Write error
555                  */
556                 flags = tvb_get_guint8(tvb, commhdr + 2);
557                 strcpy(flags_str, "");
558                 sep = " (";
559                 if (flags & ABT) {
560                         strcat(flags_str, sep);
561                         strcat(flags_str, "ABT");
562                         sep = ",";
563                 }
564                 if (flags & BSY) {
565                         strcat(flags_str, sep);
566                         strcat(flags_str, "BSY");
567                         sep = ",";
568                 }
569                 if (flags & EOB) {
570                         strcat(flags_str, sep);
571                         strcat(flags_str, "EOB");
572                         sep = ",";
573                 }
574                 if (flags & LST) {
575                         strcat(flags_str, sep);
576                         strcat(flags_str, "LST");
577                         sep = ",";
578                 }
579                 if (flags & SYS) {
580                         strcat(flags_str, sep);
581                         strcat(flags_str, "SYS");
582                 }
583                 if (flags_str[0] != '\0')
584                         strcat(flags_str, ")");
585                 ti = proto_tree_add_uint_format(ncp_tree, hf_ncp_system_flags,
586                     tvb, commhdr + 2, 1, flags, "Flags: 0x%04x%s", flags,
587                     flags_str);
588                 flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
589                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
590                     tvb, commhdr + 2, 1, FALSE);
591                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_bsy,
592                     tvb, commhdr + 2, 1, FALSE);
593                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
594                     tvb, commhdr + 2, 1, FALSE);
595                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_lst,
596                     tvb, commhdr + 2, 1, FALSE);
597                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
598                     tvb, commhdr + 2, 1, FALSE);
599
600                 proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
601                     tvb, commhdr + 3, 1, FALSE);
602                 proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
603                     tvb, commhdr + 4, 4, FALSE);
604                 proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
605                     tvb, commhdr + 8, 4, FALSE);
606                 proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
607                     tvb, commhdr + 12, 4, FALSE);
608                 proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
609                     tvb, commhdr + 16, 4, FALSE);
610                 ncp_burst_seqno = tvb_get_ntohs(tvb, commhdr+20);
611                 proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
612                     tvb, commhdr + 20, 2, FALSE);
613                 ncp_ack_seqno = tvb_get_ntohs(tvb, commhdr+22);
614                 proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
615                     tvb, commhdr + 22, 2, FALSE);
616                 proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
617                     tvb, commhdr + 24, 4, FALSE);
618                 data_offset = tvb_get_ntohl(tvb, commhdr + 28);
619                 proto_tree_add_uint(ncp_tree, hf_ncp_data_offset,
620                     tvb, commhdr + 28, 4, data_offset);
621                 data_len = tvb_get_ntohs(tvb, commhdr + 32);
622                 proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
623                     tvb, commhdr + 32, 2, data_len);
624                 missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
625                 proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
626                     tvb, commhdr + 34, 2, FALSE);
627                 offset = commhdr + 36;
628                 if (!(flags & SYS) && ncp_burst_seqno == ncp_ack_seqno &&
629                     data_offset == 0) {
630                         /*
631                          * This is either a Burst Read or Burst Write
632                          * command.  The data length includes the burst
633                          * mode header, plus any data in the command
634                          * (there shouldn't be any in a read, but there
635                          * might be some in a write).
636                          */
637                         if (data_len < 4)
638                                 return;
639                         ncp_burst_command = tvb_get_ntohl(tvb, offset);
640                         proto_tree_add_item(ncp_tree, hf_ncp_burst_command,
641                             tvb, offset, 4, FALSE);
642                         offset += 4;
643                         data_len -= 4;
644
645                         if (data_len < 4)
646                                 return;
647                         burst_file = tvb_get_ntohl(tvb, offset);
648                         proto_tree_add_item(ncp_tree, hf_ncp_burst_file_handle,
649                             tvb, offset, 4, FALSE);
650                         offset += 4;
651                         data_len -= 4;
652
653                         if (data_len < 8)
654                                 return;
655                         proto_tree_add_item(ncp_tree, hf_ncp_burst_reserved,
656                             tvb, offset, 8, FALSE);
657                         offset += 8;
658                         data_len -= 8;
659
660                         if (data_len < 4)
661                                 return;
662                         burst_off = tvb_get_ntohl(tvb, offset);
663                         proto_tree_add_uint(ncp_tree, hf_ncp_burst_offset,
664                             tvb, offset, 4, burst_off);
665                         offset += 4;
666                         data_len -= 4;
667
668                         if (data_len < 4)
669                                 return;
670                         burst_len = tvb_get_ntohl(tvb, offset);
671                         proto_tree_add_uint(ncp_tree, hf_ncp_burst_len,
672                             tvb, offset, 4, burst_len);
673                         offset += 4;
674                         data_len -= 4;
675
676                         if (check_col(pinfo->cinfo, COL_INFO)) {
677                                 col_add_fstr(pinfo->cinfo, COL_INFO,
678                                     "%s %d bytes starting at offset %d in file 0x%08x",
679                                     val_to_str(ncp_burst_command,
680                                       burst_command, "Unknown (0x%08x)"),
681                                      burst_len, burst_off, burst_file);
682                         }
683                         break;
684                 } else {
685                         if (tvb_get_guint8(tvb, commhdr + 2) & 0x10) {
686                                 if (check_col(pinfo->cinfo, COL_INFO)) {
687                                         col_set_str(pinfo->cinfo, COL_INFO,
688                                             "End of Burst");
689                                 }
690                         }
691                 }
692                 break;
693
694         case NCP_ALLOCATE_SLOT:         /* Allocate Slot Request */
695                 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
696                 if (length_remaining > 4) { 
697                         testvar = tvb_get_ntohl(tvb, commhdr+4);
698                         if (testvar == 0x4c495020) {
699                                 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr+4, 13, FALSE);
700                                 break;
701                         }
702                 }
703                 /* otherwise fall through */
704     
705         case NCP_POSITIVE_ACK:          /* Positive Acknowledgement */
706         case NCP_SERVICE_REQUEST:       /* Server NCP Request */
707         case NCP_SERVICE_REPLY:         /* Server NCP Reply */
708         case NCP_WATCHDOG:              /* Watchdog Packet */
709         case NCP_DEALLOCATE_SLOT:       /* Deallocate Slot Request */
710         default:
711                 proto_tree_add_uint(ncp_tree, hf_ncp_seq,       tvb, commhdr + 2, 1, header.sequence);
712                 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
713                 proto_tree_add_item(ncp_tree, hf_ncp_task,      tvb, commhdr + 4, 1, FALSE);
714                 break;
715         }
716
717         /*
718          * Process the packet body.
719          */
720         switch (header.type) {
721
722         case NCP_ALLOCATE_SLOT:         /* Allocate Slot Request */
723                 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
724                 if (length_remaining > 4) {
725                         testvar = tvb_get_ntohl(tvb, commhdr+4);
726                         if (testvar == 0x4c495020) {
727                                 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
728                                     "Lip Echo Packet");
729                                 /*break;*/
730                         }
731                 }
732
733         case NCP_SERVICE_REQUEST:       /* Server NCP Request */
734         case NCP_DEALLOCATE_SLOT:       /* Deallocate Slot Request */
735         case NCP_BROADCAST_SLOT:        /* Server Broadcast Packet */
736                 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
737                 if (tvb_get_guint8(tvb, commhdr+6) == 0x68) {
738                         subfunction = tvb_get_guint8(tvb, commhdr+7);
739                         switch (subfunction) {
740
741                         case 0x02:      /* NDS Frag Packet to decode */
742                                 dissect_nds_request(next_tvb, pinfo,
743                                     nw_connection, header.sequence,
744                                     header.type, ncp_tree);
745                                 break;
746
747                         case 0x01:      /* NDS Ping */
748                                 dissect_ping_req(next_tvb, pinfo,
749                                     nw_connection, header.sequence,
750                                     header.type, ncp_tree);
751                                 break;
752
753                         default:
754                                 dissect_ncp_request(next_tvb, pinfo,
755                                     nw_connection, header.sequence,
756                                     header.type, ncp_tree);
757                                 break;
758                          }
759                 } else {
760                         dissect_ncp_request(next_tvb, pinfo, nw_connection,
761                             header.sequence, header.type, ncp_tree);
762                 }
763                 break;
764
765         case NCP_SERVICE_REPLY:         /* Server NCP Reply */
766                 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
767                 nds_defrag(next_tvb, pinfo, nw_connection, header.sequence,
768                     header.type, ncp_tree);
769                 break;
770
771         case NCP_POSITIVE_ACK:          /* Positive Acknowledgement */
772                 /*
773                  * XXX - this used to call "nds_defrag()", which would
774                  * clear out "frags".  Was that the right thing to
775                  * do?
776                  */
777                 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
778                 dissect_ncp_reply(next_tvb, pinfo, nw_connection,
779                     header.sequence, header.type, ncp_tree);
780                 break;
781
782         case NCP_WATCHDOG:              /* Watchdog Packet */
783                 /*
784                  * XXX - should the completion code be interpreted as
785                  * it is in "packet-ncp2222.inc"?  If so, this
786                  * packet should be handled by "dissect_ncp_reply()".
787                  */
788                 proto_tree_add_item(ncp_tree, hf_ncp_completion_code,
789                     tvb, commhdr + 6, 1, TRUE);
790                 proto_tree_add_item(ncp_tree, hf_ncp_connection_status,
791                     tvb, commhdr + 7, 1, TRUE);
792                 proto_tree_add_item(ncp_tree, hf_ncp_slot,
793                     tvb, commhdr + 8, 1, TRUE);
794                 proto_tree_add_item(ncp_tree, hf_ncp_control_code,
795                     tvb, commhdr + 9, 1, TRUE);
796                 /*
797                  * Display the rest of the packet as data.
798                  */
799                 if (tvb_offset_exists(tvb, commhdr + 10)) {
800                         call_dissector(data_handle,
801                             tvb_new_subset(tvb, commhdr + 10, -1, -1),
802                             pinfo, ncp_tree);
803                 }
804                 break;
805
806         case NCP_BURST_MODE_XFER:       /* Packet Burst Packet */
807                 if (flags & SYS) {
808                         /*
809                          * System packet; show missing fragments if there
810                          * are any.
811                          */
812                         while (missing_fraglist_count != 0) {
813                                 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
814                                     tvb, offset, 4, FALSE);
815                                 offset += 4;
816                                 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
817                                     tvb, offset, 2, FALSE);
818                                 offset += 2;
819                                 missing_fraglist_count--;
820                         }
821                 } else {
822                         /*
823                          * XXX - do this by using -1 and -1 as the length
824                          * arguments to "tvb_new_subset()" and then calling
825                          * "tvb_set_reported_length()"?  That'll throw an
826                          * exception if "data_len" goes past the reported
827                          * length of the packet, but that's arguably a
828                          * feature in this case.
829                          */
830                         length_remaining = tvb_length_remaining(tvb, offset);
831                         if (length_remaining > data_len)
832                                 length_remaining = data_len;
833                         if (data_len != 0) {
834                                 call_dissector(data_handle,
835                                     tvb_new_subset(tvb, offset,
836                                         length_remaining, data_len),
837                                     pinfo, ncp_tree);
838                         }
839                 }
840                 break;
841
842         case NCP_LIP_ECHO:              /* LIP Echo Packet */
843                 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
844                     "Lip Echo Packet");
845                 break;
846
847         default:
848                 if (tree) {
849                     proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1,
850                             "%s packets not supported yet",
851                             val_to_str(header.type, ncp_type_vals,
852                                 "Unknown type (0x%04x)"));
853                 }
854                 break;
855         }
856 }
857
858 static void
859 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
860 {
861         dissect_ncp_common(tvb, pinfo, tree, FALSE);
862 }
863
864 static guint
865 get_ncp_pdu_len(tvbuff_t *tvb, int offset)
866 {
867   guint32 signature;
868
869   /*
870    * Check the NCP-over-TCP header signature, to make sure it's there.
871    * If it's not there, we cannot trust the next 4 bytes to be a
872    * packet length+"has signature" flag, so we just say the length is
873    * "what remains in the packet".
874    */
875   /*if (tvb_get_guint8(tvb, offset)==0xff) 
876   {
877       offset += 1;
878   }*/
879   signature = tvb_get_ntohl(tvb, offset);
880   if (signature != NCPIP_RQST && signature != NCPIP_RPLY)
881     return tvb_length_remaining(tvb, offset);
882
883   /*
884    * Get the length of the NCP-over-TCP packet.  Strip off the "has
885    * signature" flag.
886    */
887
888   return tvb_get_ntohl(tvb, offset + 4) & 0x7fffffff;
889 }
890
891 static void
892 dissect_ncp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
893 {
894   dissect_ncp_common(tvb, pinfo, tree, TRUE);
895 }
896
897 static void
898 dissect_ncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
899 {
900   tcp_dissect_pdus(tvb, pinfo, tree, ncp_desegment, 8, get_ncp_pdu_len,
901         dissect_ncp_tcp_pdu);
902 }
903
904 void
905 proto_register_ncp(void)
906 {
907
908   static hf_register_info hf[] = {
909     { &hf_ncp_ip_sig,
910       { "NCP over IP signature",        "ncp.ip.signature",
911         FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
912         "", HFILL }},
913     { &hf_ncp_ip_length,
914       { "NCP over IP length",           "ncp.ip.length",
915         FT_UINT32, BASE_DEC, NULL, 0x0,
916         "", HFILL }},
917     { &hf_ncp_ip_ver,
918       { "NCP over IP Version",          "ncp.ip.version",
919         FT_UINT32, BASE_DEC, NULL, 0x0,
920         "", HFILL }},
921     { &hf_ncp_ip_rplybufsize,
922       { "NCP over IP Reply Buffer Size",        "ncp.ip.replybufsize",
923         FT_UINT32, BASE_DEC, NULL, 0x0,
924         "", HFILL }},
925     { &hf_ncp_ip_packetsig,
926       { "NCP over IP Packet Signature", "ncp.ip.packetsig",
927         FT_BYTES, BASE_NONE, NULL, 0x0,
928         "", HFILL }},
929     { &hf_ncp_type,
930       { "Type",                 "ncp.type",
931         FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
932         "NCP message type", HFILL }},
933     { &hf_ncp_seq,
934       { "Sequence Number",      "ncp.seq",
935         FT_UINT8, BASE_DEC, NULL, 0x0,
936         "", HFILL }},
937     { &hf_ncp_connection,
938       { "Connection Number",    "ncp.connection",
939         FT_UINT16, BASE_DEC, NULL, 0x0,
940         "", HFILL }},
941     { &hf_ncp_task,
942       { "Task Number",          "ncp.task",
943         FT_UINT8, BASE_DEC, NULL, 0x0,
944         "", HFILL }},
945     { &hf_ncp_oplock_flag,
946       { "Oplock Flag",    "ncp.oplock_flag",
947         FT_UINT8, BASE_HEX, NULL, 0x0,
948         "", HFILL }},
949     { &hf_ncp_oplock_handle,
950       { "File Handle",    "ncp.oplock_handle",
951         FT_UINT16, BASE_HEX, NULL, 0x0,
952         "", HFILL }},
953     { &hf_ncp_stream_type,
954       { "Stream Type",          "ncp.stream_type",
955         FT_UINT8, BASE_HEX, NULL, 0x0,
956         "Type of burst", HFILL }},
957     { &hf_ncp_system_flags,
958       { "System Flags",         "ncp.system_flags",
959         FT_UINT8, BASE_HEX, NULL, 0x0,
960         "", HFILL }},
961     { &hf_ncp_system_flags_abt,
962       { "ABT",          "ncp.system_flags.abt",
963         FT_BOOLEAN, 8, NULL, ABT,
964         "Is this an abort request?", HFILL }},
965     { &hf_ncp_system_flags_eob,
966       { "EOB",          "ncp.system_flags.eob",
967         FT_BOOLEAN, 8, NULL, EOB,
968         "Is this the last packet of the burst?", HFILL }},
969     { &hf_ncp_system_flags_sys,
970       { "SYS",          "ncp.system_flags.sys",
971         FT_BOOLEAN, 8, NULL, SYS,
972         "Is this a system packet?", HFILL }},
973     { &hf_ncp_system_flags_bsy,
974       { "BSY",          "ncp.system_flags.bsy",
975         FT_BOOLEAN, 8, NULL, BSY,
976         "Is the server busy?", HFILL }},
977     { &hf_ncp_system_flags_lst,
978       { "LST",          "ncp.system_flags.lst",
979         FT_BOOLEAN, 8, NULL, LST,
980         "Return Fragment List?", HFILL }},
981     { &hf_ncp_src_connection,
982       { "Source Connection ID",    "ncp.src_connection",
983         FT_UINT32, BASE_DEC, NULL, 0x0,
984         "The workstation's connection identification number", HFILL }},
985     { &hf_ncp_dst_connection,
986       { "Destination Connection ID",    "ncp.dst_connection",
987         FT_UINT32, BASE_DEC, NULL, 0x0,
988         "The server's connection identification number", HFILL }},
989     { &hf_ncp_packet_seqno,
990       { "Packet Sequence Number",    "ncp.packet_seqno",
991         FT_UINT32, BASE_DEC, NULL, 0x0,
992         "Sequence number of this packet in a burst", HFILL }},
993     { &hf_ncp_delay_time,
994       { "Delay Time",    "ncp.delay_time",      /* in 100 us increments */
995         FT_UINT32, BASE_DEC, NULL, 0x0,
996         "Delay time between consecutive packet sends (100 us increments)", HFILL }},
997     { &hf_ncp_burst_seqno,
998       { "Burst Sequence Number",    "ncp.burst_seqno",
999         FT_UINT16, BASE_DEC, NULL, 0x0,
1000         "Sequence number of this packet in the burst", HFILL }},
1001     { &hf_ncp_ack_seqno,
1002       { "ACK Sequence Number",    "ncp.ack_seqno",
1003         FT_UINT16, BASE_DEC, NULL, 0x0,
1004         "Next expected burst sequence number", HFILL }},
1005     { &hf_ncp_burst_len,
1006       { "Burst Length",    "ncp.burst_len",
1007         FT_UINT32, BASE_DEC, NULL, 0x0,
1008         "Total length of data in this burst", HFILL }},
1009     { &hf_ncp_burst_offset,
1010       { "Burst Offset",    "ncp.burst_offset",
1011         FT_UINT32, BASE_DEC, NULL, 0x0,
1012         "Offset of data in the burst", HFILL }},
1013     { &hf_ncp_data_offset,
1014       { "Data Offset",    "ncp.data_offset",
1015         FT_UINT32, BASE_DEC, NULL, 0x0,
1016         "Offset of this packet", HFILL }},
1017     { &hf_ncp_data_bytes,
1018       { "Data Bytes",    "ncp.data_bytes",
1019         FT_UINT16, BASE_DEC, NULL, 0x0,
1020         "Number of data bytes in this packet", HFILL }},
1021     { &hf_ncp_missing_fraglist_count,
1022       { "Missing Fragment List Count",    "ncp.missing_fraglist_count",
1023         FT_UINT16, BASE_DEC, NULL, 0x0,
1024         "Number of missing fragments reported", HFILL }},
1025     { &hf_ncp_missing_data_offset,
1026       { "Missing Data Offset",    "ncp.missing_data_offset",
1027         FT_UINT32, BASE_DEC, NULL, 0x0,
1028         "Offset of beginning of missing data", HFILL }},
1029     { &hf_ncp_missing_data_count,
1030       { "Missing Data Count",    "ncp.missing_data_count",
1031         FT_UINT16, BASE_DEC, NULL, 0x0,
1032         "Number of bytes of missing data", HFILL }},
1033     { &hf_ncp_completion_code,
1034       { "Completion Code",    "ncp.completion_code",
1035         FT_UINT8, BASE_DEC, NULL, 0x0,
1036         "", HFILL }},
1037     { &hf_ncp_connection_status,
1038       { "Connection Status",    "ncp.connection_status",
1039         FT_UINT8, BASE_DEC, NULL, 0x0,
1040         "", HFILL }},
1041     { &hf_ncp_slot,
1042       { "Slot",    "ncp.slot",
1043         FT_UINT8, BASE_DEC, NULL, 0x0,
1044         "", HFILL }},
1045     { &hf_ncp_control_code,
1046       { "Control Code",    "ncp.control_code",
1047         FT_UINT8, BASE_DEC, NULL, 0x0,
1048         "", HFILL }},
1049     { &hf_ncp_fragment_handle,
1050       { "Fragment Handle",    "ncp.fragger_hndl",
1051     FT_UINT16, BASE_HEX, NULL, 0x0,
1052     "", HFILL }},
1053     { &hf_lip_echo,
1054       { "Large Internet Packet Echo",    "ncp.lip_echo",
1055     FT_STRING, BASE_NONE, NULL, 0x0,
1056     "", HFILL }},
1057     { &hf_ncp_burst_command,
1058       { "Burst Command",    "ncp.burst_command",
1059         FT_UINT32, BASE_HEX, VALS(burst_command), 0x0,
1060         "Packet Burst Command", HFILL }},
1061     { &hf_ncp_burst_file_handle,
1062       { "Burst File Handle",    "ncp.file_handle",
1063         FT_UINT32, BASE_HEX, NULL, 0x0,
1064         "Packet Burst File Handle", HFILL }},
1065         { &hf_ncp_burst_reserved,
1066         { "Reserved", "ncp.burst_reserved", 
1067     FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
1068   
1069   };
1070   static gint *ett[] = {
1071     &ett_ncp,
1072     &ett_ncp_system_flags,
1073     &ett_nds,
1074         &ett_nds_segments,
1075         &ett_nds_segment,
1076   };
1077   module_t *ncp_module;
1078
1079   proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
1080   proto_register_field_array(proto_ncp, hf, array_length(hf));
1081   proto_register_subtree_array(ett, array_length(ett));
1082
1083   ncp_module = prefs_register_protocol(proto_ncp, NULL);
1084   prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
1085   prefs_register_bool_preference(ncp_module, "desegment",
1086     "Reassemble NCP-over-TCP messages spanning multiple TCP segments",
1087     "Whether the NCP dissector should reassemble messages spanning multiple TCP segments."
1088     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1089     &ncp_desegment);
1090   prefs_register_bool_preference(ncp_module, "defragment_nds",
1091     "Reassemble fragmented NDS messages spanning multiple packets",
1092     "Whether the NCP dissector should defragment NDS messages spanning multiple packets.",
1093     &nds_defragment);
1094   register_init_routine(&mncp_init_protocol);
1095   register_postseq_cleanup_routine(&mncp_postseq_cleanup);
1096 }
1097
1098 void
1099 proto_reg_handoff_ncp(void)
1100 {
1101   dissector_handle_t ncp_handle;
1102   dissector_handle_t ncp_tcp_handle;
1103
1104   ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
1105   ncp_tcp_handle = create_dissector_handle(dissect_ncp_tcp, proto_ncp);
1106   dissector_add("tcp.port", TCP_PORT_NCP, ncp_tcp_handle);
1107   dissector_add("udp.port", UDP_PORT_NCP, ncp_handle);
1108   dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
1109   dissector_add("ipx.socket", IPX_SOCKET_NCP, ncp_handle);
1110
1111   data_handle = find_dissector("data");
1112 }