Set the Info column as soon as we have enough information to do so.
[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.58 2002/05/15 06:50:33 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-ncp-int.h"
46
47 int proto_ncp = -1;
48 static int hf_ncp_ip_ver = -1;
49 static int hf_ncp_ip_length = -1;
50 static int hf_ncp_ip_rplybufsize = -1;
51 static int hf_ncp_ip_sig = -1;
52 static int hf_ncp_type = -1;
53 static int hf_ncp_seq = -1;
54 static int hf_ncp_connection = -1;
55 static int hf_ncp_task = -1;
56 static int hf_ncp_stream_type = -1;
57 static int hf_ncp_system_flags = -1;
58 static int hf_ncp_system_flags_abt = -1;
59 static int hf_ncp_system_flags_eob = -1;
60 static int hf_ncp_system_flags_sys = -1;
61 static int hf_ncp_src_connection = -1;
62 static int hf_ncp_dst_connection = -1;
63 static int hf_ncp_packet_seqno = -1;
64 static int hf_ncp_delay_time = -1;
65 static int hf_ncp_burst_seqno = -1;
66 static int hf_ncp_ack_seqno = -1;
67 static int hf_ncp_burst_len = -1;
68 static int hf_ncp_data_offset = -1;
69 static int hf_ncp_data_bytes = -1;
70 static int hf_ncp_missing_fraglist_count = -1;
71 static int hf_ncp_missing_data_offset = -1;
72 static int hf_ncp_missing_data_count = -1;
73
74 gint ett_ncp = -1;
75 static gint ett_ncp_system_flags = -1;
76
77 #define TCP_PORT_NCP            524
78 #define UDP_PORT_NCP            524
79
80 #define NCP_RQST_HDR_LENGTH     7
81 #define NCP_RPLY_HDR_LENGTH     8
82
83 /* Hash functions */
84 gint  ncp_equal (gconstpointer v, gconstpointer v2);
85 guint ncp_hash  (gconstpointer v);
86
87 /* These are the header structures to handle NCP over IP */
88 #define NCPIP_RQST      0x446d6454      /* "DmdT" */
89 #define NCPIP_RPLY      0x744e6350      /* "tNcP" */
90
91 struct ncp_ip_header {
92         guint32 signature;
93         guint32 length;
94 };
95
96 /* This header only appears on NCP over IP request packets */
97 struct ncp_ip_rqhdr {
98         guint32 version;
99         guint32 rplybufsize;
100 };
101
102 static const value_string ncp_ip_signature[] = {
103         { NCPIP_RQST, "Demand Transport (Request)" },
104         { NCPIP_RPLY, "Transport is NCP (Reply)" },
105         { 0, NULL },
106 };
107
108 /* The information in this module comes from:
109         NetWare LAN Analysis, Second Edition
110         Laura A. Chappell and Dan E. Hakes
111         (c) 1994 Novell, Inc.
112         Novell Press, San Jose.
113         ISBN: 0-7821-1362-1
114
115   And from the ncpfs source code by Volker Lendecke
116
117   And:
118         Programmer's Guide to the NetWare Core Protocol
119         Steve Conner & Diane Conner
120         (c) 1996 by Steve Conner & Diane Conner
121         Published by Annabooks, San Diego, California
122         ISBN: 0-929392-31-0
123
124 */
125
126 /*
127  * Every NCP packet has this common header (except for burst packets).
128  */
129 struct ncp_common_header {
130         guint16 type;
131         guint8  sequence;
132         guint8  conn_low;
133         guint8  task;
134         guint8  conn_high; /* type=0x5555 doesn't have this */
135 };
136
137
138 static value_string ncp_type_vals[] = {
139         { 0x1111, "Create a service connection" },
140         { 0x2222, "Service request" },
141         { 0x3333, "Service reply" },
142         { 0x5555, "Destroy service connection" },
143         { 0x7777, "Burst mode transfer" },
144         { 0x9999, "Request being processed" },
145         { 0x0000, NULL }
146 };
147
148
149 /*
150  * Burst packet system flags.
151  */
152 #define ABT     0x04            /* Abort request */
153 #define EOB     0x10            /* End of burst */
154 #define SYS     0x80            /* System packet */
155
156 static void
157 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
158 {
159         proto_tree                      *ncp_tree = NULL;
160         proto_item                      *ti;
161         struct ncp_ip_header            ncpiph;
162         struct ncp_ip_rqhdr             ncpiphrq;
163         struct ncp_common_header        header;
164         guint16                         nw_connection;
165         guint16                         flags;
166         char                            flags_str[1+3+1+3+1+3+1+1];
167         char                            *sep;
168         proto_tree                      *flags_tree = NULL;
169         guint16                         data_len;
170         guint16                         missing_fraglist_count;
171         int                             hdr_offset = 0;
172         int                             commhdr;
173         int                             offset;
174         tvbuff_t                        *next_tvb;
175
176         if (check_col(pinfo->cinfo, COL_PROTOCOL))
177                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
178         if (check_col(pinfo->cinfo, COL_INFO))
179                 col_clear(pinfo->cinfo, COL_INFO);
180
181         if ( pinfo->ptype == PT_TCP || pinfo->ptype == PT_UDP ) {
182                 ncpiph.signature        = tvb_get_ntohl(tvb, 0);
183                 ncpiph.length           = tvb_get_ntohl(tvb, 4);
184                 hdr_offset += 8;
185                 if ( ncpiph.signature == NCPIP_RQST ) {
186                         ncpiphrq.version        = tvb_get_ntohl(tvb, hdr_offset);
187                         hdr_offset += 4;
188                         ncpiphrq.rplybufsize    = tvb_get_ntohl(tvb, hdr_offset);
189                         hdr_offset += 4;
190                 };
191         };
192
193         /* Record the offset where the NCP common header starts */
194         commhdr = hdr_offset;
195
196         header.type             = tvb_get_ntohs(tvb, commhdr);
197         header.sequence         = tvb_get_guint8(tvb, commhdr+2);
198         header.conn_low         = tvb_get_guint8(tvb, commhdr+3);
199         header.conn_high        = tvb_get_guint8(tvb, commhdr+5);
200
201         if (check_col(pinfo->cinfo, COL_INFO)) {
202                 col_add_fstr(pinfo->cinfo, COL_INFO,
203                     "%s",
204                     val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
205         }
206
207         nw_connection = (header.conn_high << 16) + header.conn_low;
208
209         if (tree) {
210                 ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE);
211                 ncp_tree = proto_item_add_subtree(ti, ett_ncp);
212
213                 if ( pinfo->ptype == PT_TCP || pinfo->ptype == PT_UDP ) {
214                         proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature);
215                         proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length);
216                         if ( ncpiph.signature == NCPIP_RQST ) {
217                                 proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version);
218                                 proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize);
219                         };
220                 };
221                 proto_tree_add_uint(ncp_tree, hf_ncp_type,      tvb, commhdr + 0, 2, header.type);
222         }
223
224
225         switch (header.type) {
226
227         case 0x1111:    /* "Allocate Slot Request"? */
228         case 0x2222:    /* Server NCP Request */
229                 proto_tree_add_uint(ncp_tree, hf_ncp_seq,       tvb, commhdr + 2, 1, header.sequence);
230                 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
231                 proto_tree_add_item(ncp_tree, hf_ncp_task,      tvb, commhdr + 4, 1, FALSE);
232                 next_tvb = tvb_new_subset( tvb, hdr_offset, -1, -1 );
233                 dissect_ncp_request(next_tvb, pinfo, nw_connection,
234                         header.sequence, header.type, ncp_tree);
235                 break;
236
237         case 0x3333:    /* Server NCP Reply */
238                 proto_tree_add_uint(ncp_tree, hf_ncp_seq,       tvb, commhdr + 2, 1, header.sequence);
239                 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
240                 proto_tree_add_item(ncp_tree, hf_ncp_task,      tvb, commhdr + 4, 1, FALSE);
241                 next_tvb = tvb_new_subset( tvb, hdr_offset, -1, -1 );
242                 dissect_ncp_reply(next_tvb, pinfo, nw_connection,
243                         header.sequence, ncp_tree);
244                 break;
245
246         case 0x5555:    /* Deallocate Slot Request */
247         case 0x9999:    /* Positive Acknowledgement */
248                 proto_tree_add_uint(ncp_tree, hf_ncp_seq,       tvb, commhdr + 2, 1, header.sequence);
249                 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
250                 proto_tree_add_item(ncp_tree, hf_ncp_task,      tvb, commhdr + 4, 1, FALSE);
251                 if (tree) {
252                         proto_tree_add_text(ncp_tree, tvb, commhdr + 0, 2, "Type 0x%04x not supported yet", header.type);
253                 }
254                 break;
255
256
257         case 0x7777:    /* Packet Burst Packet */
258                 /*
259                  * XXX - we should keep track of whether there's a burst
260                  * outstanding on a connection and, if not, treat the
261                  * beginning of the data as a burst header.
262                  *
263                  * The burst header contains:
264                  *
265                  *      4 bytes of little-endian function number:
266                  *          1 = read, 2 = write;
267                  *
268                  *      4 bytes of file handle;
269                  *
270                  *      8 reserved bytes;
271                  *
272                  *      4 bytes of big-endian file offset;
273                  *
274                  *      4 bytes of big-endian byte count.
275                  *
276                  * The data follows for a burst write operation.
277                  *
278                  * The first packet of a burst read reply contains:
279                  *
280                  *      4 bytes of little-endian result code:
281                  *         0: No error
282                  *         1: Initial error
283                  *         2: I/O error
284                  *         3: No data read;
285                  *
286                  *      4 bytes of returned byte count (big-endian?).
287                  *
288                  * The data follows.
289                  *
290                  * Each burst of a write request is responded to with a
291                  * burst packet with a 2-byte little-endian result code:
292                  *
293                  *      0: Write successful
294                  *      4: Write error
295                  */
296                 flags = tvb_get_guint8(tvb, commhdr + 2);
297                 strcpy(flags_str, "");
298                 sep = " (";
299                 if (flags & ABT) {
300                         strcat(flags_str, sep);
301                         strcat(flags_str, "ABT");
302                         sep = ",";
303                 }
304                 if (flags & EOB) {
305                         strcat(flags_str, sep);
306                         strcat(flags_str, "EOB");
307                         sep = ",";
308                 }
309                 if (flags & SYS) {
310                         strcat(flags_str, sep);
311                         strcat(flags_str, "SYS");
312                 }
313                 if (flags_str[0] != '\0')
314                         strcat(flags_str, ")");
315                 ti = proto_tree_add_uint_format(ncp_tree, hf_ncp_system_flags,
316                     tvb, commhdr + 2, 1, flags, "Flags: 0x%04x%s", flags,
317                     flags_str);
318                 flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
319                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
320                     tvb, commhdr + 2, 1, FALSE);
321                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
322                     tvb, commhdr + 2, 1, FALSE);
323                 proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
324                     tvb, commhdr + 2, 1, FALSE);
325
326                 proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
327                     tvb, commhdr + 3, 1, FALSE);
328                 proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
329                     tvb, commhdr + 4, 4, FALSE);
330                 proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
331                     tvb, commhdr + 8, 4, FALSE);
332                 proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
333                     tvb, commhdr + 12, 4, FALSE);
334                 proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
335                     tvb, commhdr + 16, 4, FALSE);
336                 proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
337                     tvb, commhdr + 20, 2, FALSE);
338                 proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
339                     tvb, commhdr + 22, 2, FALSE);
340                 proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
341                     tvb, commhdr + 24, 4, FALSE);
342                 proto_tree_add_item(ncp_tree, hf_ncp_data_offset,
343                     tvb, commhdr + 28, 4, FALSE);
344                 data_len = tvb_get_ntohs(tvb, commhdr + 32);
345                 proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
346                     tvb, commhdr + 32, 2, data_len);
347                 missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
348                 proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
349                     tvb, commhdr + 34, 2, FALSE);
350                 if (flags & SYS) {
351                         /*
352                          * System packet; show missing fragments if there
353                          * are any.
354                          */
355                         offset = commhdr + 36;
356                         while (missing_fraglist_count != 0) {
357                                 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
358                                     tvb, offset, 4, FALSE);
359                                 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
360                                     tvb, offset, 2, FALSE);
361                                 missing_fraglist_count--;
362                         }
363                 } else {
364                         if (data_len != 0) {
365                                 proto_tree_add_text(ncp_tree, tvb, commhdr + 36,
366                                     data_len, "Data");
367                         }
368                 }
369                 break;
370
371         default:
372                 /* The value_string for hf_ncp_type already indicates that this type is unknown.
373                  * Just return and do no more parsing. */
374                 proto_tree_add_uint(ncp_tree, hf_ncp_seq,       tvb, commhdr + 2, 1, header.sequence);
375                 proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
376                 proto_tree_add_item(ncp_tree, hf_ncp_task,      tvb, commhdr + 4, 1, FALSE);
377                 break;
378         }
379 }
380
381
382
383 void
384 proto_register_ncp(void)
385 {
386
387   static hf_register_info hf[] = {
388     { &hf_ncp_ip_sig,
389       { "NCP over IP signature",                "ncp.ip.signature",
390         FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
391         "", HFILL }},
392     { &hf_ncp_ip_length,
393       { "NCP over IP length",           "ncp.ip.length",
394         FT_UINT32, BASE_HEX, NULL, 0x0,
395         "", HFILL }},
396     { &hf_ncp_ip_ver,
397       { "NCP over IP Version",          "ncp.ip.version",
398         FT_UINT32, BASE_DEC, NULL, 0x0,
399         "", HFILL }},
400     { &hf_ncp_ip_rplybufsize,
401       { "NCP over IP Reply Buffer Size",        "ncp.ip.replybufsize",
402         FT_UINT32, BASE_DEC, NULL, 0x0,
403         "", HFILL }},
404     { &hf_ncp_type,
405       { "Type",                 "ncp.type",
406         FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
407         "NCP message type", HFILL }},
408     { &hf_ncp_seq,
409       { "Sequence Number",      "ncp.seq",
410         FT_UINT8, BASE_DEC, NULL, 0x0,
411         "", HFILL }},
412     { &hf_ncp_connection,
413       { "Connection Number",    "ncp.connection",
414         FT_UINT16, BASE_DEC, NULL, 0x0,
415         "", HFILL }},
416     { &hf_ncp_task,
417       { "Task Number",          "ncp.task",
418         FT_UINT8, BASE_DEC, NULL, 0x0,
419         "", HFILL }},
420     { &hf_ncp_stream_type,
421       { "Stream Type",          "ncp.stream_type",
422         FT_UINT8, BASE_HEX, NULL, 0x0,
423         "Type of burst", HFILL }},
424     { &hf_ncp_system_flags,
425       { "System Flags",         "ncp.system_flags",
426         FT_UINT8, BASE_HEX, NULL, 0x0,
427         "", HFILL }},
428     { &hf_ncp_system_flags_abt,
429       { "ABT",          "ncp.system_flags.abt",
430         FT_BOOLEAN, 8, NULL, ABT,
431         "Is this an abort request?", HFILL }},
432     { &hf_ncp_system_flags_eob,
433       { "EOB",          "ncp.system_flags.eob",
434         FT_BOOLEAN, 8, NULL, EOB,
435         "Is this the last packet of the burst?", HFILL }},
436     { &hf_ncp_system_flags_sys,
437       { "SYS",          "ncp.system_flags.sys",
438         FT_BOOLEAN, 8, NULL, SYS,
439         "Is this a system packet?", HFILL }},
440     { &hf_ncp_src_connection,
441       { "Source Connection ID",    "ncp.src_connection",
442         FT_UINT32, BASE_DEC, NULL, 0x0,
443         "The workstation's connection identification number", HFILL }},
444     { &hf_ncp_dst_connection,
445       { "Destination Connection ID",    "ncp.dst_connection",
446         FT_UINT32, BASE_DEC, NULL, 0x0,
447         "The server's connection identification number", HFILL }},
448     { &hf_ncp_packet_seqno,
449       { "Packet Sequence Number",    "ncp.packet_seqno",
450         FT_UINT32, BASE_DEC, NULL, 0x0,
451         "Sequence number of this packet in a burst", HFILL }},
452     { &hf_ncp_delay_time,
453       { "Delay Time",    "ncp.delay_time",      /* in 100 us increments */
454         FT_UINT32, BASE_DEC, NULL, 0x0,
455         "Delay time between consecutive packet sends (100 us increments)", HFILL }},
456     { &hf_ncp_burst_seqno,
457       { "Burst Sequence Number",    "ncp.burst_seqno",
458         FT_UINT16, BASE_DEC, NULL, 0x0,
459         "Sequence number of this packet in the burst", HFILL }},
460     { &hf_ncp_ack_seqno,
461       { "ACK Sequence Number",    "ncp.ack_seqno",
462         FT_UINT16, BASE_DEC, NULL, 0x0,
463         "Next expected burst sequence number", HFILL }},
464     { &hf_ncp_burst_len,
465       { "Burst Length",    "ncp.burst_len",
466         FT_UINT32, BASE_DEC, NULL, 0x0,
467         "Total length of data in this burst", HFILL }},
468     { &hf_ncp_data_offset,
469       { "Data Offset",    "ncp.data_offset",
470         FT_UINT32, BASE_DEC, NULL, 0x0,
471         "Offset of this packet in the burst", HFILL }},
472     { &hf_ncp_data_bytes,
473       { "Data Bytes",    "ncp.data_bytes",
474         FT_UINT16, BASE_DEC, NULL, 0x0,
475         "Number of data bytes in this packet", HFILL }},
476     { &hf_ncp_missing_fraglist_count,
477       { "Missing Fragment List Count",    "ncp.missing_fraglist_count",
478         FT_UINT16, BASE_DEC, NULL, 0x0,
479         "Number of missing fragments reported", HFILL }},
480     { &hf_ncp_missing_data_offset,
481       { "Missing Data Offset",    "ncp.missing_data_offset",
482         FT_UINT32, BASE_DEC, NULL, 0x0,
483         "Offset of beginning of missing data", HFILL }},
484     { &hf_ncp_missing_data_count,
485       { "Missing Data Count",    "ncp.missing_data_count",
486         FT_UINT16, BASE_DEC, NULL, 0x0,
487         "Number of bytes of missing data", HFILL }},
488   };
489   static gint *ett[] = {
490     &ett_ncp,
491     &ett_ncp_system_flags,
492   };
493   module_t *ncp_module;
494
495   proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
496   proto_register_field_array(proto_ncp, hf, array_length(hf));
497   proto_register_subtree_array(ett, array_length(ett));
498
499   /* Register an obsolete configuration option for what used to be the
500      initial size of the NCP hash. */
501   ncp_module = prefs_register_protocol_obsolete(proto_ncp);
502   prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
503 }
504
505 void
506 proto_reg_handoff_ncp(void)
507 {
508   dissector_handle_t ncp_handle;
509
510   ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
511   dissector_add("tcp.port", TCP_PORT_NCP, ncp_handle);
512   dissector_add("udp.port", UDP_PORT_NCP, ncp_handle);
513   dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
514   dissector_add("ipx.socket", IPX_SOCKET_NCP, ncp_handle);
515 }