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