As per a patch from Lars Roland, make RC_VERSION comma-separated.
[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
6  * & NDS packets by Greg Morris <gmorris@novell.com>
7  *
8  * $Id: packet-ncp.c,v 1.72 2002/10/11 19:36:13 guy Exp $
9  *
10  * Ethereal - Network traffic analyzer
11  * By Gerald Combs <gerald@ethereal.com>
12  * Copyright 2000 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #ifdef HAVE_NETINET_IN_H
38 # include <netinet/in.h>
39 #endif
40
41 #include <string.h>
42 #include <glib.h>
43 #include <epan/packet.h>
44 #include <epan/conversation.h>
45 #include "prefs.h"
46 #include "packet-ipx.h"
47 #include "packet-tcp.h"
48 #include "packet-ncp-int.h"
49
50 int proto_ncp = -1;
51 static int hf_ncp_ip_ver = -1;
52 static int hf_ncp_ip_length = -1;
53 static int hf_ncp_ip_rplybufsize = -1;
54 static int hf_ncp_ip_sig = -1;
55 static int hf_ncp_ip_packetsig = -1;
56 static int hf_ncp_type = -1;
57 static int hf_ncp_seq = -1;
58 static int hf_ncp_connection = -1;
59 static int hf_ncp_task = -1;
60 static int hf_ncp_stream_type = -1;
61 static int hf_ncp_system_flags = -1;
62 static int hf_ncp_system_flags_abt = -1;
63 static int hf_ncp_system_flags_eob = -1;
64 static int hf_ncp_system_flags_sys = -1;
65 static int hf_ncp_src_connection = -1;
66 static int hf_ncp_dst_connection = -1;
67 static int hf_ncp_packet_seqno = -1;
68 static int hf_ncp_delay_time = -1;
69 static int hf_ncp_burst_seqno = -1;
70 static int hf_ncp_ack_seqno = -1;
71 static int hf_ncp_burst_len = -1;
72 static int hf_ncp_data_offset = -1;
73 static int hf_ncp_data_bytes = -1;
74 static int hf_ncp_missing_fraglist_count = -1;
75 static int hf_ncp_missing_data_offset = -1;
76 static int hf_ncp_missing_data_count = -1;
77 static int hf_ncp_oplock_flag = -1;
78 static int hf_ncp_oplock_handle = -1;
79 static int hf_ncp_completion_code = -1;
80 static int hf_ncp_connection_status = -1;
81 static int hf_ncp_slot = -1;
82 static int hf_ncp_control_code = -1;
83 static int hf_ncp_fragment_handle = -1;
84 static int hf_lip_echo = -1;
85 /*static int hf_ping_version = -1;*/
86
87 gint ett_ncp = -1;
88 gint ett_nds = -1;
89 static gint ett_ncp_system_flags = -1;
90
91 /* desegmentation of NCP over TCP */
92 static gboolean ncp_desegment = TRUE;
93 /*static int ncp_nds_true = FALSE;*/
94
95 static dissector_handle_t data_handle;
96
97 #define TCP_PORT_NCP            524
98 #define UDP_PORT_NCP            524
99
100 #define NCP_RQST_HDR_LENGTH     7
101 #define NCP_RPLY_HDR_LENGTH     8
102
103
104 /* Hash functions */
105 gint  ncp_equal (gconstpointer v, gconstpointer v2);
106 guint ncp_hash  (gconstpointer v);
107
108 /* These are the header structures to handle NCP over IP */
109 #define NCPIP_RQST      0x446d6454      /* "DmdT" */
110 #define NCPIP_RPLY      0x744e6350      /* "tNcP" */
111
112 struct ncp_ip_header {
113         guint32 signature;
114         guint32 length;
115 };
116
117 /* This header only appears on NCP over IP request packets */
118 struct ncp_ip_rqhdr {
119         guint32 version;
120         guint32 rplybufsize;
121 };
122
123 static const value_string ncp_ip_signature[] = {
124         { NCPIP_RQST, "Demand Transport (Request)" },
125         { NCPIP_RPLY, "Transport is NCP (Reply)" },
126         { 0, NULL },
127 };
128
129 /* The information in this module comes from:
130         NetWare LAN Analysis, Second Edition
131         Laura A. Chappell and Dan E. Hakes
132         (c) 1994 Novell, Inc.
133         Novell Press, San Jose.
134         ISBN: 0-7821-1362-1
135
136   And from the ncpfs source code by Volker Lendecke
137
138   And:
139         Programmer's Guide to the NetWare Core Protocol
140         Steve Conner & Diane Conner
141         (c) 1996 by Steve Conner & Diane Conner
142         Published by Annabooks, San Diego, California
143         ISBN: 0-929392-31-0
144         
145  And:
146     http:developer.novell.com
147     NCP documentation        
148
149 */
150
151 /*
152  * Every NCP packet has this common header (except for burst packets).
153  */
154 struct ncp_common_header {
155         guint16 type;
156         guint8  sequence;
157         guint8  conn_low;
158         guint8  task;
159         guint8  conn_high; /* type=0x5555 doesn't have this */
160 };
161
162
163 static value_string ncp_type_vals[] = {
164         { NCP_ALLOCATE_SLOT,    "Create a service connection" },
165         { NCP_SERVICE_REQUEST,  "Service request" },
166         { NCP_SERVICE_REPLY,    "Service reply" },
167         { NCP_WATCHDOG,         "Watchdog" },
168         { NCP_DEALLOCATE_SLOT,  "Destroy service connection" },
169     { NCP_BROADCAST_SLOT,   "Server Broadcast" },
170         { NCP_BURST_MODE_XFER,  "Burst mode transfer" },
171         { NCP_POSITIVE_ACK,     "Request being processed" },
172     { NCP_LIP_ECHO, "Large Internet Packet Echo" },
173         { 0,                    NULL }
174 };
175
176
177 /*
178  * Burst packet system flags.
179  */
180 #define ABT     0x04            /* Abort request */
181 #define EOB     0x10            /* End of burst */
182 #define SYS     0x80            /* System packet */
183
184 static void
185 dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
186     gboolean is_tcp)
187 {
188         proto_tree                      *ncp_tree = NULL;
189         proto_item                      *ti;
190         struct ncp_ip_header            ncpiph;
191         struct ncp_ip_rqhdr             ncpiphrq;
192         gboolean                        is_signed = FALSE;
193         struct ncp_common_header        header;
194         guint16                         nw_connection;
195         guint16                         flags = 0;
196         char                            flags_str[1+3+1+3+1+3+1+1];
197         char                            *sep;
198         proto_tree                      *flags_tree = NULL;
199         guint16                         data_len = 0;
200         guint16                         missing_fraglist_count = 0;
201         int                             hdr_offset = 0;
202         int                             commhdr;
203         int                             offset;
204         gint                            length_remaining;
205         tvbuff_t                        *next_tvb;
206         guint32                         testvar = 0;
207         guint8                          subfunction;
208
209         if (check_col(pinfo->cinfo, COL_PROTOCOL))
210                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
211         if (check_col(pinfo->cinfo, COL_INFO))
212                 col_clear(pinfo->cinfo, COL_INFO);
213
214         if (is_tcp) {
215                 ncpiph.signature        = tvb_get_ntohl(tvb, 0);
216                 ncpiph.length           = tvb_get_ntohl(tvb, 4);
217                 hdr_offset += 8;
218                 if ( ncpiph.signature == NCPIP_RQST ) {
219                         ncpiphrq.version        = tvb_get_ntohl(tvb, hdr_offset);
220                         hdr_offset += 4;
221                         ncpiphrq.rplybufsize    = tvb_get_ntohl(tvb, hdr_offset);
222                         hdr_offset += 4;
223                 }
224                 if (ncpiph.length & 0x80000000) {
225                         /*
226                          * This appears to indicate that this packet
227                          * is signed; the signature is 8 bytes long.
228                          *
229                          * XXX - that bit does *not* appear to be set
230                          * in signed replies, and we can't dissect the
231                          * reply enough to find the matching request
232                          * without knowing whether the reply is
233                          * signed.
234                          *
235                          * XXX - what about NCP-over-IPX signed
236                          * messages?
237                          */
238                         is_signed = TRUE;
239                         hdr_offset += 8;
240                         ncpiph.length &= 0x7fffffff;
241                 }
242         }
243
244         /* Record the offset where the NCP common header starts */
245         commhdr = hdr_offset;
246
247         header.type                 = tvb_get_ntohs(tvb, commhdr);
248         header.sequence         = tvb_get_guint8(tvb, commhdr+2);
249         header.conn_low         = tvb_get_guint8(tvb, commhdr+3);
250         header.conn_high        = tvb_get_guint8(tvb, commhdr+5);
251
252         if (check_col(pinfo->cinfo, COL_INFO)) {
253             col_add_fstr(pinfo->cinfo, COL_INFO,
254                     "%s",
255                     val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
256
257         }
258
259         nw_connection = (header.conn_high << 16) + header.conn_low;
260
261         if (tree) {
262                 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE);
263                 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
264
265                 if (is_tcp) {
266                         proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature);
267                         proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length);
268                         if (ncpiph.signature == NCPIP_RQST) {
269                                 proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version);
270                                 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize);
271                         }
272                         if (is_signed)
273                                 proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, 16, 8, FALSE);
274                 }
275                 proto_tree_add_uint(ncp_tree, hf_ncp_type,      tvb, commhdr + 0, 2, header.type);
276         }
277
278
279         /*
280          * Process the packet-type-specific header.
281          */
282         switch (header.type) {
283
284         case NCP_BROADCAST_SLOT:    /* Server Broadcast */
285                 proto_tree_add_uint(ncp_tree, hf_ncp_seq,       tvb, commhdr + 2, 1, header.sequence);
286                 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
287                 proto_tree_add_item(ncp_tree, hf_ncp_task,      tvb, commhdr + 4, 1, FALSE);
288                 proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, FALSE);
289                 proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, FALSE);
290                 break;
291
292         case NCP_LIP_ECHO:    /* Lip Echo Packet */
293                 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 2, FALSE);
294                 break;
295
296         case NCP_BURST_MODE_XFER:       /* Packet Burst Packet */
297                 /*
298                  * XXX - we should keep track of whether there's a burst
299                  * outstanding on a connection and, if not, treat the
300                  * beginning of the data as a burst header.
301                  *
302                  * The burst header contains:
303                  *
304                  *      4 bytes of little-endian function number:
305                  *          1 = read, 2 = write;
306                  *
307                  *      4 bytes of file handle;
308                  *
309                  *      8 reserved bytes;
310                  *
311                  *      4 bytes of big-endian file offset;
312                  *
313                  *      4 bytes of big-endian byte count.
314                  *
315                  * The data follows for a burst write operation.
316                  *
317                  * The first packet of a burst read reply contains:
318                  *
319                  *      4 bytes of little-endian result code:
320                  *         0: No error
321                  *         1: Initial error
322                  *         2: I/O error
323                  *         3: No data read;
324                  *
325                  *      4 bytes of returned byte count (big-endian?).
326                  *
327                  * The data follows.
328                  *
329                  * Each burst of a write request is responded to with a
330                  * burst packet with a 2-byte little-endian result code:
331                  *
332                  *      0: Write successful
333                  *      4: Write error
334                  */
335                 flags = tvb_get_guint8(tvb, commhdr + 2);
336                 strcpy(flags_str, "");
337                 sep = " (";
338                 if (flags & ABT) {
339                         strcat(flags_str, sep);
340                         strcat(flags_str, "ABT");
341                         sep = ",";
342                 }
343                 if (flags & EOB) {
344                         strcat(flags_str, sep);
345                         strcat(flags_str, "EOB");
346                         sep = ",";
347                 }
348                 if (flags & SYS) {
349                         strcat(flags_str, sep);
350                         strcat(flags_str, "SYS");
351                 }
352                 if (flags_str[0] != '\0')
353                         strcat(flags_str, ")");
354                 ti = proto_tree_add_uint_format(ncp_tree, hf_ncp_system_flags,
355                     tvb, commhdr + 2, 1, flags, "Flags: 0x%04x%s", flags,
356                     flags_str);
357                 flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
358                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
359                     tvb, commhdr + 2, 1, FALSE);
360                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
361                     tvb, commhdr + 2, 1, FALSE);
362                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
363                     tvb, commhdr + 2, 1, FALSE);
364
365                 proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
366                     tvb, commhdr + 3, 1, FALSE);
367                 proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
368                     tvb, commhdr + 4, 4, FALSE);
369                 proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
370                     tvb, commhdr + 8, 4, FALSE);
371                 proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
372                     tvb, commhdr + 12, 4, FALSE);
373                 proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
374                     tvb, commhdr + 16, 4, FALSE);
375                 proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
376                     tvb, commhdr + 20, 2, FALSE);
377                 proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
378                     tvb, commhdr + 22, 2, FALSE);
379                 proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
380                     tvb, commhdr + 24, 4, FALSE);
381                 proto_tree_add_item(ncp_tree, hf_ncp_data_offset,
382                     tvb, commhdr + 28, 4, FALSE);
383                 data_len = tvb_get_ntohs(tvb, commhdr + 32);
384                 proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
385                     tvb, commhdr + 32, 2, data_len);
386                 missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
387                 proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
388                     tvb, commhdr + 34, 2, FALSE);
389                 break;
390
391         case NCP_ALLOCATE_SLOT:         /* Allocate Slot Request */
392                 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
393                 if (length_remaining > 4) { 
394                         testvar = tvb_get_ntohl(tvb, commhdr+4);
395                         if (testvar == 0x4c495020) {
396                                 proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr+4, 13, FALSE);
397                                 break;
398                         }
399                 }
400                 /* otherwise fall through */
401     
402         case NCP_POSITIVE_ACK:          /* Positive Acknowledgement */
403         case NCP_SERVICE_REQUEST:       /* Server NCP Request */
404         case NCP_SERVICE_REPLY:         /* Server NCP Reply */
405         case NCP_WATCHDOG:              /* Watchdog Packet */
406         case NCP_DEALLOCATE_SLOT:       /* Deallocate Slot Request */
407         default:
408                 proto_tree_add_uint(ncp_tree, hf_ncp_seq,       tvb, commhdr + 2, 1, header.sequence);
409                 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
410                 proto_tree_add_item(ncp_tree, hf_ncp_task,      tvb, commhdr + 4, 1, FALSE);
411                 break;
412         }
413
414         /*
415          * Process the packet body.
416          */
417         switch (header.type) {
418
419         case NCP_ALLOCATE_SLOT:         /* Allocate Slot Request */
420                 length_remaining = tvb_length_remaining(tvb, commhdr + 4);
421                 if (length_remaining > 4) {
422                         testvar = tvb_get_ntohl(tvb, commhdr+4);
423                         if (testvar == 0x4c495020) {
424                                 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
425                                     "Lip Echo Packet");
426                                 /*break;*/
427                         }
428                 }
429
430         case NCP_SERVICE_REQUEST:       /* Server NCP Request */
431         case NCP_DEALLOCATE_SLOT:       /* Deallocate Slot Request */
432         case NCP_BROADCAST_SLOT:        /* Server Broadcast Packet */
433                 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
434                 if (tvb_get_guint8(tvb, commhdr+6) == 0x68) {
435                         subfunction = tvb_get_guint8(tvb, commhdr+7);
436                         switch (subfunction) {
437
438                         case 0x02:      /* NDS Frag Packet to decode */
439                                 dissect_nds_request(next_tvb, pinfo,
440                                     nw_connection, header.sequence,
441                                     header.type, ncp_tree);
442                                 break;
443
444                         case 0x01:      /* NDS Ping */
445                                 dissect_ping_req(next_tvb, pinfo,
446                                     nw_connection, header.sequence,
447                                     header.type, ncp_tree);
448                                 break;
449
450                         default:
451                                 dissect_ncp_request(next_tvb, pinfo,
452                                     nw_connection, header.sequence,
453                                     header.type, ncp_tree);
454                                 break;
455                          }
456                 } else {
457                         dissect_ncp_request(next_tvb, pinfo, nw_connection,
458                             header.sequence, header.type, ncp_tree);
459                 }
460                 break;
461
462         case NCP_SERVICE_REPLY:         /* Server NCP Reply */
463         case NCP_POSITIVE_ACK:          /* Positive Acknowledgement */
464                 next_tvb = tvb_new_subset(tvb, hdr_offset, -1, -1);
465                 dissect_ncp_reply(next_tvb, pinfo, nw_connection,
466                         header.sequence, header.type, ncp_tree);
467                 break;
468
469         case NCP_WATCHDOG:              /* Watchdog Packet */
470                 /*
471                  * XXX - should the completion code be interpreted as
472                  * it is in "packet-ncp2222.inc"?  If so, this
473                  * packet should be handled by "dissect_ncp_reply()".
474                  */
475                 proto_tree_add_item(ncp_tree, hf_ncp_completion_code,
476                     tvb, commhdr + 6, 1, TRUE);
477                 proto_tree_add_item(ncp_tree, hf_ncp_connection_status,
478                     tvb, commhdr + 7, 1, TRUE);
479                 proto_tree_add_item(ncp_tree, hf_ncp_slot,
480                     tvb, commhdr + 8, 1, TRUE);
481                 proto_tree_add_item(ncp_tree, hf_ncp_control_code,
482                     tvb, commhdr + 9, 1, TRUE);
483                 /*
484                  * Display the rest of the packet as data.
485                  */
486                 if (tvb_offset_exists(tvb, commhdr + 10)) {
487                         call_dissector(data_handle,
488                             tvb_new_subset(tvb, commhdr + 10, -1, -1),
489                             pinfo, ncp_tree);
490                 }
491                 break;
492
493         case NCP_BURST_MODE_XFER:       /* Packet Burst Packet */
494                 if (flags & SYS) {
495                         /*
496                          * System packet; show missing fragments if there
497                          * are any.
498                          */
499                         offset = commhdr + 36;
500                         while (missing_fraglist_count != 0) {
501                                 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
502                                     tvb, offset, 4, FALSE);
503                                 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
504                                     tvb, offset, 2, FALSE);
505                                 missing_fraglist_count--;
506                         }
507                 } else {
508                         /*
509                          * XXX - do this by using -1 and -1 as the length
510                          * arguments to "tvb_new_subset()" and then calling
511                          * "tvb_set_reported_length()"?  That'll throw an
512                          * exception if "data_len" goes past the reported
513                          * length of the packet, but that's arguably a
514                          * feature in this case.
515                          */
516                         length_remaining = tvb_length_remaining(tvb, commhdr + 36);
517                         if (length_remaining > data_len)
518                                 length_remaining = data_len;
519                         if (data_len != 0) {
520                                 call_dissector(data_handle,
521                                     tvb_new_subset(tvb, commhdr + 36,
522                                         length_remaining, data_len),
523                                     pinfo, ncp_tree);
524                         }
525                 }
526                 break;
527
528         case NCP_LIP_ECHO:              /* LIP Echo Packet */
529                 proto_tree_add_text(ncp_tree, tvb, commhdr, -1,
530                     "Lip Echo Packet");
531                 break;
532
533         default:
534                 if (tree) {
535                     proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1,
536                             "%s packets not supported yet",
537                             val_to_str(header.type, ncp_type_vals,
538                                 "Unknown type (0x%04x)"));
539                 }
540                 break;
541         }
542 }
543
544 static void
545 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
546 {
547         dissect_ncp_common(tvb, pinfo, tree, FALSE);
548 }
549
550 static guint
551 get_ncp_pdu_len(tvbuff_t *tvb, int offset)
552 {
553   guint32 signature;
554
555   /*
556    * Check the NCP-over-TCP header signature, to make sure it's there.
557    * If it's not there, we cannot trust the next 4 bytes to be a
558    * packet length+"has signature" flag, so we just say the length is
559    * "what remains in the packet".
560    */
561   signature = tvb_get_ntohl(tvb, offset);
562   if (signature != NCPIP_RQST && signature != NCPIP_RPLY)
563     return tvb_length_remaining(tvb, offset);
564
565   /*
566    * Get the length of the NCP-over-TCP packet.  Strip off the "has
567    * signature" flag.
568    */
569
570   return tvb_get_ntohl(tvb, offset + 4) & 0x7fffffff;
571 }
572
573 static void
574 dissect_ncp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
575 {
576   dissect_ncp_common(tvb, pinfo, tree, TRUE);
577 }
578
579 static void
580 dissect_ncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
581 {
582   tcp_dissect_pdus(tvb, pinfo, tree, ncp_desegment, 8, get_ncp_pdu_len,
583         dissect_ncp_tcp_pdu);
584 }
585
586 void
587 proto_register_ncp(void)
588 {
589
590   static hf_register_info hf[] = {
591     { &hf_ncp_ip_sig,
592       { "NCP over IP signature",        "ncp.ip.signature",
593         FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
594         "", HFILL }},
595     { &hf_ncp_ip_length,
596       { "NCP over IP length",           "ncp.ip.length",
597         FT_UINT32, BASE_DEC, NULL, 0x0,
598         "", HFILL }},
599     { &hf_ncp_ip_ver,
600       { "NCP over IP Version",          "ncp.ip.version",
601         FT_UINT32, BASE_DEC, NULL, 0x0,
602         "", HFILL }},
603     { &hf_ncp_ip_rplybufsize,
604       { "NCP over IP Reply Buffer Size",        "ncp.ip.replybufsize",
605         FT_UINT32, BASE_DEC, NULL, 0x0,
606         "", HFILL }},
607     { &hf_ncp_ip_packetsig,
608       { "NCP over IP Packet Signature", "ncp.ip.packetsig",
609         FT_BYTES, BASE_NONE, NULL, 0x0,
610         "", HFILL }},
611     { &hf_ncp_type,
612       { "Type",                 "ncp.type",
613         FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
614         "NCP message type", HFILL }},
615     { &hf_ncp_seq,
616       { "Sequence Number",      "ncp.seq",
617         FT_UINT8, BASE_DEC, NULL, 0x0,
618         "", HFILL }},
619     { &hf_ncp_connection,
620       { "Connection Number",    "ncp.connection",
621         FT_UINT16, BASE_DEC, NULL, 0x0,
622         "", HFILL }},
623     { &hf_ncp_task,
624       { "Task Number",          "ncp.task",
625         FT_UINT8, BASE_DEC, NULL, 0x0,
626         "", HFILL }},
627     { &hf_ncp_oplock_flag,
628       { "Oplock Flag",    "ncp.oplock_flag",
629         FT_UINT8, BASE_HEX, NULL, 0x0,
630         "", HFILL }},
631     { &hf_ncp_oplock_handle,
632       { "File Handle",    "ncp.oplock_handle",
633         FT_UINT16, BASE_HEX, NULL, 0x0,
634         "", HFILL }},
635     { &hf_ncp_stream_type,
636       { "Stream Type",          "ncp.stream_type",
637         FT_UINT8, BASE_HEX, NULL, 0x0,
638         "Type of burst", HFILL }},
639     { &hf_ncp_system_flags,
640       { "System Flags",         "ncp.system_flags",
641         FT_UINT8, BASE_HEX, NULL, 0x0,
642         "", HFILL }},
643     { &hf_ncp_system_flags_abt,
644       { "ABT",          "ncp.system_flags.abt",
645         FT_BOOLEAN, 8, NULL, ABT,
646         "Is this an abort request?", HFILL }},
647     { &hf_ncp_system_flags_eob,
648       { "EOB",          "ncp.system_flags.eob",
649         FT_BOOLEAN, 8, NULL, EOB,
650         "Is this the last packet of the burst?", HFILL }},
651     { &hf_ncp_system_flags_sys,
652       { "SYS",          "ncp.system_flags.sys",
653         FT_BOOLEAN, 8, NULL, SYS,
654         "Is this a system packet?", HFILL }},
655     { &hf_ncp_src_connection,
656       { "Source Connection ID",    "ncp.src_connection",
657         FT_UINT32, BASE_DEC, NULL, 0x0,
658         "The workstation's connection identification number", HFILL }},
659     { &hf_ncp_dst_connection,
660       { "Destination Connection ID",    "ncp.dst_connection",
661         FT_UINT32, BASE_DEC, NULL, 0x0,
662         "The server's connection identification number", HFILL }},
663     { &hf_ncp_packet_seqno,
664       { "Packet Sequence Number",    "ncp.packet_seqno",
665         FT_UINT32, BASE_DEC, NULL, 0x0,
666         "Sequence number of this packet in a burst", HFILL }},
667     { &hf_ncp_delay_time,
668       { "Delay Time",    "ncp.delay_time",      /* in 100 us increments */
669         FT_UINT32, BASE_DEC, NULL, 0x0,
670         "Delay time between consecutive packet sends (100 us increments)", HFILL }},
671     { &hf_ncp_burst_seqno,
672       { "Burst Sequence Number",    "ncp.burst_seqno",
673         FT_UINT16, BASE_DEC, NULL, 0x0,
674         "Sequence number of this packet in the burst", HFILL }},
675     { &hf_ncp_ack_seqno,
676       { "ACK Sequence Number",    "ncp.ack_seqno",
677         FT_UINT16, BASE_DEC, NULL, 0x0,
678         "Next expected burst sequence number", HFILL }},
679     { &hf_ncp_burst_len,
680       { "Burst Length",    "ncp.burst_len",
681         FT_UINT32, BASE_DEC, NULL, 0x0,
682         "Total length of data in this burst", HFILL }},
683     { &hf_ncp_data_offset,
684       { "Data Offset",    "ncp.data_offset",
685         FT_UINT32, BASE_DEC, NULL, 0x0,
686         "Offset of this packet in the burst", HFILL }},
687     { &hf_ncp_data_bytes,
688       { "Data Bytes",    "ncp.data_bytes",
689         FT_UINT16, BASE_DEC, NULL, 0x0,
690         "Number of data bytes in this packet", HFILL }},
691     { &hf_ncp_missing_fraglist_count,
692       { "Missing Fragment List Count",    "ncp.missing_fraglist_count",
693         FT_UINT16, BASE_DEC, NULL, 0x0,
694         "Number of missing fragments reported", HFILL }},
695     { &hf_ncp_missing_data_offset,
696       { "Missing Data Offset",    "ncp.missing_data_offset",
697         FT_UINT32, BASE_DEC, NULL, 0x0,
698         "Offset of beginning of missing data", HFILL }},
699     { &hf_ncp_missing_data_count,
700       { "Missing Data Count",    "ncp.missing_data_count",
701         FT_UINT16, BASE_DEC, NULL, 0x0,
702         "Number of bytes of missing data", HFILL }},
703     { &hf_ncp_completion_code,
704       { "Completion Code",    "ncp.completion_code",
705         FT_UINT8, BASE_DEC, NULL, 0x0,
706         "", HFILL }},
707     { &hf_ncp_connection_status,
708       { "Connection Status",    "ncp.connection_status",
709         FT_UINT8, BASE_DEC, NULL, 0x0,
710         "", HFILL }},
711     { &hf_ncp_slot,
712       { "Slot",    "ncp.slot",
713         FT_UINT8, BASE_DEC, NULL, 0x0,
714         "", HFILL }},
715     { &hf_ncp_control_code,
716       { "Control Code",    "ncp.control_code",
717         FT_UINT8, BASE_DEC, NULL, 0x0,
718         "", HFILL }},
719     { &hf_ncp_fragment_handle,
720       { "Fragment Handle",    "ncp.fragger_hndl",
721     FT_UINT16, BASE_HEX, NULL, 0x0,
722     "", HFILL }},
723     { &hf_lip_echo,
724       { "Large Internet Packet Echo",    "ncp.lip_echo",
725     FT_STRING, BASE_NONE, NULL, 0x0,
726     "", HFILL }},
727   
728   };
729   static gint *ett[] = {
730     &ett_ncp,
731     &ett_ncp_system_flags,
732     &ett_nds,
733   };
734   module_t *ncp_module;
735
736   proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
737   proto_register_field_array(proto_ncp, hf, array_length(hf));
738   proto_register_subtree_array(ett, array_length(ett));
739
740   ncp_module = prefs_register_protocol(proto_ncp, NULL);
741   prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
742   prefs_register_bool_preference(ncp_module, "desegment",
743     "Desegment all NCP-over-TCP messages spanning multiple segments",
744     "Whether the NCP dissector should desegment all messages spanning multiple TCP segments",
745     &ncp_desegment);
746 }
747
748 void
749 proto_reg_handoff_ncp(void)
750 {
751   dissector_handle_t ncp_handle;
752   dissector_handle_t ncp_tcp_handle;
753
754   ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
755   ncp_tcp_handle = create_dissector_handle(dissect_ncp_tcp, proto_ncp);
756   dissector_add("tcp.port", TCP_PORT_NCP, ncp_tcp_handle);
757   dissector_add("udp.port", UDP_PORT_NCP, ncp_handle);
758   dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
759   dissector_add("ipx.socket", IPX_SOCKET_NCP, ncp_handle);
760
761   data_handle = find_dissector("data");
762 }
763
764