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