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