1 /* packet-ncp.c
2  * Routines for NetWare Core Protocol
3  * Gilbert Ramirez <gram@alumni.rice.edu>
4  * Modified to allow NCP over TCP/IP decodes by James Coe <jammer@cin.net>
5  * Modified to decode server op-lock, packet signature,
6  * & NDS packets by Greg Morris <gmorris@novell.com>
7  *
8  * Portions Copyright (c) by Gilbert Ramirez 2000-2002
9  * Portions Copyright (c) by James Coe 2000-2002
10  * Portions Copyright (c) Novell, Inc. 2000-2003
11  *
init(cs_struct * ud)12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 2000 Gerald Combs
15  *
16  * SPDX-License-Identifier: GPL-2.0-or-later
17  */
18 
19 /* XXX:
20    ToDo: Find and fix possible memory leak(s):
21 
22    Example:
23 
24    A 40M capture file with mostly NCP frames results
25    in a 400K-800K memory usage increase each time the file is reloaded.
26 
27    (If the NCP dissection is disabled, there is minimal memory usage
28    increase each time the file is reloaded).
29 */
30 
31 /*
32  * On page 86 of
33  *
34  *   https://www.novell.com/documentation/developer/smscomp/pdfdoc/sms_docs/sms_docs.pdf
35  *
36  * it says:
37  *
38  * The following table lists the wild cards options that can be used in
39  * the terminal path node.
40  *
41  *    Value  Option     Description
42  *    0x2A   ASTERISK   Regular asterisk
43  *    0x3F   QUESTION   Regular question mark
44  *    0xAE   SPERIOD    Special Period-the most significant bit set
45  *    0xAA   SASTERISK. Special Asterisk-the most significant bit set.
46  *    0xBF   SQUESTION  Special Question-with the most significant bit set.
47  *
48  * ASTERISK is '*', and QUESTION is '?'; the "special" versions correspond
49  * to the corresponding ASCII character, but with the upper bit set.
50  *
51  * They do not indicate what "special" means here.  During the painful
52  * process at NetApp of reverse-engineering SMB server wildcard matching;
53  * it turned out that "traditional 8.3 name" matching and "long name"
54  * matching behave differently, and there were separate code points for
55  * "traditional 8.3 name" wildcards and period and "long name" wildcards
56  * and period, so that might be what's involved here.
57  *
58  * How should we display them?  Show the character in question plus a
59  * Unicode COMBINING OVERLINE (U+0305), so they show up as {period,
60  * asterisk, question mark} with an overline, for example?
61  */
62 #include "config.h"
63 
64 #include <epan/packet.h>
65 #include <epan/prefs.h>
66 #include <epan/srt_table.h>
67 #include "packet-ipx.h"
68 #include "packet-tcp.h"
69 #include "packet-ncp-int.h"
70 #include <epan/conversation_table.h>
71 
72 void proto_register_ncp(void);
73 void proto_reg_handoff_ncp(void);
74 
75 int proto_ncp = -1;
76 static int hf_ncp_ip_ver = -1;
77 static int hf_ncp_ip_length = -1;
78 static int hf_ncp_ip_rplybufsize = -1;
79 static int hf_ncp_ip_sig = -1;
80 static int hf_ncp_ip_packetsig = -1;
81 static int hf_ncp_type = -1;
82 static int hf_ncp_seq = -1;
83 static int hf_ncp_connection = -1;
84 static int hf_ncp_task = -1;
85 static int hf_ncp_stream_type = -1;
86 static int hf_ncp_system_flags = -1;
87 static int hf_ncp_system_flags_abt = -1;
88 static int hf_ncp_system_flags_eob = -1;
89 static int hf_ncp_system_flags_sys = -1;
90 static int hf_ncp_system_flags_bsy = -1;
91 static int hf_ncp_system_flags_lst = -1;
92 static int hf_ncp_src_connection = -1;
93 static int hf_ncp_dst_connection = -1;
94 static int hf_ncp_packet_seqno = -1;
95 static int hf_ncp_delay_time = -1;
96 static int hf_ncp_burst_seqno = -1;
97 static int hf_ncp_ack_seqno = -1;
98 static int hf_ncp_burst_len = -1;
99 static int hf_ncp_burst_offset = -1;
100 static int hf_ncp_data_offset = -1;
101 static int hf_ncp_data_bytes = -1;
102 static int hf_ncp_missing_fraglist_count = -1;
103 static int hf_ncp_missing_data_offset = -1;
104 static int hf_ncp_missing_data_count = -1;
105 static int hf_ncp_oplock_flag = -1;
106 static int hf_ncp_oplock_handle = -1;
107 static int hf_ncp_completion_code = -1;
108 static int hf_ncp_connection_status = -1;
109 static int hf_ncp_slot = -1;
110 static int hf_ncp_signature_character = -1;
111 /* static int hf_ncp_fragment_handle = -1; */
112 static int hf_lip_echo_magic = -1;
113 static int hf_lip_echo_payload = -1;
114 static int hf_ncp_burst_command = -1;
115 static int hf_ncp_burst_file_handle = -1;
116 static int hf_ncp_burst_reserved = -1;
117 
118 gint ett_ncp = -1;
119 gint ett_nds = -1;
120 gint ett_nds_segments = -1;
121 gint ett_nds_segment = -1;
122 static gint ett_ncp_system_flags = -1;
123 
124 static expert_field ei_ncp_oplock_handle = EI_INIT;
125 static expert_field ei_ncp_new_server_session = EI_INIT;
126 static expert_field ei_ncp_type = EI_INIT;
127 
128 static struct novell_tap ncp_tap;
129 static struct ncp_common_header     header;
130 static struct ncp_common_header    *ncp_hdr;
131 
132 dissector_handle_t nds_data_handle;
133 
134 /* desegmentation of NCP over TCP */
135 static gboolean ncp_desegment = TRUE;
136 
137 #define TCP_PORT_NCP            524
138 #define UDP_PORT_NCP            524
139 
140 #define NCP_RQST_HDR_LENGTH     7
141 #define NCP_RPLY_HDR_LENGTH     8
142 
143 /* These are the header structures to handle NCP over IP */
144 #define NCPIP_RQST      0x446d6454      /* "DmdT" */
145 #define NCPIP_RPLY      0x744e6350      /* "tNcP" */
146 
147 struct ncp_ip_header {
148     guint32 signature;
149     guint32 length;
150 };
151 
152 /* This header only appears on NCP over IP request packets */
153 struct ncp_ip_rqhdr {
154     guint32 version;
155     guint32 rplybufsize;
156 };
157 
158 static const value_string ncp_sigchar_vals[] = {
159 	{ '?', "Poll inactive station" },
160 	{ 'Y', "Station is still using the connection" },
161 	{ '!', "Broadcast message waiting" },
162 	{ 0, NULL }
163 };
164 
165 static const value_string ncp_ip_signature[] = {
166     { NCPIP_RQST, "Demand Transport (Request)" },
167     { NCPIP_RPLY, "Transport is NCP (Reply)" },
168     { 0, NULL }
169 };
170 
171 static const value_string burst_command[] = {
172     { 0x01000000, "Burst Read" },
173     { 0x02000000, "Burst Write" },
174     { 0, NULL }
175 };
176 
177 /* The information in this module comes from:
178    NetWare LAN Analysis, Second Edition
179    Laura A. Chappell and Dan E. Hakes
180    (c) 1994 Novell, Inc.
181    Novell Press, San Jose.
182    ISBN: 0-7821-1362-1
183 
184    And from the ncpfs source code by Volker Lendecke
185 
186    And:
187    Programmer's Guide to the NetWare Core Protocol
188    Steve Conner & Diane Conner
189    (c) 1996 by Steve Conner & Diane Conner
190    Published by Annabooks, San Diego, California
191    ISBN: 0-929392-31-0
192 
193    And:
194 
195    https://www.novell.com/developer/ndk/netware_core_protocols.html
196 
197    NCP documentation
198 
199    (formerly http:developer.novell.com)
200 
201 */
202 
203 static const value_string ncp_type_vals[] = {
204     { NCP_ALLOCATE_SLOT,    "Create a service connection" },
205     { NCP_SERVICE_REQUEST,  "Service request" },
206     { NCP_SERVICE_REPLY,    "Service reply" },
207     { NCP_WATCHDOG,         "Watchdog" },
208     { NCP_DEALLOCATE_SLOT,  "Destroy service connection" },
209     { NCP_BROADCAST_SLOT,   "Server Broadcast" },
210     { NCP_BURST_MODE_XFER,  "Burst mode transfer" },
211     { NCP_POSITIVE_ACK,     "Request being processed" },
212     { NCP_LIP_ECHO,         "Large Internet Packet Echo" },
213     { 0,                    NULL }
214 };
215 
216 static const value_string ncp_oplock_vals[] = {
217     { 0x21, "Message Waiting" },
218     { 0x24, "Clear Op-lock" },
219     { 0, NULL }
220 };
221 
222 enum ncp_table_values
223 {
224     NCP_NCP_SRT_TABLE_INDEX = 0,
225     NCP_NDS_SRT_TABLE_INDEX,
226     NCP_FUNC_SRT_TABLE_INDEX,
227     NCP_SSS_SRT_TABLE_INDEX,
228     NCP_NMAS_SRT_TABLE_INDEX,
229     NCP_SUB17_SRT_TABLE_INDEX,
230     NCP_SUB21_SRT_TABLE_INDEX,
231     NCP_SUB22_SRT_TABLE_INDEX,
232     NCP_SUB23_SRT_TABLE_INDEX,
233     NCP_SUB32_SRT_TABLE_INDEX,
234     NCP_SUB34_SRT_TABLE_INDEX,
235     NCP_SUB35_SRT_TABLE_INDEX,
236     NCP_SUB36_SRT_TABLE_INDEX,
237     NCP_SUB86_SRT_TABLE_INDEX,
238     NCP_SUB87_SRT_TABLE_INDEX,
239     NCP_SUB89_SRT_TABLE_INDEX,
240     NCP_SUB90_SRT_TABLE_INDEX,
241     NCP_SUB92_SRT_TABLE_INDEX,
242     NCP_SUB94_SRT_TABLE_INDEX,
243     NCP_SUB104_SRT_TABLE_INDEX,
244     NCP_SUB111_SRT_TABLE_INDEX,
245     NCP_SUB114_SRT_TABLE_INDEX,
246     NCP_SUB123_SRT_TABLE_INDEX,
247     NCP_SUB131_SRT_TABLE_INDEX
248 
249 };
250 
251 #define NCP_NUM_PROCEDURES     0
252 
253 static const value_string ncp_group_vals[] = {
254     { 0, "Synchronization" },
255     { 1, "Print" },
256     { 2, "File System" },
257     { 3, "Connection" },
258     { 4, "File Server Environment" },
259     { 5, "Message" },
260     { 6, "Bindery" },
261     { 7, "Queue Management System (QMS)" },
262     { 8, "Accounting" },
263     { 9, "Transaction Tracking" },
264     { 10, "AFP" },
265     { 11, "NCP Extension" },
266     { 12, "Extended Attribute" },
267     { 13, "Auditing" },
268     { 14, "Enhanced File System" },
269     { 15, "Migration" },
270     { 16, "Novell Modular Authentication Services (NMAS)" },
271     { 17, "Secret Store Services (SSS)" },
272     { 18, "Packet Burst" },
273     { 19, "Novell Directory Services (NDS)" },
274     { 20, "Time Synchronization" },
275     { 21, "Server Statistics" },
276     { 22, "Remote" },
277     { 0,  NULL}
278 };
279 
280 WS_DLL_PUBLIC_DEF const value_string sss_verb_enum[] = {
281     { 0x00000000, "Query Server" },
282     { 0x00000001, "Read App Secrets" },
283     { 0x00000002, "Write App Secrets" },
284     { 0x00000003, "Add Secret ID" },
285     { 0x00000004, "Remove Secret ID" },
286     { 0x00000005, "Remove SecretStore" },
287     { 0x00000006, "Enumerate Secret IDs" },
288     { 0x00000007, "Unlock Store" },
289     { 0x00000008, "Set Master Password" },
290     { 0x00000009, "Get Service Information" },
291     { 0x000000ff, "Fragment"},
292     { 0x00000000, NULL}
293 };
294 
295 WS_DLL_PUBLIC_DEF const value_string nmas_subverb_enum[] = {
296     { 0, "Fragmented Ping" },
297     { 2, "Client Put Data" },
298     { 4, "Client Get Data" },
299     { 6, "Client Get User NDS Credentials" },
300     { 8, "Login Store Management" },
301     { 10, "Writable Object Check" },
302     { 1242, "Message Handler" },
303     { 0,  NULL}
304 };
305 
306 WS_DLL_PUBLIC_DEF const value_string ncp_nds_verb_vals[] = {
307     { 1, "Resolve Name" },
308     { 2, "Read Entry Information" },
309     { 3, "Read" },
310     { 4, "Compare" },
311     { 5, "List" },
312     { 6, "Search Entries" },
313     { 7, "Add Entry" },
314     { 8, "Remove Entry" },
315     { 9, "Modify Entry" },
316     { 10, "Modify RDN" },
317     { 11, "Create Attribute" },
318     { 12, "Read Attribute Definition" },
319     { 13, "Remove Attribute Definition" },
320     { 14, "Define Class" },
321     { 15, "Read Class Definition" },
322     { 16, "Modify Class Definition" },
323     { 17, "Remove Class Definition" },
324     { 18, "List Containable Classes" },
325     { 19, "Get Effective Rights" },
326     { 20, "Add Partition" },
327     { 21, "Remove Partition" },
328     { 22, "List Partitions" },
329     { 23, "Split Partition" },
330     { 24, "Join Partitions" },
331     { 25, "Add Replica" },
332     { 26, "Remove Replica" },
333     { 27, "Open Stream" },
334     { 28, "Search Filter" },
335     { 29, "Create Subordinate Reference" },
336     { 30, "Link Replica" },
337     { 31, "Change Replica Type" },
338     { 32, "Start Update Schema" },
339     { 33, "End Update Schema" },
340     { 34, "Update Schema" },
341     { 35, "Start Update Replica" },
342     { 36, "End Update Replica" },
343     { 37, "Update Replica" },
344     { 38, "Synchronize Partition" },
345     { 39, "Synchronize Schema" },
346     { 40, "Read Syntaxes" },
347     { 41, "Get Replica Root ID" },
348     { 42, "Begin Move Entry" },
349     { 43, "Finish Move Entry" },
350     { 44, "Release Moved Entry" },
351     { 45, "Backup Entry" },
352     { 46, "Restore Entry" },
353     { 47, "Save DIB (Obsolete)" },
354     { 48, "Control" },
355     { 49, "Remove Backlink" },
356     { 50, "Close Iteration" },
357     { 51, "Mutate Entry" },
358     { 52, "Audit Skulking" },
359     { 53, "Get Server Address" },
360     { 54, "Set Keys" },
361     { 55, "Change Password" },
362     { 56, "Verify Password" },
363     { 57, "Begin Login" },
364     { 58, "Finish Login" },
365     { 59, "Begin Authentication" },
366     { 60, "Finish Authentication" },
367     { 61, "Logout" },
368     { 62, "Repair Ring (Obsolete)" },
369     { 63, "Repair Timestamps" },
370     { 64, "Create Back Link" },
371     { 65, "Delete External Reference" },
372     { 66, "Rename External Reference" },
373     { 67, "Create Queue Entry Directory" },
374     { 68, "Remove Queue Entry Directory" },
375     { 69, "Merge Entries" },
376     { 70, "Change Tree Name" },
377     { 71, "Partition Entry Count" },
378     { 72, "Check Login Restrictions" },
379     { 73, "Start Join" },
380     { 74, "Low Level Split" },
381     { 75, "Low Level Join" },
382     { 76, "Abort Partition Operation" },
383     { 77, "Get All Servers" },
384     { 78, "Partition Function" },
385     { 79, "Read References" },
386     { 80, "Inspect Entry" },
387     { 81, "Get Remote Entry ID" },
388     { 82, "Change Security" },
389     { 83, "Check Console Operator" },
390     { 84, "Start Move Tree" },
391     { 85, "Move Tree" },
392     { 86, "End Move Tree" },
393     { 87, "Low Level Abort Join" },
394     { 88, "Check Security Equivalence" },
395     { 89, "Merge Tree" },
396     { 90, "Sync External Reference" },
397     { 91, "Resend Entry" },
398     { 92, "New Schema Epoch" },
399     { 93, "Statistics" },
400     { 94, "Ping" },
401     { 95, "Get Bindery Contexts" },
402     { 96, "Monitor Connection" },
403     { 97, "Get DS Statistics" },
404     { 98, "Reset DS Counters" },
405     { 99, "Console" },
406     { 100, "Read Stream" },
407     { 101, "Write Stream" },
408     { 102, "Create Orphan Partition" },
409     { 103, "Remove Orphan Partition" },
410     { 104, "Link Orphan Partition" },
411     { 105, "Set Distributed Reference Link (DRL)" },
412     { 106, "Available" },
413     { 107, "Available" },
414     { 108, "Verify Distributed Reference Link (DRL)" },
415     { 109, "Verify Partition" },
416     { 110, "Iterator" },
417     { 111, "Available" },
418     { 112, "Close Stream" },
419     { 113, "Available" },
420     { 114, "Read Status" },
421     { 115, "Partition Sync Status" },
422     { 116, "Read Reference Data" },
423     { 117, "Write Reference Data" },
424     { 118, "Resource Event" },
425     { 119, "DIB Request (obsolete)" },
426     { 120, "Set Replication Filter" },
427     { 121, "Get Replication Filter" },
428     { 122, "Change Attribute Definition" },
429     { 123, "Schema in Use" },
430     { 124, "Remove Keys" },
431     { 125, "Clone" },
432     { 126, "Multiple Operations Transaction" },
433     { 240, "Ping" },
434     { 255, "EDirectory Call" },
435     { 0,  NULL }
436 };
437 
438 static void
439 ncpstat_init(struct register_srt* srt _U_, GArray* srt_array)
440 {
441     /* Initialize all of the SRT tables with 0 rows.  That way we can "filter" the drawing
442        function to only output tables with rows > 0 */
443 
444     init_srt_table("NCP", "Groups", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.group", NULL);
445 
446     /* NDS Verbs */
447     init_srt_table("NDS Verbs", "NDS", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.ndsverb", NULL);
448 
449     /* NCP Functions */
450     init_srt_table("NCP Functions without Subfunctions", "Functions", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func", NULL);
451 
452     /* Secret Store Verbs */
453     init_srt_table("Secret Store Verbs", "SSS", srt_array, NCP_NUM_PROCEDURES, NULL, "sss.subverb", NULL);
454 
455     /* NMAS Verbs */
456     init_srt_table("NMAS Verbs", "NMAS", srt_array, NCP_NUM_PROCEDURES, NULL, "nmas.subverb", NULL);
457 
458     /* NCP Subfunctions */
459     init_srt_table("Subfunctions for NCP 17", "17", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==17 && ncp.subfunc", NULL);
460     init_srt_table("Subfunctions for NCP 21", "21", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==21 && ncp.subfunc", NULL);
461     init_srt_table("Subfunctions for NCP 22", "22", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==22 && ncp.subfunc", NULL);
462     init_srt_table("Subfunctions for NCP 23", "23", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==23 && ncp.subfunc", NULL);
463     init_srt_table("Subfunctions for NCP 32", "32", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==32 && ncp.subfunc", NULL);
464     init_srt_table("Subfunctions for NCP 34", "34", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==34 && ncp.subfunc", NULL);
465     init_srt_table("Subfunctions for NCP 35", "35", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==35 && ncp.subfunc", NULL);
466     init_srt_table("Subfunctions for NCP 36", "36", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==36 && ncp.subfunc", NULL);
467     init_srt_table("Subfunctions for NCP 86", "86", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==86 && ncp.subfunc", NULL);
468     init_srt_table("Subfunctions for NCP 87", "87", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==87 && ncp.subfunc", NULL);
469     init_srt_table("Subfunctions for NCP 89 (Extended NCP's with UTF8 Support)", "89", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==89 && ncp.subfunc", NULL);
470     init_srt_table("Subfunctions for NCP 90", "90", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==90 && ncp.subfunc", NULL);
471     init_srt_table("Subfunctions for NCP 92 (Secret Store Services)", "92", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==92 && ncp.subfunc", NULL);
472     init_srt_table("Subfunctions for NCP 94 (Novell Modular Authentication Services)", "94", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==94 && ncp.subfunc", NULL);
473     init_srt_table("Subfunctions for NCP 104", "104", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==104 && ncp.subfunc", NULL);
474     init_srt_table("Subfunctions for NCP 111", "111", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==111 && ncp.subfunc", NULL);
475     init_srt_table("Subfunctions for NCP 114", "114", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==114 && ncp.subfunc", NULL);
476     init_srt_table("Subfunctions for NCP 123", "123", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==123 && ncp.subfunc", NULL);
477     init_srt_table("Subfunctions for NCP 131", "131", srt_array, NCP_NUM_PROCEDURES, NULL, "ncp.func==131 && ncp.subfunc", NULL);
478 }
479 
480 static tap_packet_status
481 ncpstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
482 {
483     guint i = 0;
484     srt_stat_table *ncp_srt_table;
485     srt_data_t *data = (srt_data_t *)pss;
486     const ncp_req_hash_value *request_val=(const ncp_req_hash_value *)prv;
487     gchar* tmp_str;
488 
489     /* if we haven't seen the request, just ignore it */
490     if(!request_val || request_val->ncp_rec==0){
491         return TAP_PACKET_DONT_REDRAW;
492     }
493 
494     /* By Group */
495     tmp_str = val_to_str_wmem(NULL, request_val->ncp_rec->group, ncp_group_vals, "Unknown(%u)");
496     i = NCP_NCP_SRT_TABLE_INDEX;
497     ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
498     init_srt_table_row(ncp_srt_table, request_val->ncp_rec->group, tmp_str);
499     wmem_free(NULL, tmp_str);
500     add_srt_table_data(ncp_srt_table, request_val->ncp_rec->group, &request_val->req_frame_time, pinfo);
501     /* By NCP number without subfunction*/
502     if (request_val->ncp_rec->subfunc==0) {
503         i = NCP_FUNC_SRT_TABLE_INDEX;
504         ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
505         init_srt_table_row(ncp_srt_table, request_val->ncp_rec->func, request_val->ncp_rec->name);
506         add_srt_table_data(ncp_srt_table, request_val->ncp_rec->func, &request_val->req_frame_time, pinfo);
507     }
508     /* By Subfunction number */
509     if(request_val->ncp_rec->subfunc!=0){
510         if (request_val->ncp_rec->func==17) {
511             i = NCP_SUB17_SRT_TABLE_INDEX;
512             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
513             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
514             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
515         }
516         if (request_val->ncp_rec->func==21) {
517             i = NCP_SUB21_SRT_TABLE_INDEX;
518             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
519             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
520             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
521         }
522         if (request_val->ncp_rec->func==22) {
523             i = NCP_SUB22_SRT_TABLE_INDEX;
524             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
525             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
526             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
527         }
528         if (request_val->ncp_rec->func==23) {
529             i = NCP_SUB23_SRT_TABLE_INDEX;
530             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
531             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
532             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
533         }
534         if (request_val->ncp_rec->func==32) {
535             i = NCP_SUB32_SRT_TABLE_INDEX;
536             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
537             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
538             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
539         }
540         if (request_val->ncp_rec->func==34) {
541             i = NCP_SUB34_SRT_TABLE_INDEX;
542             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
543             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
544             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
545         }
546         if (request_val->ncp_rec->func==35) {
547             i = NCP_SUB35_SRT_TABLE_INDEX;
548             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
549             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
550             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
551         }
552         if (request_val->ncp_rec->func==36) {
553             i = NCP_SUB36_SRT_TABLE_INDEX;
554             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
555             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
556             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
557         }
558         if (request_val->ncp_rec->func==86) {
559             i = NCP_SUB86_SRT_TABLE_INDEX;
560             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
561             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
562             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
563         }
564         if (request_val->ncp_rec->func==87) {
565             i = NCP_SUB87_SRT_TABLE_INDEX;
566             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
567             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
568             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
569         }
570         if (request_val->ncp_rec->func==89) {
571             i = NCP_SUB89_SRT_TABLE_INDEX;
572             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
573             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
574             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
575         }
576         if (request_val->ncp_rec->func==90) {
577             i = NCP_SUB90_SRT_TABLE_INDEX;
578             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
579             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
580             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
581         }
582         if (request_val->ncp_rec->func==92) {
583             i = NCP_SUB92_SRT_TABLE_INDEX;
584             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
585             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
586             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
587         }
588         if (request_val->ncp_rec->func==94) {
589             i = NCP_SUB94_SRT_TABLE_INDEX;
590             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
591             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
592             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
593         }
594         if (request_val->ncp_rec->func==104) {
595             i = NCP_SUB104_SRT_TABLE_INDEX;
596             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
597             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
598             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
599         }
600         if (request_val->ncp_rec->func==111) {
601             i = NCP_SUB111_SRT_TABLE_INDEX;
602             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
603             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
604             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
605         }
606         if (request_val->ncp_rec->func==114) {
607             i = NCP_SUB114_SRT_TABLE_INDEX;
608             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
609             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
610             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
611         }
612         if (request_val->ncp_rec->func==123) {
613             i = NCP_SUB123_SRT_TABLE_INDEX;
614             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
615             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
616             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
617         }
618         if (request_val->ncp_rec->func==131) {
619             i = NCP_SUB131_SRT_TABLE_INDEX;
620             ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
621             init_srt_table_row(ncp_srt_table, (request_val->ncp_rec->subfunc), request_val->ncp_rec->name);
622             add_srt_table_data(ncp_srt_table, (request_val->ncp_rec->subfunc), &request_val->req_frame_time, pinfo);
623         }
624     }
625     /* By NDS verb */
626     if (request_val->ncp_rec->func==0x68) {
627         tmp_str = val_to_str_wmem(NULL, request_val->nds_request_verb, ncp_nds_verb_vals, "Unknown(%u)");
628         i = NCP_NDS_SRT_TABLE_INDEX;
629         ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
630         init_srt_table_row(ncp_srt_table, (request_val->nds_request_verb), tmp_str);
631         add_srt_table_data(ncp_srt_table, (request_val->nds_request_verb), &request_val->req_frame_time, pinfo);
632         wmem_free(NULL, tmp_str);
633     }
634     if (request_val->ncp_rec->func==0x5c) {
635         tmp_str = val_to_str_wmem(NULL, request_val->req_nds_flags, sss_verb_enum, "Unknown(%u)");
636         i = NCP_SSS_SRT_TABLE_INDEX;
637         ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
638         init_srt_table_row(ncp_srt_table, (request_val->req_nds_flags), tmp_str);
639         add_srt_table_data(ncp_srt_table, (request_val->req_nds_flags), &request_val->req_frame_time, pinfo);
640         wmem_free(NULL, tmp_str);
641     }
642     if (request_val->ncp_rec->func==0x5e) {
643         tmp_str = val_to_str_wmem(NULL, request_val->req_nds_flags, nmas_subverb_enum, "Unknown(%u)");
644         i = NCP_NMAS_SRT_TABLE_INDEX;
645         ncp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
646         init_srt_table_row(ncp_srt_table, (request_val->req_nds_flags), tmp_str);
647         add_srt_table_data(ncp_srt_table, (request_val->req_nds_flags), &request_val->req_frame_time, pinfo);
648         wmem_free(NULL, tmp_str);
649     }
650     return TAP_PACKET_REDRAW;
651 }
652 
653 
654 /* Conversation Struct so we can detect NCP server sessions */
655 
656 typedef struct {
657     conversation_t *conversation;
658     guint32         nwconnection;
659     guint8          nwtask;
660 } mncp_rhash_key;
661 
662 /* Store the packet number for the start of the NCP session.
663  * Note sessions are defined as
664  * NCP Connection + NCP Task == Unique NCP server session
665  * It is normal for multiple sessions per connection to exist
666  * These are normally different applications running on multi-tasking
667  * Operating Systems.
668  */
669 typedef struct {
670     guint32  session_start_packet_num;
671 } mncp_rhash_value;
672 
673 static GHashTable *mncp_rhash = NULL;
674 
675 /* Hash Functions */
676 static gint
677 mncp_equal(gconstpointer v, gconstpointer v2)
678 {
679     const mncp_rhash_key *val1 = (const mncp_rhash_key*)v;
680     const mncp_rhash_key *val2 = (const mncp_rhash_key*)v2;
681 
682     if (val1->conversation == val2->conversation && val1->nwconnection == val2->nwconnection && val1->nwtask == val2->nwtask) {
683         return 1;
684     }
685     return 0;
686 }
687 
688 static guint
689 mncp_hash(gconstpointer v)
690 {
691     const mncp_rhash_key *mncp_key = (const mncp_rhash_key*)v;
692     return GPOINTER_TO_UINT(mncp_key->conversation)+mncp_key->nwconnection+mncp_key->nwtask;
693 }
694 
695 /* Initializes the hash table each time a new
696  * file is loaded or re-loaded in wireshark */
697 static void
698 mncp_init_protocol(void)
699 {
700     mncp_rhash = g_hash_table_new(mncp_hash, mncp_equal);
701 }
702 
703 static void
704 mncp_cleanup_protocol(void)
705 {
706     g_hash_table_destroy(mncp_rhash);
707 }
708 
709 static mncp_rhash_value*
710 mncp_hash_insert(conversation_t *conversation, guint32 nwconnection, guint8 nwtask, packet_info *pinfo)
711 {
712     mncp_rhash_key      *key;
713     mncp_rhash_value    *value;
714 
715     /* Now remember the request, so we can find it if we later
716        a reply to it. Track by conversation, connection, and task number.
717        in NetWare these values determine each unique session */
718     key = wmem_new(wmem_file_scope(), mncp_rhash_key);
719     key->conversation = conversation;
720     key->nwconnection = nwconnection;
721     key->nwtask = nwtask;
722 
723     value = wmem_new(wmem_file_scope(), mncp_rhash_value);
724 
725     g_hash_table_insert(mncp_rhash, key, value);
726 
727     if (ncp_echo_conn && nwconnection != 65535) {
728         expert_add_info_format(pinfo, NULL, &ei_ncp_new_server_session, "Detected New Server Session. Connection %d, Task %d", nwconnection, nwtask);
729         value->session_start_packet_num = pinfo->num;
730     }
731 
732     return value;
733 }
734 
735 /* Returns the ncp_rec*, or NULL if not found. */
736 static mncp_rhash_value*
737 mncp_hash_lookup(conversation_t *conversation, guint32 nwconnection, guint8 nwtask)
738 {
739     mncp_rhash_key        key;
740 
741     key.conversation = conversation;
742     key.nwconnection = nwconnection;
743     key.nwtask = nwtask;
744 
745     return (mncp_rhash_value *)g_hash_table_lookup(mncp_rhash, &key);
746 }
747 
748 static const char* ncp_conv_get_filter_type(conv_item_t* conv _U_, conv_filter_type_e filter)
749 {
750     if ((filter == CONV_FT_SRC_PORT) || (filter == CONV_FT_DST_PORT) || (filter == CONV_FT_ANY_PORT))
751         return "ncp.connection";
752 
753     return CONV_FILTER_INVALID;
754 }
755 
756 static ct_dissector_info_t ncp_ct_dissector_info = {&ncp_conv_get_filter_type};
757 
758 static tap_packet_status
759 ncp_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
760 {
761     conv_hash_t *hash = (conv_hash_t*) pct;
762     const struct ncp_common_header *ncph=(const struct ncp_common_header *)vip;
763     guint32 connection;
764 
765     connection = (ncph->conn_high * 256)+ncph->conn_low;
766     if (connection < 65535) {
767         add_conversation_table_data(hash, &pinfo->src, &pinfo->dst, connection, connection, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->abs_ts, &ncp_ct_dissector_info, ENDPOINT_NCP);
768     }
769 
770     return TAP_PACKET_REDRAW;
771 }
772 
773 static const char* ncp_host_get_filter_type(hostlist_talker_t* host _U_, conv_filter_type_e filter)
774 {
775     return ncp_conv_get_filter_type(NULL, filter);
776 }
777 
778 static hostlist_dissector_info_t ncp_host_dissector_info = {&ncp_host_get_filter_type};
779 
780 static tap_packet_status
781 ncp_hostlist_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip _U_)
782 {
783     conv_hash_t *hash = (conv_hash_t*) pit;
784     /*const ncp_common_header *ncphdr=vip;*/
785 
786     /* Take two "add" passes per packet, adding for each direction, ensures that all
787     packets are counted properly (even if address is sending to itself)
788     XXX - this could probably be done more efficiently inside hostlist_table */
789     add_hostlist_table_data(hash, &pinfo->src, 0, TRUE, 1, pinfo->fd->pkt_len, &ncp_host_dissector_info, ENDPOINT_NCP);
790     add_hostlist_table_data(hash, &pinfo->dst, 0, FALSE, 1, pinfo->fd->pkt_len, &ncp_host_dissector_info, ENDPOINT_NCP);
791 
792     return TAP_PACKET_REDRAW;
793 }
794 
795 /*
796  * Burst packet system flags.
797  */
798 #define ABT 0x04        /* Abort request */
799 #define BSY 0x08        /* Server Busy */
800 #define EOB 0x10        /* End of burst */
801 #define LST 0x40        /* Include Fragment List */
802 #define SYS 0x80        /* System packet */
803 
804 #define LIP_ECHO_MAGIC_LEN 16
805 static char lip_echo_magic[LIP_ECHO_MAGIC_LEN] = {
806     'L', 'I', 'P', ' ', 'E', 'c', 'h', 'o', ' ', 'D', 'a', 't', 'a', ' ', ' ', ' '
807 };
808 
809 static void
810 dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
811     gboolean is_tcp)
812 {
813     proto_tree            *ncp_tree = NULL;
814     proto_item            *ti;
815     struct ncp_ip_header  ncpiph;
816     struct ncp_ip_rqhdr   ncpiphrq;
817     gboolean              is_lip_echo_allocate_slot = FALSE;
818     guint16               ncp_burst_seqno, ncp_ack_seqno;
819     guint16               flags = 0;
820     proto_tree            *flags_tree = NULL;
821     int                   hdr_offset = 0;
822     int                   commhdr = 0;
823     int                   offset = 0;
824     gint                  length_remaining;
825     tvbuff_t              *next_tvb;
826     guint32               ncp_burst_command, burst_len, burst_off, burst_file;
827     guint8                subfunction;
828     guint32               nw_connection = 0, data_offset;
829     guint16               data_len = 0;
830     guint16               missing_fraglist_count = 0;
831     mncp_rhash_value      *request_value = NULL;
832     conversation_t        *conversation;
833 
834     col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP");
835     col_clear(pinfo->cinfo, COL_INFO);
836 
837     ncp_hdr = &header;
838 
839     ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, ENC_NA);
840     ncp_tree = proto_item_add_subtree(ti, ett_ncp);
841     if (is_tcp) {
842         if (tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RQST && tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RPLY)
843             commhdr += 1;
844         /* Get NCPIP Header data */
845         ncpiph.signature = tvb_get_ntohl(tvb, commhdr);
846         proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, commhdr, 4, ncpiph.signature);
847         ncpiph.length = (0x7fffffff & tvb_get_ntohl(tvb, commhdr+4));
848         proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, commhdr+4, 4, ncpiph.length);
849         commhdr += 8;
850         if (ncpiph.signature == NCPIP_RQST) {
851             ncpiphrq.version = tvb_get_ntohl(tvb, commhdr);
852             proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, commhdr, 4, ncpiphrq.version);
853             commhdr += 4;
854             ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, commhdr);
855             proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, commhdr, 4, ncpiphrq.rplybufsize);
856             commhdr += 4;
857         }
858         /* Check to see if this is a valid offset, otherwise increment for packet signature */
859         if (try_val_to_str(tvb_get_ntohs(tvb, commhdr), ncp_type_vals)==NULL) {
860             /* Check to see if we have a valid type after packet signature length */
861             if (try_val_to_str(tvb_get_ntohs(tvb, commhdr+8), ncp_type_vals)!=NULL) {
862                 proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, commhdr, 8, ENC_NA);
863                 commhdr += 8;
864             }
865         }
866     } else {
867         /* Initialize this structure, we use it below */
868         memset(&ncpiph, 0, sizeof(ncpiph));
869     }
870 
871     header.type         = tvb_get_ntohs(tvb, commhdr);
872     header.sequence     = tvb_get_guint8(tvb, commhdr+2);
873     header.conn_low     = tvb_get_guint8(tvb, commhdr+3);
874     header.task         = tvb_get_guint8(tvb, commhdr+4);
875     header.conn_high    = tvb_get_guint8(tvb, commhdr+5);
876     proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr, 2, header.type);
877     nw_connection = (header.conn_high*256)+header.conn_low;
878 
879     /* Ok, we need to track the conversation so that we can
880      * determine if a new server session is occurring for this
881      * connection.
882      */
883     conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
884         ENDPOINT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport,
885         0);
886     if ((ncpiph.length & 0x80000000) || ncpiph.signature == NCPIP_RPLY) {
887         /* First time through we will record the initial connection and task
888          * values
889          */
890         if (!pinfo->fd->visited) {
891             if (conversation != NULL) {
892                 /* find the record telling us the
893                  * request made that caused this
894                  * reply
895                  */
896                 request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
897                 /* if for some reason we have no
898                  * conversation in our hash, create
899                  * one */
900                 if (request_value == NULL) {
901                     mncp_hash_insert(conversation, nw_connection, header.task, pinfo);
902                 }
903             } else {
904                 /* It's not part of any conversation
905                  * - create a new one.
906                  */
907                 conversation = conversation_new(pinfo->num, &pinfo->src,
908                     &pinfo->dst, ENDPOINT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0);
909                 mncp_hash_insert(conversation, nw_connection, header.task, pinfo);
910             }
911             /* If this is a request packet then we
912              * might have a new task
913              */
914             if (ncpiph.signature == NCPIP_RPLY) {
915                 /* Now on reply packets we have to
916                  * use the state of the original
917                  * request packet, so look up the
918                  * request value and check the task number
919                  */
920                 /*request_value = mncp_hash_lookup(conversation, nw_connection, header.task);*/
921             }
922         } else {
923             /* Get request value data */
924             request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
925             if (request_value) {
926                 if ((request_value->session_start_packet_num == pinfo->num) && ncp_echo_conn) {
927                     expert_add_info_format(pinfo, NULL, &ei_ncp_new_server_session, "Detected New Server Session. Connection %d, Task %d", nw_connection, header.task);
928                 }
929             }
930         }
931     } else {
932         if (!pinfo->fd->visited) {
933             if (conversation != NULL) {
934                 /* find the record telling us the
935                  * request made that caused this
936                  * reply
937                  */
938                 request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
939                 /* if for some reason we have no
940                  * conversation in our hash, create
941                  * one */
942                 if (request_value == NULL) {
943                     mncp_hash_insert(conversation, nw_connection, header.task, pinfo);
944                 }
945             } else {
946                 /* It's not part of any conversation
947                  * - create a new one.
948                  */
949                 conversation = conversation_new(pinfo->num, &pinfo->src,
950                     &pinfo->dst, ENDPOINT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0);
951                 mncp_hash_insert(conversation, nw_connection, header.task, pinfo);
952             }
953             /* find the record telling us the request
954              * made that caused this reply
955              */
956         } else {
957             request_value = mncp_hash_lookup(conversation, nw_connection, header.task);
958             if (request_value) {
959                 if ((request_value->session_start_packet_num == pinfo->num) && ncp_echo_conn) {
960                     expert_add_info_format(pinfo, NULL, &ei_ncp_new_server_session, "Detected New Server Session. Connection %d, Task %d", nw_connection, header.task);
961                 }
962             }
963         }
964     }
965 
966     tap_queue_packet(ncp_tap.hdr, pinfo, ncp_hdr);
967 
968     col_add_str(pinfo->cinfo, COL_INFO,
969         val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)"));
970 
971     /*
972      * Process the packet-type-specific header.
973      */
974     switch (header.type) {
975 
976     case NCP_BROADCAST_SLOT:    /* Server Broadcast */
977         proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
978         proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
979         proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, ENC_BIG_ENDIAN);
980         proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, tvb_get_guint8(tvb, commhdr+9));
981         proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, ENC_BIG_ENDIAN);
982         if ((tvb_get_guint8(tvb, commhdr+9)==0x24) && ncp_echo_file) {
983             expert_add_info_format(pinfo, NULL, &ei_ncp_oplock_handle, "Server requesting station to clear oplock on handle - %08x", tvb_get_ntohl(tvb, commhdr+10));
984         }
985         break;
986 
987     case NCP_LIP_ECHO:    /* Lip Echo Packet */
988         /* Unlike the ones with a packet type of 0x1111, in this one, the
989            packet type field is the first two bytes of "Lip Echo Data"
990            (with "Lip" not capitalized, and with "Echo Data" not followed
991            by blanks) */
992         proto_tree_add_item(ncp_tree, hf_lip_echo_magic, tvb, commhdr, 13, ENC_ASCII|ENC_NA);
993         break;
994 
995     case NCP_BURST_MODE_XFER:    /* Packet Burst Packet */
996         /*
997          * XXX - we should keep track of whether there's a burst
998          * outstanding on a connection and, if not, treat the
999          * beginning of the data as a burst header.
1000          *
1001          * The burst header contains:
1002          *
1003          *    4 bytes of little-endian function number:
1004          *        1 = read, 2 = write;
1005          *
1006          *    4 bytes of file handle;
1007          *
1008          *    8 reserved bytes;
1009          *
1010          *    4 bytes of big-endian file offset;
1011          *
1012          *    4 bytes of big-endian byte count.
1013          *
1014          * The data follows for a burst write operation.
1015          *
1016          * The first packet of a burst read reply contains:
1017          *
1018          *    4 bytes of little-endian result code:
1019          *       0: No error
1020          *       1: Initial error
1021          *       2: I/O error
1022          *       3: No data read;
1023          *
1024          *    4 bytes of returned byte count (big-endian?).
1025          *
1026          * The data follows.
1027          *
1028          * Each burst of a write request is responded to with a
1029          * burst packet with a 2-byte little-endian result code:
1030          *
1031          *    0: Write successful
1032          *    4: Write error
1033          */
1034         flags = tvb_get_guint8(tvb, commhdr + 2);
1035 
1036         ti = proto_tree_add_uint(ncp_tree, hf_ncp_system_flags,
1037             tvb, commhdr + 2, 1, flags);
1038         flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags);
1039 
1040         proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt,
1041             tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
1042         if (flags & ABT) {
1043             proto_item_append_text(ti, "  ABT");
1044         }
1045         flags&=(~( ABT ));
1046 
1047         proto_tree_add_item(flags_tree, hf_ncp_system_flags_bsy,
1048             tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
1049         if (flags & BSY) {
1050             proto_item_append_text(ti, "  BSY");
1051         }
1052         flags&=(~( BSY ));
1053 
1054         proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob,
1055             tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
1056         if (flags & EOB) {
1057             proto_item_append_text(ti, "  EOB");
1058         }
1059         flags&=(~( EOB ));
1060 
1061         proto_tree_add_item(flags_tree, hf_ncp_system_flags_lst,
1062             tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
1063         if (flags & LST) {
1064             proto_item_append_text(ti, "  LST");
1065         }
1066         flags&=(~( LST ));
1067 
1068         proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys,
1069             tvb, commhdr + 2, 1, ENC_BIG_ENDIAN);
1070         if (flags & SYS) {
1071             proto_item_append_text(ti, "  SYS");
1072         }
1073         flags&=(~( SYS ));
1074 
1075 
1076         proto_tree_add_item(ncp_tree, hf_ncp_stream_type,
1077             tvb, commhdr + 3, 1, ENC_BIG_ENDIAN);
1078         proto_tree_add_item(ncp_tree, hf_ncp_src_connection,
1079             tvb, commhdr + 4, 4, ENC_BIG_ENDIAN);
1080         proto_tree_add_item(ncp_tree, hf_ncp_dst_connection,
1081             tvb, commhdr + 8, 4, ENC_BIG_ENDIAN);
1082         proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno,
1083             tvb, commhdr + 12, 4, ENC_BIG_ENDIAN);
1084         proto_tree_add_item(ncp_tree, hf_ncp_delay_time,
1085             tvb, commhdr + 16, 4, ENC_BIG_ENDIAN);
1086         ncp_burst_seqno = tvb_get_ntohs(tvb, commhdr+20);
1087         proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno,
1088             tvb, commhdr + 20, 2, ENC_BIG_ENDIAN);
1089         ncp_ack_seqno = tvb_get_ntohs(tvb, commhdr+22);
1090         proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno,
1091             tvb, commhdr + 22, 2, ENC_BIG_ENDIAN);
1092         proto_tree_add_item(ncp_tree, hf_ncp_burst_len,
1093             tvb, commhdr + 24, 4, ENC_BIG_ENDIAN);
1094         data_offset = tvb_get_ntohl(tvb, commhdr + 28);
1095         proto_tree_add_uint(ncp_tree, hf_ncp_data_offset,
1096             tvb, commhdr + 28, 4, data_offset);
1097         data_len = tvb_get_ntohs(tvb, commhdr + 32);
1098         proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes,
1099             tvb, commhdr + 32, 2, data_len);
1100         missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34);
1101         proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count,
1102             tvb, commhdr + 34, 2, ENC_BIG_ENDIAN);
1103         offset = commhdr + 36;
1104         if (!(flags & SYS) && ncp_burst_seqno == ncp_ack_seqno &&
1105             data_offset == 0) {
1106             /*
1107              * This is either a Burst Read or Burst Write
1108              * command.  The data length includes the burst
1109              * mode header, plus any data in the command
1110              * (there shouldn't be any in a read, but there
1111              * might be some in a write).
1112              */
1113             if (data_len < 4)
1114                 return;
1115             ncp_burst_command = tvb_get_ntohl(tvb, offset);
1116             proto_tree_add_item(ncp_tree, hf_ncp_burst_command,
1117                 tvb, offset, 4, ENC_BIG_ENDIAN);
1118             offset += 4;
1119             data_len -= 4;
1120 
1121             if (data_len < 4)
1122                 return;
1123             burst_file = tvb_get_ntohl(tvb, offset);
1124             proto_tree_add_item(ncp_tree, hf_ncp_burst_file_handle,
1125                 tvb, offset, 4, ENC_BIG_ENDIAN);
1126             offset += 4;
1127             data_len -= 4;
1128 
1129             if (data_len < 8)
1130                 return;
1131             proto_tree_add_item(ncp_tree, hf_ncp_burst_reserved,
1132                 tvb, offset, 8, ENC_NA);
1133             offset += 8;
1134             data_len -= 8;
1135 
1136             if (data_len < 4)
1137                 return;
1138             burst_off = tvb_get_ntohl(tvb, offset);
1139             proto_tree_add_uint(ncp_tree, hf_ncp_burst_offset,
1140                 tvb, offset, 4, burst_off);
1141             offset += 4;
1142             data_len -= 4;
1143 
1144             if (data_len < 4)
1145                 return;
1146             burst_len = tvb_get_ntohl(tvb, offset);
1147             proto_tree_add_uint(ncp_tree, hf_ncp_burst_len,
1148                 tvb, offset, 4, burst_len);
1149             offset += 4;
1150             data_len -= 4;
1151 
1152             col_add_fstr(pinfo->cinfo, COL_INFO,
1153                 "%s %d bytes starting at offset %d in file 0x%08x",
1154                 val_to_str(ncp_burst_command,
1155                     burst_command, "Unknown (0x%08x)"),
1156                     burst_len, burst_off, burst_file);
1157             break;
1158         } else {
1159             if (tvb_get_guint8(tvb, commhdr + 2) & 0x10) {
1160                 col_set_str(pinfo->cinfo, COL_INFO, "End of Burst");
1161             }
1162         }
1163         break;
1164 
1165     case NCP_ALLOCATE_SLOT:        /* Allocate Slot Request */
1166         length_remaining = tvb_reported_length_remaining(tvb, commhdr + 4);
1167         if (length_remaining >= LIP_ECHO_MAGIC_LEN &&
1168             tvb_memeql(tvb, commhdr+4, lip_echo_magic, LIP_ECHO_MAGIC_LEN) == 0) {
1169             /* This is a LIP Echo. */
1170             is_lip_echo_allocate_slot = TRUE;
1171             col_set_str(pinfo->cinfo, COL_INFO, "LIP Echo");
1172         }
1173         /* fall through */
1174 
1175     case NCP_POSITIVE_ACK:        /* Positive Acknowledgement */
1176     case NCP_SERVICE_REQUEST:    /* Server NCP Request */
1177     case NCP_SERVICE_REPLY:        /* Server NCP Reply */
1178     case NCP_WATCHDOG:        /* Watchdog Packet */
1179     case NCP_DEALLOCATE_SLOT:    /* Deallocate Slot Request */
1180     default:
1181         proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence);
1182         /* XXX - what's at commhdr + 3 in a LIP Echo packet?
1183            commhdr + 4 on is the LIP echo magic number and data. */
1184         if (!is_lip_echo_allocate_slot) {
1185             proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection);
1186             proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, ENC_BIG_ENDIAN);
1187         }
1188         break;
1189     }
1190 
1191     /*
1192      * Process the packet body.
1193      */
1194     switch (header.type) {
1195 
1196     case NCP_ALLOCATE_SLOT:        /* Allocate Slot Request */
1197         if (is_lip_echo_allocate_slot) {
1198             length_remaining = tvb_reported_length_remaining(tvb, commhdr + 4);
1199             proto_tree_add_item(ncp_tree, hf_lip_echo_magic, tvb, commhdr + 4, LIP_ECHO_MAGIC_LEN, ENC_ASCII|ENC_NA);
1200             if (length_remaining > LIP_ECHO_MAGIC_LEN)
1201                 proto_tree_add_item(ncp_tree, hf_lip_echo_payload, tvb, commhdr+4+LIP_ECHO_MAGIC_LEN, length_remaining - LIP_ECHO_MAGIC_LEN, ENC_NA);
1202         }
1203         next_tvb = tvb_new_subset_remaining(tvb, commhdr);
1204         dissect_ncp_request(next_tvb, pinfo, nw_connection,
1205             header.sequence, header.type, is_lip_echo_allocate_slot, ncp_tree);
1206         break;
1207 
1208     case NCP_DEALLOCATE_SLOT:    /* Deallocate Slot Request */
1209         next_tvb = tvb_new_subset_remaining(tvb, commhdr);
1210         dissect_ncp_request(next_tvb, pinfo, nw_connection,
1211             header.sequence, header.type, FALSE, ncp_tree);
1212         break;
1213 
1214     case NCP_SERVICE_REQUEST:    /* Server NCP Request */
1215     case NCP_BROADCAST_SLOT:    /* Server Broadcast Packet */
1216         next_tvb = tvb_new_subset_remaining(tvb, commhdr);
1217         if (tvb_get_guint8(tvb, commhdr+6) == 0x68) {
1218             subfunction = tvb_get_guint8(tvb, commhdr+7);
1219             switch (subfunction) {
1220 
1221             case 0x02:    /* NDS Frag Packet to decode */
1222                 dissect_nds_request(next_tvb, pinfo,
1223                     nw_connection, header.sequence,
1224                     header.type, ncp_tree);
1225                 break;
1226 
1227             case 0x01:    /* NDS Ping */
1228                 dissect_ping_req(next_tvb, pinfo,
1229                     nw_connection, header.sequence,
1230                     header.type, ncp_tree);
1231                 break;
1232 
1233             default:
1234                 dissect_ncp_request(next_tvb, pinfo,
1235                     nw_connection, header.sequence,
1236                     header.type, FALSE, ncp_tree);
1237                 break;
1238              }
1239         } else {
1240             dissect_ncp_request(next_tvb, pinfo, nw_connection,
1241                 header.sequence, header.type, FALSE, ncp_tree);
1242         }
1243         break;
1244 
1245     case NCP_SERVICE_REPLY:        /* Server NCP Reply */
1246         next_tvb = tvb_new_subset_remaining(tvb, commhdr);
1247         nds_defrag(next_tvb, pinfo, nw_connection, header.sequence,
1248             header.type, ncp_tree, &ncp_tap);
1249         break;
1250 
1251     case NCP_POSITIVE_ACK:        /* Positive Acknowledgement */
1252         /*
1253          * XXX - this used to call "nds_defrag()", which would
1254          * clear out "frags".  Was that the right thing to
1255          * do?
1256          */
1257         next_tvb = tvb_new_subset_remaining(tvb, commhdr);
1258         dissect_ncp_reply(next_tvb, pinfo, nw_connection,
1259             header.sequence, header.type, ncp_tree, &ncp_tap);
1260         break;
1261 
1262     case NCP_WATCHDOG:        /* Watchdog Packet */
1263         /*
1264          * XXX - should the completion code be interpreted as
1265          * it is in "packet-ncp2222.inc"?  If so, this
1266          * packet should be handled by "dissect_ncp_reply()".
1267          */
1268         proto_tree_add_item(ncp_tree, hf_ncp_completion_code,
1269             tvb, commhdr + 6, 1, ENC_LITTLE_ENDIAN);
1270         proto_tree_add_item(ncp_tree, hf_ncp_connection_status,
1271             tvb, commhdr + 7, 1, ENC_LITTLE_ENDIAN);
1272         proto_tree_add_item(ncp_tree, hf_ncp_slot,
1273             tvb, commhdr + 8, 1, ENC_LITTLE_ENDIAN);
1274         proto_tree_add_item(ncp_tree, hf_ncp_signature_character,
1275             tvb, commhdr + 9, 1, ENC_LITTLE_ENDIAN);
1276         /*
1277          * Display the rest of the packet as data.
1278          */
1279         if (tvb_offset_exists(tvb, commhdr + 10)) {
1280             call_data_dissector(tvb_new_subset_remaining(tvb, commhdr + 10),
1281                 pinfo, ncp_tree);
1282         }
1283         break;
1284 
1285     case NCP_BURST_MODE_XFER:    /* Packet Burst Packet */
1286         if (flags & SYS) {
1287             /*
1288              * System packet; show missing fragments if there
1289              * are any.
1290              */
1291             while (missing_fraglist_count != 0) {
1292                 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset,
1293                     tvb, offset, 4, ENC_BIG_ENDIAN);
1294                 offset += 4;
1295                 proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count,
1296                     tvb, offset, 2, ENC_BIG_ENDIAN);
1297                 offset += 2;
1298                 missing_fraglist_count--;
1299             }
1300         } else {
1301             /*
1302              * XXX - do this by using -1 and -1 as the length
1303              * arguments to "tvb_new_subset_length_caplen()" and then calling
1304              * "tvb_set_reported_length()"?  That'll throw an
1305              * exception if "data_len" goes past the reported
1306              * length of the packet, but that's arguably a
1307              * feature in this case.
1308              */
1309             length_remaining = tvb_captured_length_remaining(tvb, offset);
1310             if (length_remaining > data_len)
1311                 length_remaining = data_len;
1312             if (data_len != 0) {
1313                 call_data_dissector(tvb_new_subset_length_caplen(tvb, offset,
1314                     length_remaining, data_len),
1315                     pinfo, ncp_tree);
1316             }
1317         }
1318         break;
1319 
1320     case NCP_LIP_ECHO:        /* LIP Echo Packet */
1321         proto_tree_add_item(ncp_tree, hf_lip_echo_payload, tvb, commhdr + 13, -1, ENC_NA);
1322         break;
1323 
1324     default:
1325         proto_tree_add_expert_format(ncp_tree, pinfo, &ei_ncp_type, tvb, commhdr + 6, -1,
1326             "%s packets not supported yet",
1327             val_to_str(header.type, ncp_type_vals,
1328                 "Unknown type (0x%04x)"));
1329         break;
1330     }
1331 }
1332 
1333 static int
1334 dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1335 {
1336     dissect_ncp_common(tvb, pinfo, tree, FALSE);
1337     return tvb_captured_length(tvb);
1338 }
1339 
1340 static guint
1341 get_ncp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
1342 {
1343     guint32 signature;
1344 
1345     /*
1346      * Check the NCP-over-TCP header signature, to make sure it's there.
1347      * If it's not there, we cannot trust the next 4 bytes to be a
1348      * packet length+"has signature" flag, so we just say the length is
1349      * "what remains in the packet".
1350      */
1351     signature = tvb_get_ntohl(tvb, offset);
1352     if (signature != NCPIP_RQST && signature != NCPIP_RPLY)
1353         return tvb_captured_length_remaining(tvb, offset);
1354 
1355     /*
1356      * Get the length of the NCP-over-TCP packet.  Strip off the "has
1357      * signature" flag.
1358      */
1359 
1360     return tvb_get_ntohl(tvb, offset + 4) & 0x7fffffff;
1361 }
1362 
1363 static int
1364 dissect_ncp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1365 {
1366     dissect_ncp_common(tvb, pinfo, tree, TRUE);
1367     return tvb_captured_length(tvb);
1368 }
1369 
1370 static int
1371 dissect_ncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1372 {
1373     tcp_dissect_pdus(tvb, pinfo, tree, ncp_desegment, 8, get_ncp_pdu_len,
1374                      dissect_ncp_tcp_pdu, data);
1375     return tvb_captured_length(tvb);
1376 }
1377 
1378 void
1379 proto_register_ncp(void)
1380 {
1381     static hf_register_info hf[] = {
1382         { &hf_ncp_ip_sig,
1383           { "NCP over IP signature",            "ncp.ip.signature",
1384             FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0,
1385             NULL, HFILL }},
1386         { &hf_ncp_ip_length,
1387           { "NCP over IP length",               "ncp.ip.length",
1388             FT_UINT32, BASE_DEC, NULL, 0x0,
1389             NULL, HFILL }},
1390         { &hf_ncp_ip_ver,
1391           { "NCP over IP Version",              "ncp.ip.version",
1392             FT_UINT32, BASE_DEC, NULL, 0x0,
1393             NULL, HFILL }},
1394         { &hf_ncp_ip_rplybufsize,
1395           { "NCP over IP Reply Buffer Size",    "ncp.ip.replybufsize",
1396             FT_UINT32, BASE_DEC, NULL, 0x0,
1397             NULL, HFILL }},
1398         { &hf_ncp_ip_packetsig,
1399           { "NCP over IP Packet Signature",     "ncp.ip.packetsig",
1400             FT_BYTES, BASE_NONE, NULL, 0x0,
1401             NULL, HFILL }},
1402         { &hf_ncp_type,
1403           { "Type",                             "ncp.type",
1404             FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0,
1405             "NCP message type", HFILL }},
1406         { &hf_ncp_seq,
1407           { "Sequence Number",                  "ncp.seq",
1408             FT_UINT8, BASE_DEC, NULL, 0x0,
1409             NULL, HFILL }},
1410         { &hf_ncp_connection,
1411           { "Connection Number",                "ncp.connection",
1412             FT_UINT16, BASE_DEC, NULL, 0x0,
1413             NULL, HFILL }},
1414         { &hf_ncp_task,
1415           { "Task Number",                      "ncp.task",
1416             FT_UINT8, BASE_DEC, NULL, 0x0,
1417             NULL, HFILL }},
1418         { &hf_ncp_oplock_flag,
1419           { "Broadcast Message Flag",           "ncp.msg_flag",
1420             FT_UINT8, BASE_HEX, VALS(ncp_oplock_vals), 0x0,
1421             NULL, HFILL }},
1422         { &hf_ncp_oplock_handle,
1423           { "File Handle",                      "ncp.oplock_handle",
1424             FT_UINT16, BASE_HEX, NULL, 0x0,
1425             NULL, HFILL }},
1426         { &hf_ncp_stream_type,
1427           { "Stream Type",                      "ncp.stream_type",
1428             FT_UINT8, BASE_HEX, NULL, 0x0,
1429             "Type of burst", HFILL }},
1430         { &hf_ncp_system_flags,
1431           { "System Flags",                     "ncp.system_flags",
1432             FT_UINT8, BASE_HEX, NULL, 0x0,
1433             NULL, HFILL }},
1434         { &hf_ncp_system_flags_abt,
1435           { "ABT",                              "ncp.system_flags.abt",
1436             FT_BOOLEAN, 8, NULL, ABT,
1437             "Is this an abort request?", HFILL }},
1438         { &hf_ncp_system_flags_eob,
1439           { "EOB",                              "ncp.system_flags.eob",
1440             FT_BOOLEAN, 8, NULL, EOB,
1441             "Is this the last packet of the burst?", HFILL }},
1442         { &hf_ncp_system_flags_sys,
1443           { "SYS",                              "ncp.system_flags.sys",
1444             FT_BOOLEAN, 8, NULL, SYS,
1445             "Is this a system packet?", HFILL }},
1446         { &hf_ncp_system_flags_bsy,
1447           { "BSY",                              "ncp.system_flags.bsy",
1448             FT_BOOLEAN, 8, NULL, BSY,
1449             "Is the server busy?", HFILL }},
1450         { &hf_ncp_system_flags_lst,
1451           { "LST",                              "ncp.system_flags.lst",
1452             FT_BOOLEAN, 8, NULL, LST,
1453             "Return Fragment List?", HFILL }},
1454         { &hf_ncp_src_connection,
1455           { "Source Connection ID",             "ncp.src_connection",
1456             FT_UINT32, BASE_DEC, NULL, 0x0,
1457             "The workstation's connection identification number", HFILL }},
1458         { &hf_ncp_dst_connection,
1459           { "Destination Connection ID",        "ncp.dst_connection",
1460             FT_UINT32, BASE_DEC, NULL, 0x0,
1461             "The server's connection identification number", HFILL }},
1462         { &hf_ncp_packet_seqno,
1463           { "Packet Sequence Number",           "ncp.packet_seqno",
1464             FT_UINT32, BASE_DEC, NULL, 0x0,
1465             "Sequence number of this packet in a burst", HFILL }},
1466         { &hf_ncp_delay_time,
1467           { "Delay Time",                       "ncp.delay_time",       /* in 100 us increments */
1468             FT_UINT32, BASE_DEC, NULL, 0x0,
1469             "Delay time between consecutive packet sends (100 us increments)", HFILL }},
1470         { &hf_ncp_burst_seqno,
1471           { "Burst Sequence Number",            "ncp.burst_seqno",
1472             FT_UINT16, BASE_DEC, NULL, 0x0,
1473             "Sequence number of this packet in the burst", HFILL }},
1474         { &hf_ncp_ack_seqno,
1475           { "ACK Sequence Number",              "ncp.ack_seqno",
1476             FT_UINT16, BASE_DEC, NULL, 0x0,
1477             "Next expected burst sequence number", HFILL }},
1478         { &hf_ncp_burst_len,
1479           { "Burst Length",                     "ncp.burst_len",
1480             FT_UINT32, BASE_DEC, NULL, 0x0,
1481             "Total length of data in this burst", HFILL }},
1482         { &hf_ncp_burst_offset,
1483           { "Burst Offset",                     "ncp.burst_offset",
1484             FT_UINT32, BASE_DEC, NULL, 0x0,
1485             "Offset of data in the burst", HFILL }},
1486         { &hf_ncp_data_offset,
1487           { "Data Offset",                      "ncp.data_offset",
1488             FT_UINT32, BASE_DEC, NULL, 0x0,
1489             "Offset of this packet", HFILL }},
1490         { &hf_ncp_data_bytes,
1491           { "Data Bytes",                       "ncp.data_bytes",
1492             FT_UINT16, BASE_DEC, NULL, 0x0,
1493             "Number of data bytes in this packet", HFILL }},
1494         { &hf_ncp_missing_fraglist_count,
1495           { "Missing Fragment List Count",      "ncp.missing_fraglist_count",
1496             FT_UINT16, BASE_DEC, NULL, 0x0,
1497             "Number of missing fragments reported", HFILL }},
1498         { &hf_ncp_missing_data_offset,
1499           { "Missing Data Offset",              "ncp.missing_data_offset",
1500             FT_UINT32, BASE_DEC, NULL, 0x0,
1501             "Offset of beginning of missing data", HFILL }},
1502         { &hf_ncp_missing_data_count,
1503           { "Missing Data Count",               "ncp.missing_data_count",
1504             FT_UINT16, BASE_DEC, NULL, 0x0,
1505             "Number of bytes of missing data", HFILL }},
1506         { &hf_ncp_completion_code,
1507           { "Completion Code",                  "ncp.completion_code",
1508             FT_UINT8, BASE_DEC, NULL, 0x0,
1509             NULL, HFILL }},
1510         { &hf_ncp_connection_status,
1511           { "Connection Status",                "ncp.connection_status",
1512             FT_UINT8, BASE_DEC, NULL, 0x0,
1513             NULL, HFILL }},
1514         { &hf_ncp_slot,
1515           { "Slot",                             "ncp.slot",
1516             FT_UINT8, BASE_DEC, NULL, 0x0,
1517             NULL, HFILL }},
1518         { &hf_ncp_signature_character,
1519           { "Signature Character",              "ncp.signature_character",
1520             FT_CHAR, BASE_HEX, VALS(ncp_sigchar_vals), 0x0,
1521             NULL, HFILL }},
1522 #if 0
1523         { &hf_ncp_fragment_handle,
1524           { "Fragment Handle",                  "ncp.fragger_hndl",
1525             FT_UINT16, BASE_HEX, NULL, 0x0,
1526             NULL, HFILL }},
1527 #endif
1528         { &hf_lip_echo_magic,
1529           { "Large Internet Packet Echo Magic String",  "ncp.lip_echo.magic_string",
1530             FT_STRING, BASE_NONE, NULL, 0x0,
1531             NULL, HFILL }},
1532         { &hf_lip_echo_payload,
1533           { "Large Internet Packet Echo Payload",  "ncp.lip_echo.payload",
1534             FT_BYTES, BASE_NONE, NULL, 0x0,
1535             NULL, HFILL }},
1536         { &hf_ncp_burst_command,
1537           { "Burst Command",                    "ncp.burst_command",
1538             FT_UINT32, BASE_HEX, VALS(burst_command), 0x0,
1539             "Packet Burst Command", HFILL }},
1540         { &hf_ncp_burst_file_handle,
1541           { "Burst File Handle",                "ncp.burst_file_handle",
1542             FT_UINT32, BASE_HEX, NULL, 0x0,
1543             "Packet Burst File Handle", HFILL }},
1544         { &hf_ncp_burst_reserved,
1545           { "Reserved",                         "ncp.burst_reserved",
1546             FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}
1547     };
1548     static gint *ett[] = {
1549         &ett_ncp,
1550         &ett_ncp_system_flags,
1551         &ett_nds,
1552         &ett_nds_segments,
1553         &ett_nds_segment
1554     };
1555     static ei_register_info ei[] = {
1556         { &ei_ncp_new_server_session, { "ncp.new_server_session", PI_RESPONSE_CODE, PI_CHAT, "Detected New Server Session", EXPFILL }},
1557         { &ei_ncp_oplock_handle, { "ncp.oplock_handle.clear", PI_RESPONSE_CODE, PI_CHAT, "Server requesting station to clear oplock", EXPFILL }},
1558         { &ei_ncp_type, { "ncp.type.unsupported", PI_UNDECODED, PI_NOTE, "Packet type not supported yet", EXPFILL }},
1559     };
1560     module_t *ncp_module;
1561     expert_module_t* expert_ncp;
1562 
1563     proto_ncp = proto_register_protocol("NetWare Core Protocol", "NCP", "ncp");
1564 
1565     proto_register_field_array(proto_ncp, hf, array_length(hf));
1566     proto_register_subtree_array(ett, array_length(ett));
1567     expert_ncp = expert_register_protocol(proto_ncp);
1568     expert_register_field_array(expert_ncp, ei, array_length(ei));
1569 
1570     ncp_module = prefs_register_protocol(proto_ncp, NULL);
1571     prefs_register_obsolete_preference(ncp_module, "initial_hash_size");
1572     prefs_register_bool_preference(ncp_module, "desegment",
1573                                    "Reassemble NCP-over-TCP messages spanning multiple TCP segments",
1574                                    "Whether the NCP dissector should reassemble messages spanning multiple TCP segments."
1575                                    " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1576                                    &ncp_desegment);
1577     prefs_register_bool_preference(ncp_module, "defragment_nds",
1578                                    "Reassemble fragmented NDS messages spanning multiple reply packets",
1579                                    "Whether the NCP dissector should defragment NDS messages spanning multiple reply packets.",
1580                                    &nds_defragment);
1581     prefs_register_bool_preference(ncp_module, "newstyle",
1582                                    "Dissect New Netware Information Structure",
1583                                    "Dissect the NetWare Information Structure as NetWare 5.x or higher or as older NetWare 3.x.",
1584                                    &ncp_newstyle);
1585     prefs_register_bool_preference(ncp_module, "eid_2_expert",
1586                                    "Expert: EID to Name lookups?",
1587                                    "Whether the NCP dissector should echo the NDS Entry ID to name resolves to the expert table.",
1588                                    &nds_echo_eid);
1589     prefs_register_bool_preference(ncp_module, "connection_2_expert",
1590                                    "Expert: NCP Connections?",
1591                                    "Whether the NCP dissector should echo NCP connection information to the expert table.",
1592                                    &ncp_echo_conn);
1593     prefs_register_bool_preference(ncp_module, "error_2_expert",
1594                                    "Expert: NCP Errors?",
1595                                    "Whether the NCP dissector should echo protocol errors to the expert table.",
1596                                    &ncp_echo_err);
1597     prefs_register_bool_preference(ncp_module, "server_2_expert",
1598                                    "Expert: Server Information?",
1599                                    "Whether the NCP dissector should echo server information to the expert table.",
1600                                    &ncp_echo_server);
1601     prefs_register_bool_preference(ncp_module, "file_2_expert",
1602                                    "Expert: File Information?",
1603                                    "Whether the NCP dissector should echo file open/close/oplock information to the expert table.",
1604                                    &ncp_echo_file);
1605     register_init_routine(&mncp_init_protocol);
1606     register_cleanup_routine(&mncp_cleanup_protocol);
1607     ncp_tap.stat=register_tap("ncp_srt");
1608     ncp_tap.hdr=register_tap("ncp");
1609 
1610     register_conversation_table(proto_ncp, FALSE, ncp_conversation_packet, ncp_hostlist_packet);
1611     register_srt_table(proto_ncp, "ncp_srt", 24, ncpstat_packet, ncpstat_init, NULL);
1612 }
1613 
1614 void
1615 proto_reg_handoff_ncp(void)
1616 {
1617     dissector_handle_t ncp_handle;
1618     dissector_handle_t ncp_tcp_handle;
1619 
1620     ncp_handle = create_dissector_handle(dissect_ncp, proto_ncp);
1621     ncp_tcp_handle = create_dissector_handle(dissect_ncp_tcp, proto_ncp);
1622     dissector_add_uint_with_preference("tcp.port", TCP_PORT_NCP, ncp_tcp_handle);
1623     dissector_add_uint("udp.port", UDP_PORT_NCP, ncp_handle);
1624     dissector_add_uint("ipx.packet_type", IPX_PACKET_TYPE_NCP, ncp_handle);
1625     dissector_add_uint("ipx.socket", IPX_SOCKET_NCP, ncp_handle);
1626 }
1627 
1628 /*
1629  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1630  *
1631  * Local variables:
1632  * c-basic-offset: 4
1633  * tab-width: 8
1634  * indent-tabs-mode: nil
1635  * End:
1636  *
1637  * vi: set shiftwidth=4 tabstop=8 expandtab:
1638  * :indentSize=4:tabSize=8:noTabs=true:
1639  */
1640 
1641