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